> ### Section 7.7
> Frames and Dialogs

> APPLETS ARE A FINE IDEA. It's nice to be able to put a complete program in a rectangle on a Web page. But more serious, large-scale programs have to run in their own windows, independently of a Web browser. In Java, a program can open an independent window by creating an object of type `Frame`. A `Frame` has a title, displayed in the title bar at the top of the window. It can have a menu bar containing one or more pull-down menus. A `Frame` is a `Container`, which means that it can hold other GUI components. The default layout manager for a `Frame` is a `BorderLayout`. A common way to design a frame is to add a single GUI component, such as a `Panel` or `Canvas`, in the layout's Center position so that it will fill the entire frame.

> It is possible for an applet to create a frame. The frame will be a separate window from the Web browser window in which the applet is running. Any frame created by an applet includes a warning message such as "Warning: Insecure Applet Window." The warning is there so that you can always recognize windows created by applets. This is just one of the security restrictions on applets, which, after all, are programs that can be downloaded automatically from Web sites that you happen to stumble across without knowing anything about them.

> Here is an applet that displays just one small button on the page. When you click the "Launch ShapeDraw" button, a window will be opened. This is another version of the `ShapeDraw` program that you've seen several times already. This version has a pull-down menu named "Add Shape", which contains commands that you can use to add shapes to the window. (Note for Macintosh users: The menus for the frame might just be added to the list of menus at the top of the screen. Look there for the "Add Shape" menu if you don't see it at the top of the window.) Once a shape is in the window, you can drag it around. The color that will be used for newly created shapes is controlled by another pull-down menu named "Color". There is also a pop-up menu that appears when you click on a shape in the appropriate, platform-dependent way.

> Sorry, but your browser
> doesn't support Java.

> The window in this example belongs to a class named `ShapeDrawFrame`, which is defined as a subclass of `Frame`. The applet creates the window with the statement

> `shapeDraw = new ShapeDrawFrame();`

> The constructor sets up the structure of the window and makes the window appear on the screen. Once the window has been created, it runs independently of the applet and of any other windows. Of course, there can be some communication through shared variables, method calls, and events. In the sample applet above, for example, the name of the button changes from "Launch ShapeDraw" to "Close ShapeDraw" while the window is open. If the user clicks on the "Close ShapeDraw" button, the applet responds by closing the window. This is done by calling an appropriate method in the window object. On the other hand, if the user closes the window by clicking on its close box, an event is generated belonging to the class `WindowEvent`. The applet listens for such events so that it can change the name of the button back to "Launch ShapeDraw" when the window is closed. (You might be interested to see how all this is handled in the source code for the applet. You can find it in the file ShapeDrawLauncher.java.)

> Fortunately, you don't have to learn a lot of new material to use frames. There are a few specialized methods in the `Frame` class that you should know about. You'll want to know how to use pull-down menus and menu bars. And there are a few important events that are generated by windows. Aside from that, programming with frames is the same as programming with applets. Many of the new features show up in the constructor for the `ShapeDrawFrame` class, so let's take a look at that:

>           public ShapeDrawFrame() {
>                  // Constructor.  Create and open the window.  The window
>                  // has a menu bar containing two menus, "Add Shape" and
>                  // "Color".  The content of the window is a canvas belonging
>                  // to the class ShapeCanvas.

>              setBackground(Color.white);

>              /* Set window title by calling the superclass constructor. */

>              super("Shape Draw");

>              /* Create a canvas that fills the frame. */

>              canvas = new ShapeCanvas();
>              add(canvas, BorderLayout.CENTER);

>              /* Create pull-down menus and a menu bar.  The frame listens
>                 for ActionEvents from the menus.  These are generated when
>                 the user selects commands from the menus.  */

>              Menu colorMenu = new Menu("Color", true);  // Color choice menu.
>              colorMenu.add("Red");
>              colorMenu.add("Green");
>              colorMenu.add("Blue");
>              colorMenu.add("Cyan");
>              colorMenu.add("Magenta");
>              colorMenu.add("Yellow");
>              colorMenu.add("Black");
>              colorMenu.add("White");

>              colorMenu.addActionListener(this);

>              Menu shapeMenu = new Menu("Add Shape", true);  // Shape menu.
>              shapeMenu.add("Rectangle");
>              shapeMenu.add("Oval");
>              shapeMenu.add("Round Rect");

>              shapeMenu.addActionListener(this);

>              MenuBar mbar = new MenuBar();  // Create menu bar and add the menus.
>              mbar.add(shapeMenu);
>              mbar.add(colorMenu);

>              setMenuBar(mbar); // Add the menu bar to the frame.

>              /* Do the remaining setup and show the window. */

>              setBounds(30,50,380,280);  // Set size and position of window.

>              setResizable(false);       // Make the window non-resizable.

>              addWindowListener(
>                         new WindowAdapter() {
>                                // A listener that will close the window
>                                // when the user clicks its close box.
>                              public void windowClosing(WindowEvent evt) {
>                                 ShapeDrawFrame.this.dispose();
>                              }
>                           }
>                   );  // end addWindowListener statement

>              show();  // Make the window visible.

>           }  // end constructor

> This constructor begins by calling a constructor from the superclass, `Frame`. The `Frame` constructor specifies a title for the window, which is displayed in the window's title bar. A `Frame` object contains an instance method, `setTitle(String)`, that can be used to set the title of the frame at any time. There is also a `getTitle()` method that returns the current title.

> The frame's "Color" menu is created with the command "`Menu colorMenu = new Menu("Color", true);`". The second parameter of the `Menu` constructor specifies that this should be a tear-off menu, which can be dragged by the user away from the menu bar, where it becomes a little independent window. (This might not work on all platforms.) This second parameter is optional. The `add()` method is used to add commands to the menu. The version of the `add()` command that is used here takes a `String`, which will appear as one of the commands in the menu. You can be more sophisticated than this if you want. There is another version of the `add` command that adds one menu as a submenu or hierarchical menu in another menu. You can add a separator line to a menu with the `addSeparator()` method. You can also create an object belonging to the class `MenuItem` and add it to a menu. A `MenuItem` represents a command, and the text of that command appears in the menu. But you can also associate a keyboard shortcut key with the menu item (like Control-V for pasting in Windows or Command-V for pasting on a Macintosh). Furthermore, a `MenuItem` can be enabled and disabled. And there are even `CheckboxMenuItems` representing menu items that can be checked and unchecked by the user (generally to represent options that can be turned on and off). You can look up all the details in a Java reference if you are interested.

> For a menu to be useful, you must register an `ActionListener` with it. Whenever the user selects an item from the menu, an `ActionEvent` is generated and the `actionPerformed()` method of the action listener is called. The action command that is associated with the `ActionEvent` is the text of the menu item. (It is also possible to listen for action events from individual `MenuItem` objects, but it is more common simply to use one listener for the menu as a whole.) In the above constructor, the frame itself is registered as the listener for the menus. There is an `actionPerformed()` method elsewhere in the `ShapeDrawFrame` class that handles menu commands.

> A pull-down menu can only appear in the menu bar of a frame. A menu bar is an object of type `MenuBar`. Menus are added to the menu bar using the `add()` method of the `MenuBar` object. The menu bar itself must be associated with the frame by calling the frame's `setMenuBar()` command. Note that a frame can have only one menu bar, but that you can change to a different menu bar at any time by calling `setMenuBar()`.

> In this example, I call `setBounds(30,50,380,280)` to set the position and size of the frame. The upper left corner of the frame will be at the point (30,50) on the computer screen, where (0,0) is the upper left corner of the screen. The width of the frame will be 380 and the height will be 280. By calling `setResizable(false)`, I make it impossible for the user to change the size of the frame. By default, the frame would be resizable. In most cases, it's better to allow the user to change the size of the frame, but that means you have to write a program that can deal with components that change size.

> (Using the `setBounds()` command is also not particularly good style. Better style would be to use the `pack()` command, which tells the frame to set itself to its so-called preferred size. A frame computes its preferred size by taking into consideration the preferred sizes and the layout of all the components that it contains. However, I failed to define a `getPreferredSize()` method in the `ShapeCanvas` class, so the canvas component in the frame doesn't know how big it wants to be. In this case, `setBounds()` works well enough. But if you ever start writing "serious" GUI components that will see a lot of reuse by yourself or other programmers, you have to start worrying about the fine points of style, like `getPreferredSize()`. `The MessageDialog` example that is discussed at the end of this page uses both `pack()` and `getPreferredSize()`. Look at the source code if you'd like to see how they work.)

> The next statement in the constructor sets up a listener to listen for `WindowEvents` from the frame:

>              addWindowListener(
>                         new WindowAdapter() {
>                                // A listener that will close the window
>                                // when the user clicks its close box
>                              public void windowClosing(WindowEvent evt) {
>                                 ShapeDrawFrame.this.dispose();
>                              }
>                           }
>                   );  // end addWindowListener statement

> This requires some explanation. To understand it all, you need to have absorbed the material about anonymous nested classes and adapter classes from the previous section. Frames generate events belonging to the class `WindowEvent`. There are seven types of `WindowEvent`, and the associated `WindowListener` interface declares seven methods. Here, I only want to define a response to one type of window event, so I base my listener object on the `WindowAdapter` class. The listener object belongs to an anonymous subclass of `WindowAdapter`. The `windowClosing()` method is called when the user clicks on the close box of the frame. The system does not automatically close the window when the user does this! It just generates a `windowClosing` event. The event handler for that event is responsible for closing the window. (It can even decide not to close it. For example, the event handler method might ask the user, "Do you really want to close this window?" and give the user a chance to change his mind.) A frame is closed by calling its `dispose()` method. The statement `ShapeDrawFrame.this.dispose()` in the event handler refers to the `dispose()` method in the `ShapeDrawFrame` class.

> The final line in the constructor for `ShapeDrawFrame` is "`show()`;". This is extremely important. When a window is first created, it is hidden. The `show()` command makes the window appear on the screen.

> By the way, the `ShapeDrawFrame` class also includes the following `main()` routine:

>                    public static void main(String[] args) {
>                       new ShapeDrawFrame();
>                    }

> This means that `ShapeDrawFrame` can be executed as an independent program. When it is executed, the `main()` routine simply opens a window of type `ShapeDrawFrame`. After opening the window, the `main()` routine ends, but the window stays open until the user closes it. (If the frame is being run as an independent program, it would be a good idea to call `System.exit(0)` when the user closes the window. This statement will end the program completely, not just dispose of the window. This can be done in the `windowClosing` method.)

> A problem sometimes arises when using `Insets` with frames. To leave a border between the edges of the frame and the components that it contains, you have to define a `getInsets()` method in the frame class. However, on some platforms, a frame already uses insets to leave space for the menu bar. Your `getInsets()` has to allow for this space. The way to do this is to call `super.getInsets()` to find out how much space the frame is already allowing for insets. Then add on the extra space that you want to allow for the border. The following `getInsets()` method adds an extra 2 pixels to the insets along each edge of the frame:

>             public Insets getInsets() {
>                Insets currentInsets = super.getInsets();
>                Insets myInsets = new Insets();
>                myInsets.top = currentInsets.top + 2;
>                myInsets.bottom = currentInsets.bottom + 2;
>                myInsets.left = currentInsets.left + 2;
>                myInsets.right = currentInsets.right + 2;
>                return myInsets;
>             }

> (When you call `super.getInsets()`, you are not supposed to modify the object that it returns. You should construct a new object and return that one, as is done in this example.)

> ### Dialogs

> Like a frame, a dialog box is a separate window. Unlike a frame, however, a dialog box is not completely independent. Every dialog box is associated with a frame, which is called its parent. The dialog box is dependent on its parent. For example, if the parent is closed, the dialog box will also be closed.

> Dialog boxes can be either modal or modeless. When a modal dialog is created, its parent frame is blocked. That is, the user will not be able to interact with the parent or even bring the parent to the front of the screen until the dialog box is closed. Modeless dialog boxes do not block their parents in the same way, so they seem a lot more like independent windows.

> In Java, a dialog box is an object belonging to the class `Dialog` or to one of its subclasses. A `Dialog` cannot have a menu bar, but it can contain other GUI components, and it generates the same `WindowEvents` as a `Frame`. `Dialog` objects can be either modal or modeless. A parameter to the constructor specifies which it should be.

> Click on this button to run a little demonstration of modal dialogs:

> Sorry, but your browser
> doesn't support Java.

> The dialogs in this example belong to a class named `MessageDialog`, which is defined in the file MessageDialog.java. You might find this class useful for creating simple dialogs for your own programs. The source code for the applet and frame classes used in this example is in the file DialogDemoLauncher.java

[ Next Section | Previous Section | Chapter Index | Main Index ]