Dialogs and Modal Windows
A window can be defined as a subclass of JFrame, and its constructor can set up the window's contents, title, and menu bar.
A Window That Builds Itself
A common first way to build a window in Java is to create a JFrame object inside main(), attach a panel as its content pane, and then show it. That pattern works, and many programs use it. Because it is so common, learners often come to believe it is the only way to build a window. Under that belief, every piece of frame setup must live in main(), and the window is treated as a plain container that someone else configures from the outside.
There is another approach. A window can be defined as its own class, a subclass of JFrame, that sets up its own contents when it is constructed. This is more object-oriented because the window describes itself. As you read the rest of this article, keep two questions in mind: what does the subclass gain, and what has to happen before the window is ready to be seen?
Walking Through the Constructor
When a class extends JFrame, the class itself is a frame. Its constructor is where the window is assembled. The constructor of the subclass always begins by calling the constructor of the superclass with super(). In the MosaicDraw example from the source, that call passes the string "Mosaic Draw" to the JFrame constructor, and that string becomes the text shown in the title bar.
A minimal window class in the same shape as MosaicDraw. The constructor sets the title through super(), installs a content pane, calls pack(), and centers the window. The main() method only creates the window, makes it close the program on exit, and makes it visible.- 1Line 1 imports the Swing and AWT classes needed for a window and for screen measurement.
- 2Line 3 declares MosaicDraw as a subclass of
JFrame, so every MosaicDraw object is a frame. - 3Line 5 calls super with the title string. This runs the
JFrameconstructor first, so the superclass part of the object is established before the rest of the constructor runs. - 4Lines 6 and 7 build a panel holding a button and install it as the content pane.
- 5Line 8 calls
pack(), which is equivalent tothis.pack(), meaning the window being constructed. - 6Lines 9 and 10 center the window using the size that
pack()just settled. - 7In
main(), line 14 creates the window, line 15 makes closing the window end the program, and line 16 makes the window visible.
super("Mosaic Draw")passes the title up toJFramesetContentPaneinstalls the panel that holds the window's componentspack()resizes the window to match the preferred size of its contents- Centering uses
getWidth()andgetHeight(), so it must run afterpack() main()only creates, configures close behavior, and shows the window
- 1The caller invokes new
MosaicDraw(), which starts the subclass constructor. - 2
super("Mosaic Draw")runs first, so theJFramepart of the object is set up and the title is stored. - 3The rest of the constructor installs the contents and attaches the menu bar if one is defined.
- 4
pack()runs, so the window takes its size from the components it now holds. - 5The centering calculation runs, because the size it reads is now settled.
- 6The constructor returns a fully configured window, and
main()makes it visible.
Follow the diagram from top to bottom. The superclass is set up first, through super(). Then the constructor installs the contents, calls pack(), and centers the window. Only after the constructor returns does main() make the window visible. The benefit of this structure is that anyone who creates a MosaicDraw object receives a fully configured window in one step, and main() needs only to create it, set its close behavior, and show it.
What pack() Actually Does
The pack() method resizes the window so that its size matches the preferred size of its contents. It does not decide the size on its own. It asks the components inside the window how large they would like to be, and it adjusts the window to fit them. The source describes this method as usually the best way to set the size of a window, which is why it appears in nearly every well-built frame constructor.
Read the diagram below as a change of target rather than a change of number. Before pack() runs, the window has not been fitted to what it contains. After pack() runs, its size has been set to the preferred size of its contents. The contents themselves are not altered by the call. Only the window's own dimensions are adjusted.
What do you think happens?
The constructor could center the window before calling pack(). Why does the example call pack() first?
Reveal answer
The centering calculation uses getWidth() and getHeight(), so the window's size must be settled before centering runs.
If centering ran before pack(), it would read the window's size before pack() had fitted it to the contents, so the window would be centered for the wrong size.
In the source, the call is written as a bare pack(), which is equivalent to this.pack(). That refers to the window being built by the constructor. If a variable named window of type JFrame or JDialog held the object instead, the same resizing would be written window.pack().
Where pack() Cannot Find the Right Size
Because pack() depends on each component reporting a correct preferred size, it only works reliably when those sizes are available. The source identifies exactly two situations in which the system cannot find a correct preferred size on its own. In both cases the panel has no layout logic that can compute a size from its children, so the system has nothing reliable to report.
Setting a preferred size by hand means telling a component how large it would like to be before pack() asks. Once that value is supplied, pack() has something correct to match. The rule is simple: when a panel is a drawing surface, or a panel holds components with a null layout manager, do not rely on pack() alone to discover the right size.
- A drawing panel has no layout logic that reports a size
setPreferredSizesupplies the size by hand beforepack()asks
Setting a Preferred Size by Hand
A window's content pane holds a JPanel that is used only to draw a mosaic pattern, and no layout manager arranges its children. Describe the change you would make to the panel's setup before calling pack(), and explain why pack() alone would not produce the correct window size.
Hints
- Ask which of the two situations in the source this panel matches.
- Think about what
pack()asks each component for before it resizes the window. - The fix is to supply a preferred size before
pack()runs, not after.
Mistakes to Avoid
Common mistake Believing that a window can only be built inside main()
Why it failsThe
main()pattern works, but a window can also define itself as a subclass ofJFrameand set up its contents in its constructor.Do this insteadChoose the design that makes the window's configuration clearest, knowing both are valid.
Common mistake Omitting the super() call in a JFrame subclass constructor
Why it failsThe subclass constructor begins by calling
super(), which passes the title to theJFramesuperclass. Without it, the title is not set through that path.Do this insteadBegin the constructor with super("Title") and then configure the rest of the window.
Common mistake Assuming pack() always produces the correct window size
Why it failspack()only works correctly when every component reports a correct preferred size. A drawing-surface panel or a null-layout panel reports nothing reliable.Do this insteadSet the preferred size by hand on those panels before calling pack().
Common mistake Centering the window before calling pack()
Why it failsCentering reads
getWidth()andgetHeight(), which depend on the sizepack()sets.Do this insteadCall pack() first, then compute the position from the settled size.
Common mistake Thinking that pack() changes the contents of the window; it only adjusts the window's own dimensions.
Summary of Window Construction
- 1A window can be a subclass of
JFramewhose constructor sets up its contents, title, and menu bar. - 2The constructor calls
super()first, passing the title toJFrame, and then configures the rest of the window. - 3
pack()resizes the window to match the preferred size of its contents and is usually the best way to size a window. - 4
pack()cannot be trusted for drawing-surface panels or panels with a null layout manager, so set their preferred sizes by hand before callingpack().
At a glance
- A window can be defined as a subclass of
JFrame, so the class itself is a frame whose constructor assembles the window. - The subclass constructor calls
super()first, which passes the title toJFramebefore the rest of the setup runs. pack()resizes the window to match the preferred size of its contents, and it only works correctly when those preferred sizes are correct.- Drawing-surface panels and panels with a null layout manager require a preferred size set by hand before
pack()is called.