Swing Application Structure

   

Java™ 2 Primer Plus
By Steven Haines, Steve Potts

Table of Contents
Chapter 16.  The Swing Library


Beneath the surface, Swingcomponents differ greatly from AWT components. For one thing, they are written entirely in Java. Another difference is in the way that they are implemented. Swing is built on the concept of the Model, View, and Controller (MVC) design pattern.

The MVC design pattern suggests that all the logic that is needed to make a component work be divided into three separate classes that work together to provide the behavior that you want.

  • Model Contains the actual data that describes the state of a component. That state might include whether a button is pushed or what text is currently in a text field. This layer talks to the database if the GUI is a database front-end.

  • View Displays the component on the screen. Controls colors, cell dimensions, fonts, and so on. A single Model can have several views. For example, an HTML file can be shown as a text file with the tags visible for edit. Alternatively, it can be rendered to the screen with the tags interpreted and rendered in the correct color, font, and so on.

  • Controller Responds to user input. If a user clicks on save, this class receives the event and calls the Model class's save-to-file methods to store the data.

All the Swing components are built using this division of labor, although you may or may not have to use some of the layers. For example, the JButton class is the controller, but it contains a DefaultButtonModel object, some state information, and a DefaultButtonUI object that provides the view. Because of its simplicity, a JButton's underlying MVC structure is rarely visible to the programmer. It can be made visible, however, if you choose to program with it. Listing 16.1 shows an example of this.

Listing 16.1 The TestButtonModel.java File
 /*   * TestButtonModel.java   *    * Created on July 30, 2002, 2:36 PM   */  package ch16;  import javax.swing.*;  import javax.swing.plaf.*;  import java.awt.FlowLayout;  import java.awt.event.*;   /**   *   * @author  Stephen Potts   * @version   */  public class TestButtonModel extends JFrame implements ActionListener  {     JButton btnTest;     /** Creates new TestButtonModel */     public TestButtonModel()     {        btnTest = new JButton("Test");        btnTest.addActionListener(this);         getContentPane().add(btnTest);        this.getContentPane().setLayout(new FlowLayout());        addWindowListener(new WinCloser());        setTitle("Using a JButton Model");        setBounds( 100, 100, 300, 300);        setVisible(true);     }     public void actionPerformed(ActionEvent ae)     {        if (ae.getActionCommand().equals("Test"))        {            ButtonModel bm = btnTest.getModel();            System.out.println("The ButtonModel class is " + bm);            System.out.println(bm.getMnemonic());            System.out.println(bm.isArmed());            System.out.println(bm.isEnabled());            System.out.println(bm.isPressed());            System.out.println(bm.isRollover());            System.out.println(bm.isSelected());            ButtonUI bu = btnTest.getUI();            System.out.println("The ButtonUI class is " + bu);        }     }     public static void main(String[] args)      {        TestButtonModel tbm = new TestButtonModel();     }  }  class WinCloser extends WindowAdapter  {     public void windowClosing(WindowEvent e)     {        System.exit(0);      }  } 

We declare a JButton instead of a Button object.

 JButton btnTest; 

The button is instantiated, and the actionListener is added in the same way as an AWT button.

 btnTest = new JButton("Test");  btnTest.addActionListener(this); 

The rules of Swing forbid operations directly on the JFrame itself. A method call to getContentPane() returns a handle to a Pane object that covers the JFrame. You use this object to access the JFrame.

 getContentPane().add(btnTest);  this.getContentPane().setLayout(new FlowLayout()); 

The event listener is the controller for this application. It gets a handle to the Model, and then uses it to make several calls to the Model class's methods.

 ButtonModel bm = btnTest.getModel();  System.out.println("The ButtonModel class is " + bm);  System.out.println(bm.getMnemonic());  System.out.println(bm.isArmed());  System.out.println(bm.isEnabled());  System.out.println(bm.isPressed());  System.out.println(bm.isRollover());  System.out.println(bm.isSelected()); 

We can also obtain a handle to the UI object for JButton, but all that we can do with it is print the object to the screen. The ButtonUI class has methods that it inherits from ComponentUI, but none of them are meant for programmers to use.

 ButtonUI bu = btnTest.getUI();  System.out.println("The ButtonUI class is " + bu); 

The result of running this example is shown if Figure 16.1.

Figure 16.1. The Model and View classes can be accessed by obtaining a handle to them.

graphics/16fig01.gif

The JButton class instantiates the DefautlButtonModel class to serve as its model. The MetalButtonUI class is instantiated if this is the look and feel that you have chosen, or has been set by default (the case here).

Managing Windows

Listing 16.1 still contains a WinCloser class to handle window events. Swing introduces a better way to close applications. JFrame contains a method call to handle this for you. All that you have to do is call the setDefaultCloseOperation() method and pass it a constant. The application will close automatically when the window closes. Listing 16.2 shows a modified version of the TestButtonModel class that closes in the new way.

Listing 16.2 The TestJFrame1.java File
 /*   * TestJFrame1.java   *   * Created on July 30, 2002, 2:36 PM   */  package ch16;  import javax.swing.*;  import java.awt.FlowLayout;  import java.awt.event.*;   /**   *   * @author  Stephen Potts   * @version   */  public class TestJFrame1 extends JFrame implements ActionListener  {     JButton btnExit;     /** Creates new TestJFrame1 */      public TestJFrame1()     {        btnExit = new JButton("Exit");        btnExit.addActionListener(this);        getContentPane().add(btnExit);        this.getContentPane().setLayout(new FlowLayout());        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        setTitle("Using JFrame Default Closing");        setBounds( 100, 100, 300, 300);        setVisible(true);     }     public void actionPerformed(ActionEvent ae)     {        if (ae.getActionCommand().equals("Exit"))        {             System.out.println("Preparing to close ");             System.exit(0);        }     }     public static void main(String[] args)     {        TestJFrame1 tjf = new TestJFrame1();     }  } 

The WinCloser class is completely gone. The setting of the Window listener has also been made obsolete. The only line of code needed to provide the behavior that we need is this one:

 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

Running this example produces the result shown in Figure 16.2.

Figure 16.2. JFrame enables you to specify the proper application termination logic without creating an extra class.

graphics/16fig02.gif

JFrame

The JFrame class is the container most used when creating Swing applications. Even when we create JPanels and JScrollPanes, we typically place them inside a JFrame for display.

A JFrame is an extension of the Frame class that adds Swing compatibility. There are two ways to create a JFrame object from your Java class. You can extend the JFrame class, or you can declare a JFrame in the main() method. Listing 16.3 shows how to create a Java application by declaration in the main().

Listing 16.3 The JFrameDeclarer.java File
 /*   * JFrameDeclarer.java   *   * Created on July 29, 2002, 3:15 PM   */  package ch16;  import javax.swing.*;  import java.awt.event.*;  /**   *   * @author  Stephen Potts   * @version   */  public class JFrameDeclarer extends JPanel  {      JLabel jl1;     /** Creates new JFrameDeclarer */      public JFrameDeclarer()     {         jl1 = new JLabel("This is a JPanel");         this.add(jl1);      }     public static void main(String args[])     {        JFrameDeclarer jfd = new JFrameDeclarer();        JFrame jf = new JFrame();        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        jf.getContentPane().add(jfd);        jf.setTitle("Just a JFrame");        jf.setBounds( 100, 100, 200, 200);        jf.setVisible(true);     }  } 

In this example, the JFrame is declared explicitly and the handle is used to call methods on this class.

 JFrame jf = new JFrame();  jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  jf.getContentPane().add(jfd); 

Notice the explicit use of the handle in the method calls.

 C:\>java ch16.JFrameDeclarer 

This will open a window that looks like the one in Figure 16.3:

Figure 16.3. Declaring a class JFrame can create a window.

graphics/16fig03.gif

This JPanel only holds one simple JLabel object. They are really sophisticated containers that are capable of far more, as you will see in the following sections.

JComponent

All Swing components inherit functionality from the javax.swing.JComponent class. The JComponent class is actually derived from the java.awt.Container class. It provides the following functionality to all the classes derived from it:

  • Pluggable look and feel The same component can be rendered either to look like a Windows, Motif, Mac, or a special Metal form.

  • Keyboard bindings Hot keys can be associated with the components.

  • ToolTips Mouse-over help can be created using the JComponent.

  • Property Support The association between properties and components is done at this level.

  • Accessibility This class provides dummy method calls of the Accessibility interface.

Because the JComponent class is declared to be abstract, you never create an instance of it directly, but rather through one of its subclasses such as JButton or JTextField.

JPanels

The javax.swing.JPanel class is a generic container that is rectangular, but lacks the title and border of a JFrame. Its default behavior is to implement a flow of controls from left to right (flow layout) with wrapping and double buffering.

Primarily, JPanels are used to provide several containers within a JFrame. This enables you greater flexibility when laying out a screen. Listing 16.4 shows how adding a JPanel can change the behavior of the layout of objects.

Listing 16.4 The TestJPanel.java File
 /*   * TestJPanel.java   *   * Created on July 30, 2002, 11:35 AM   */  package ch16;  import javax.swing.*;  import java.awt.event.*;  /**   *   * @author  Stephen Potts   * @version   */  public class TestJPanel extends JFrame  {      JTextField tf1;      JTextField tf2;      /** Creates new TestJPanel */      public TestJPanel()      {          tf1 = new JTextField("Directly on the JPanel");          tf2 = new JTextField("Following the first TextField");          JPanel p1 = new JPanel();          p1.add(tf1);          p1.add(tf2);          getContentPane().add(p1);          this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          setTitle("Using a JPanel");          setBounds( 100, 100, 250, 300);          setVisible(true);      }      public static void main(String[] args)      {          TestJPanel tp = new TestJPanel();      }  } 

The main import statement is to access the javax.swing package.

 import javax.swing.*; 

This JPanel is placed on a JFrame.

 public class TestJPanel extends JFrame 

We add two components so that we can see how the layout works.

 JTextField tf1;  JTextField tf2; 

In the constructor, we add the JPanel first.

 JPanel p1 = new JPanel(); 

Next, we add the text fields to the JPanel.

 p1.add(tf1);  p1.add(tf2); 

We add the JPanel to the content pane of the JFrame.

 getContentPane().add(p1); 

We use our new way of closing the window and the application.

 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

Running this example produces the result shown in Figure 16.4.

Figure 16.4. Text fields can be added directly to the panel, which lays them out flowing from left to right with line wrapping.

graphics/16fig04.gif

Notice the behavior that comes from using a JPanel. The laying of objects one after the other with wrapping is far more intuitive than overwriting one with the other.

Using the JScrollPane Control

Another useful container is the javax.swing.JScrollPane class. This container is unique in that it only allows for one object to be placed on it. This seems limiting until you realize that the object can be a JPanel, which can hold an arbitrary number of objects.

The big attraction of the JScrollPane is the optional presence of both a horizontal and a vertical scrollbar. There are six possible values that can be passed to one of the constructors:

  • HORIZONTAL_SCROLLBAR_ALWAYS

  • HORIZONTAL_SCROLLBAR_AS_NEEDED

  • HORIZONTAL_SCROLLBAR_NEVER

  • VERTICAL_SCROLLBAR_ALWAYS

  • VERTICAL_SCROLLBAR_AS_NEEDED

  • VERTICAL_SCROLLBAR_NEVER

The default is ScrollPane.SCROLLBARS_AS_NEEDED. If you create a JScrollPane using the default constructor, you will get scrollbars only if the size of the panel exceeds the size of the JScrollPane.

Listing 16.5 shows a JPanel that is added to a JScrollPane.

Listing 16.5 The TestJScrollPane.java File
 /*   * TestJScrollPane.java   *   * Created on July 30, 2002, 11:35 AM   */  package ch16;  import java.awt.*;  import javax.swing.*;  import java.awt.event.*;  /**   *   * @author  Stephen Potts   * @version   */  public class TestJScrollPane extends JFrame  {     JScrollPane sp;     JTextField tf1;     JTextField tf2;     JTextField tf3;     JTextField tf4;     JTextField tf5;     JTextField tf6;     JTextField tf7;     JTextField tf8;     /** Creates new TestJScrollPane */      public TestJScrollPane()     {        //create eight text fields        tf1 = new JTextField("Text Field Number 1 ");        tf2 = new JTextField("Text Field Number 2 ");        tf3 = new JTextField("Text Field Number 3 ");        tf4 = new JTextField("Text Field Number 4 ");        tf5 = new JTextField("Text Field Number 5 ");        tf6 = new JTextField("Text Field Number 6 ");        tf7 = new JTextField("Text Field Number 7 ");        tf8 = new JTextField("Text Field Number 8 ");        //add the panel        JPanel p1 = new JPanel();        p1.add(tf1);        p1.add(tf2);        p1.add(tf3);        p1.add(tf4);        p1.add(tf5);        p1.add(tf6);        p1.add(tf7);        p1.add(tf8);        //create the scroll pane        sp = new JScrollPane(p1);        sp.setHorizontalScrollBarPolicy(                  JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);        sp.setVerticalScrollBarPolicy(                    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);        getContentPane().add(sp);        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        setTitle("Using a JScrollPane");        setBounds( 100, 100, 300, 300);         setVisible(true);        sp.scrollRectToVisible(new Rectangle(150,150,300,300));     }     public static void main(String[] args)     {        TestJScrollPane tsp = new TestJScrollPane();     }  } 

The JScrollPane is instantiated with the panel to be displayed passed in as a parameter to the constructor.

 sp = new JScrollPane(p1); 

Calling methods on the JscrollPane class can set the policy on scrollbars that you want to follow.

 sp.setHorizontalScrollBarPolicy(                  JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);  sp.setVerticalScrollBarPolicy(                     JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 

Finally, we add the JScrollPane to the content pane of the JFrame.

 getContentPane().add(sp); 

The result of running this example is shown in Figure 16.5.

Figure 16.5. JPanels added to JScrollPanes can be accessed using scrollbars.

graphics/16fig05.gif

Notice that no wrapping took place after we placed the Panel in the JScrollPane.

Dialogs

The final container type that we will cover is the Dialog class. A Frame object or another Dialog always contains Dialog objects. It can be modal, locking out other processes until the dialog is closed, or it can be modeless, allowing it to remain open while the user works in other windows.

A Dialog object fires window events when the state of its window changes. The show() method is used to bring the Dialog object to the front and display it.

A common use of Dialogs is to confirm something. Listing 16.6 shows an example of how this works.

Listing 16.6 The TestJDialog.java File
 /*   * TestJDialog.java   *   * Created on July 30, 2002, 2:36 PM    */  package ch16;  import javax.swing.*;  import java.awt.*;  import java.awt.event.*;  /**   *   * @author  Stephen Potts   * @version   */  public class TestJDialog extends JFrame implements ActionListener  {      JButton btnExit;      JButton btnYes;      JButton btnNo;      JDialog dlgConfirm;       /** Creates new TestJDialog */      public TestJDialog()      {          btnExit = new JButton("Exit");          btnExit.addActionListener(this);          getContentPane().add(btnExit);          this.getContentPane().setLayout(new FlowLayout());          dlgConfirm = new JDialog(this);          dlgConfirm.setResizable(false);          btnYes = new JButton("Yes");          btnYes.addActionListener(this);          btnNo = new JButton("No");          btnNo.addActionListener(this);          dlgConfirm.getContentPane().add(btnYes);           dlgConfirm.getContentPane().add(btnNo);          dlgConfirm.setTitle("Are you sure?");          dlgConfirm.setSize(200, 100);          dlgConfirm.getContentPane().setLayout(new FlowLayout());          this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          setTitle("Using a JDialog");          setBounds( 100, 100, 300, 300);          setVisible(true);      }       public void actionPerformed(ActionEvent ae)      {          if (ae.getActionCommand().equals("Exit"))              dlgConfirm.show();          if (ae.getActionCommand().equals("Yes"))              System.exit(0);          if (ae.getActionCommand().equals("No"))              dlgConfirm.setVisible(false);      }      public static void main(String[] args)      {          TestJDialog td = new TestJDialog();      }  } 

A new JDialog is created and passed to its parent as a parameter.

 dlgConfirm = new JDialog(this); 

Buttons are created to be added to the dialog. The ActionListener for these buttons will still be this class.

 btnYes = new JButton("Yes");  btnYes.addActionListener(this);  btnNo = new JButton("No");  btnNo.addActionListener(this); 

We add the buttons to the content pane of the JDialog class.

 dlgConfirm.getContentPane().add(btnYes);  dlgConfirm.getContentPane().add(btnNo); 

The title is added with a setTitle() method call.

 dlgConfirm.setTitle("Are you sure?"); 

The size and layout are added next.

 dlgConfirm.setSize(200, 100);  dlgConfirm.getContentPane().setLayout(new FlowLayout()); 

When we run this example, the JFrame appears and shows the Exit button. Clicking this will open the JDialog as shown in Figure 16.6.

Figure 16.6. JDialogs can be used to confirm user actions.

graphics/16fig06.gif

Clicking the Yes button will cause the Dialog and the Frame to close.


       
    Top
     



    Java 2 Primer Plus
    Java 2 Primer Plus
    ISBN: 0672324156
    EAN: 2147483647
    Year: 2001
    Pages: 332

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