10.6 A Comparison: Constructors Versus Static Methods


We've talked quite a bit about the two fundamental ways to create dialogs using JOptionPane: instantiate a JOptionPane and ask it to put itself into a JDialog or JInternalFrame, which you then display, or create and display the dialog in a single step by invoking one of the many static "show" methods.

The basic trade-off is this: using the static methods is a bit easier, but using a constructor allows you to hold onto and reuse the JOptionPane instance, a tempting feature if the pane is fairly complex and you expect to display it frequently (if you use the static methods, the option pane is recreated each time you call). The significance of this difference depends largely on the complexity of the pane. Because of lingering issues that make reusing JOptionPane problematic, it's still best to avoid this feature (see the note in the discussion following this example program for details).

The following example shows the differences between using JOptionPane's static methods and its constructors. It allows both internal and noninternal dialogs to be created, showing how each is done.

// OptPaneComparison.java // import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.beans.*; public class OptPaneComparison extends JFrame {   public static void main(String[] args) {     JFrame f = new OptPaneComparison("Enter your name");     f.setVisible(true);   }   public OptPaneComparison(final String message) {     setDefaultCloseOperation(EXIT_ON_CLOSE);     final int msgType = JOptionPane.QUESTION_MESSAGE;     final int optType = JOptionPane.OK_CANCEL_OPTION;     final String title = message;     setSize(350, 200);     // Create a desktop for internal frames.     final JDesktopPane desk = new JDesktopPane( );     setContentPane(desk);     // Add a simple menu bar.     JMenuBar mb = new JMenuBar( );     setJMenuBar(mb);     JMenu menu = new JMenu("Dialog");     JMenu imenu = new JMenu("Internal");     mb.add(menu);     mb.add(imenu);     final JMenuItem construct = new JMenuItem("Constructor");     final JMenuItem stat = new JMenuItem("Static Method");     final JMenuItem iconstruct = new JMenuItem("Constructor");     final JMenuItem istat = new JMenuItem("Static Method");     menu.add(construct);     menu.add(stat);     imenu.add(iconstruct);     imenu.add(istat);     // Create our JOptionPane. We're asking for input, so we call setWantsInput.      // Note that we cannot specify this via constructor parameters.     optPane = new JOptionPane(message, msgType, optType);     optPane.setWantsInput(true);     // Add a listener for each menu item that will display the appropriate     // dialog/internal frame.     construct.addActionListener(new ActionListener( ) {       public void actionPerformed(ActionEvent ev) {         // Create and display the dialog.         JDialog d = optPane.createDialog(desk, title);         d.setVisible(true);         respond(getOptionPaneValue( ));       }     });     stat.addActionListener(new ActionListener( ) {       public void actionPerformed(ActionEvent ev) {         String s = JOptionPane.showInputDialog           (desk, message, title, msgType);         respond(s);       }     });     iconstruct.addActionListener(new ActionListener( ) {       public void actionPerformed(ActionEvent ev) {         // Create and display the dialog.         JInternalFrame f = optPane.createInternalFrame(desk, title);         f.setVisible(true);         // Listen for the frame to close before getting the value from it.         f.addPropertyChangeListener(new PropertyChangeListener( ) {           public void propertyChange(PropertyChangeEvent ev) {             if ((ev.getPropertyName( ).equals(JInternalFrame.IS_CLOSED_PROPERTY))             && (ev.getNewValue( ) == Boolean.TRUE)) {               respond(getOptionPaneValue( ));             }           }         });       }     });     istat.addActionListener(new ActionListener( ) {       public void actionPerformed(ActionEvent ev) {         String s = JOptionPane.showInternalInputDialog           (desk, message, title, msgType);         respond(s);       }     });   }   // This method gets the selected value from the option pane and resets the   // value to null so we can use it again.   protected String getOptionPaneValue( ) {     // Get the result . . .      Object o = optPane.getInputValue( );     String s = "<Unknown>";     if (o != null)       s = (String)o;     Object val = optPane.getValue( ); // which button?     // Check for Cancel button or closed option.     if (val != null) {       if (val instanceof Integer) {         int intVal = ((Integer)val).intValue( );         if((intVal == JOptionPane.CANCEL_OPTION) ||            (intVal == JOptionPane.CLOSED_OPTION))           s = "<Cancel>";       }     }     // A little trick to clean the text field. It is updated only if the initial     // value is changed. To do this, we'll set it to a dummy value ("X")     // and then clear it.     optPane.setValue("");     optPane.setInitialValue("X");     optPane.setInitialValue("");     return s;   }   protected void respond(String s) {     if (s == null)       System.out.println("Never mind.");     else       System.out.println("You entered: " + s);   }   protected JOptionPane optPane; } 

The user interface for this example (Figure 10-14) is simple. We provide two menus: one to create standard dialogs and one to create internal frame dialogs. Each menu allows us to create a dialog using the JOptionPane we're holding (created via a constructor) or create a new dialog with a static method call.

Figure 10-14. OptPaneComparison display
figs/swng2.1014.gif

There are a few details here worth pointing out. First, notice that we called setWantsInput(true) on our JOptionPane object. This is how we create a pane that looks like those created by the showInputDialog( ) methods. Without this call, there would not be a text field in our dialog.

The next point of interest is the way we handle the JInternalFrame we get from the JOptionPane. Since this is just an ordinary internal frame, we don't have any simple way to block while we wait for input. Instead, we add a property change listener to the frame, which will wait for the frame to be closed. Alternatively, we could have added a property change listener to the JOptionPane and listened for the INPUT_VALUE_PROPERTY.

One last thing to point out is the little trick at the end of our getOptionPaneValue( ) method. We want to clear the value from the text field so that it won't show up there the next time we use the same option pane. Since we have no way of getting to the text field directly, and no way of explicitly clearing the value,[11] we resort to making two changes to the initial value of the field. The reason we have to make two calls is that the text field is cleared only when the initialValue property changes. If we just set it to an empty string every time, that wouldn't be considered a change, so the field wouldn't be updated.

[11] The setValue( ) call with an empty string might seem promising, but it isn't enough.

In this example, we held onto the JOptionPane object. You might be tempted to hold onto the JDialog you get from the pane instead. This is generally not a good idea. The JOptionPane "disposes" of the dialog when it closes, meaning that, among other things, its peer is destroyed. It's easier to reuse the JOptionPane. Similar difficulties arise if you try to reuse the JInternalFrame created by the JOptionPane. Reusing the JOptionPane seems like a safer strategy, but there are still problems.

Reusing a JOptionPane is not recommended. Read this section for details.

If you experiment with the program carefully, you'll discover some lingering and subtle problems with any attempt to reuse a single JOptionPane for multiple interactions with the user for example, use the Constructor method in the Dialog menu, enter a name, and then click on OK. Then try the same method again, enter some text (or not, it doesn't make a difference), and close the window manually instead of clicking on either of the buttons. The program will report that you entered the same name as when you last clicked on OK, and there's no way to get it to forget this! You can even show the dialog multiple times and click on Cancel. If you then show it and close the window again, you'll see that the program still believes you entered the name you last said "OK" to.

This problem, on top of the fact that we needed to resort to trickery to get an empty initial value displayed at all, suggests that any savings in efficiency we might gain by reusing a JOptionPane are more than offset by the fact that, at least as it is currently implemented, this is not a safe or well-supported thing to do.

If you want to see even more disturbing behavior, remove the line in the "little trick" that reads optPane.setValue(""). The program seems at first to work the same way, but if you use the Constructor option in the Internal menu and try to enter the same name more than once, the OK button fails to work, leaving the internal frame open. Trying to cancel that method twice in a row fails in the same way.

10.6.1 Nonstatic Methods

Most of the methods defined in JOptionPane are static (or accessors for the pane's properties). Here are the only other nonstatic methods in the class:

public JDialog createDialog(Component parentComponent, String title)

Create a new JDialog containing this JOptionPane. The dialog's parent is the specified component, and the input string is used as the window's title. The dialog is centered on the input parent component. This method is used by all of the static "show dialog" methods, and it is also the method to use when you construct a JOptionPane directly and want to use it in a dialog.

public JInternalFrame createInternalFrame(Component parentComponent, String title)

Create a new JInternalFrame containing this JOptionPane. The frame's parent is the specified component, and the input string is used as the frame's title. The parent component is used to search (up the parent chain) for an enclosing JDesktopPane. (See the detailed discussion of the parentComponent parameter earlier in this chapter.) This method is used by all of the static "show internal frame" methods; it is the method to use when you construct a JOptionPane directly and want to use it in an internal frame.

public void selectInitialValue( )

Select the initial value, causing the default button to receive focus. If you are going to use a JOptionPane to display a dialog multiple times, you should call this method before making the dialog visible.

public void updateUI( )

Called to indicate that the L&F has changed.

10.6.2 Miscellaneous Static Methods

In addition to all of the static methods defined for showing dialogs (of which we saw some examples earlier), several other static methods are also defined:

public static Frame getFrameForComponent(Component parentComponent)

Search the parent hierarchy of the given Component until it finds a Frame, which it returns. If it encounters a null parent (or if the input component is null), it returns the result of a call to getRootFrame( ).

public static JDesktopPane getDesktopPaneForComponent(Component parentComponent)

Search the parent hierarchy of the given Component until it finds a JDesktopPane, which it returns. If it encounters a null parent (or if the input component is null), it returns null.

public static void setRootFrame(Frame newRootFrame)

Set a default Frame to be used when an attempt is made to create a dialog and a parent Frame cannot be found.

public static Frame getRootFrame( )

Return the value set by setRootFrame( ). The value is initially determined by the L&F.



Java Swing
Graphic Java 2: Mastering the Jfc, By Geary, 3Rd Edition, Volume 2: Swing
ISBN: 0130796670
EAN: 2147483647
Year: 2001
Pages: 289
Authors: David Geary

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net