Swing

A catalog of Swing components

Now that you understand layout managers and the event model, you’re ready to see how Swing components can be used. This section is a non-exhaustive tour of the Swing components and features that you’ll probably use most of the time. Each example is intended to be reasonably small so that you can easily lift the code and use it in your own programs. Feedback

Keep in mind:

  1. You can easily see what each of these examples looks like while running by viewing the HTML pages in the downloadable source code for this chapter (www.BruceEckel.com). Feedback
  2. The JDK documentation from java.sun.com contains all of the Swing classes and methods (only a few are shown here). Feedback
  3. Because of the naming convention used for Swing events, it’s fairly easy to guess how to write and install a handler for a particular type of event. Use the lookup program ShowAddListeners.java from earlier in this chapter to aid in your investigation of a particular component. Feedback
  4. When things start to get complicated you should graduate to a GUI builder. Feedback

Buttons

Swing includes a number of different types of buttons. All buttons, check boxes, radio buttons, and even menu items are inherited from AbstractButton (which, since menu items are included, would probably have been better named “AbstractSelector” or something equally general). You’ll see the use of menu items shortly, but the following example shows the various types of buttons available: Feedback

This begins with the BasicArrowButton from javax.swing.plaf.basic, then continues with the various specific types of buttons. When you run the example, you’ll see that the toggle button holds its last position, in or out. But the check boxes and radio buttons behave identically to each other, just clicking on or off (they are inherited from JToggleButton). Feedback

Button groups

If you want radio buttons to behave in an “exclusive or” fashion, you must add them to a “button group.” But, as the following example demonstrates, any AbstractButton can be added to a ButtonGroup. Feedback

To avoid repeating a lot of code, this example uses reflection to generate the groups of different types of buttons. This is seen in makeBPanel( ), which creates a button group and a JPanel. The second argument to makeBPanel( ) is an array of String. For each String, a button of the class represented by the first argument is added to the JPanel:

The title for the border is taken from the name of the class, stripping off all the path information. The AbstractButton is initialized to a JButton that has the label “Failed,” so if you ignore the exception message, you’ll still see the problem on screen. The getConstructor( ) method produces a Constructor object that takes the array of arguments of the types in the Class array passed to getConstructor( ). Then all you do is call newInstance( ), passing it an array of Object containing your actual arguments—in this case, just the String from the ids array. Feedback

This adds a little complexity to what is a simple process. To get “exclusive or” behavior with buttons, you create a button group and add each button for which you want that behavior to the group. When you run the program, you’ll see that all the buttons except JButton exhibit this “exclusive or” behavior. Feedback

Icons

You can use an Icon inside a JLabel or anything that inherits from AbstractButton (including JButton, JCheckBox, JRadioButton, and the different kinds of JMenuItem). Using Icons with JLabels is quite straightforward (you’ll see an example later). The following example explores all the additional ways you can use Icons with buttons and their descendants. Feedback

You can use any gif files you want, but the ones used in this example are part of this book’s code distribution, available at www.BruceEckel.com. To open a file and bring in the image, simply create an ImageIcon and hand it the file name. From then on, you can use the resulting Icon in your program. Feedback

An Icon can be used as an argument for many different Swing component constructors, but you can also use setIcon( ) to add or change an Icon. This example also shows how a JButton (or any AbstractButton) can set the various different sorts of icons that appear when things happen to that button: when it’s pressed, disabled, or “rolled over” (the mouse moves over it without clicking). You’ll see that this gives the button a nice animated feel. Feedback

Tool tips

The previous example added a “tool tip” to the button. Almost all of the classes that you’ll be using to create your user interfaces are derived from JComponent, which contains a method called setToolTipText(String). So, for virtually anything you place on your form, all you need to do is say (for an object jc of any JComponent-derived class):

jc.setToolTipText("My tip");

 

and when the mouse stays over that JComponent for a predetermined period of time, a tiny box containing your text will pop up next to the mouse. Feedback

Text fields

This example shows the extra behavior that JTextFields are capable of:

The JTextField t3 is included as a place to report when the action listener for the JTextField t1 is fired. You’ll see that the action listener for a JTextField is fired only when you press the “enter” key. Feedback

The JTextField t1 has several listeners attached to it. The T1 listener is a DocumentListener that responds to any change in the “document” (the contents of the JTextField, in this case). It automatically copies all text from t1 into t2. In addition, t1’s document is set to a derived class of PlainDocument, called UpperCaseDocument, which forces all characters to uppercase. It automatically detects backspaces and performs the deletion, adjusting the caret and handling everything as you would expect. Feedback

Borders

JComponent contains a method called setBorder( ), which allows you to place various interesting borders on any visible component. The following example demonstrates a number of the different borders that are available, using a method called showBorder( ) that creates a JPanel and puts on the border in each case. Also, it uses RTTI to find the name of the border that you’re using (stripping off all the path information), then puts that name in a JLabel in the middle of the panel:

You can also create your own borders and put them inside buttons, labels, etc.—anything derived from JComponent. Feedback

JScrollPanes

Most of the time you’ll just want to let a JScrollPane do its job, but you can also control which scroll bars are allowed—vertical, horizontal, both, or neither:

 

Using different arguments in the JScrollPane constructor controls the scrollbars that are available. This example also dresses things up a bit using borders. Feedback

A mini-editor

The JTextPane control provides a great deal of support for editing, without much effort. The following example makes very simple use of this component, ignoring the bulk of the functionality of the class:

 

The button just adds randomly generated text. The intent of the JTextPane is to allow text to be edited in place, so you will see that there is no append( ) method. In this case (admittedly, a poor use of the capabilities of JTextPane), the text must be captured, modified, and placed back into the pane using setText( ). Feedback

As mentioned before, the default layout behavior of an applet is to use the BorderLayout. If you add something to the pane without specifying any details, it just fills the center of the pane out to the edges. However, if you specify one of the surrounding regions (NORTH, SOUTH, EAST, or WEST) as is done here, the component will fit itself into that region; in this case, the button will nest down at the bottom of the screen. Feedback

Notice the built-in features of JTextPane, such as automatic line wrapping. There are lots of other features that you can look up using the JDK documentation. Feedback

Check boxes

A check box provides a way to make a single on/off choice. It consists of a tiny box and a label. The box typically holds a little “x” (or some other indication that it is set) or is empty, depending on whether that item was selected. Feedback

You’ll normally create a JCheckBox using a constructor that takes the label as an argument. You can get and set the state, and also get and set the label if you want to read or change it after the JCheckBox has been created. Feedback

Whenever a JCheckBox is set or cleared, an event occurs, which you can capture the same way you do a button: by using an ActionListener. The following example uses a JTextArea to enumerate all the check boxes that have been checked:

The trace( ) method sends the name of the selected JCheckBox and its current state to the JTextArea using append( ), so you’ll see a cumulative list of the checkboxes that were selected and what their state is. Feedback

Radio buttons

The concept of a radio button in GUI programming comes from pre-electronic car radios with mechanical buttons; when you push one in, any other button that was pressed pops out. Thus, it allows you to force a single choice among many. Feedback

All you need to do to set up an associated group of JRadioButtons is to add them to a ButtonGroup (you can have any number of ButtonGroups on a form). One of the buttons can optionally have its starting state set to true (using the second argument in the constructor). If you try to set more than one radio button to true, then only the final one set will be true. Feedback

Here’s a simple example of the use of radio buttons. Note that you capture radio button events like all others:

To display the state, a text field is used. This field is set to non-editable because it’s used only to display data, not to collect it. Thus it is an alternative to using a JLabel. Feedback

Combo boxes (drop-down lists)

Like a group of radio buttons, a drop-down list is a way to force the user to select only one element from a group of possibilities. However, it’s a more compact way to accomplish this, and it’s easier to change the elements of the list without surprising the user. (You can change radio buttons dynamically, but that tends to be visibly jarring). Feedback

By default, JComboBox box is not like the combo box in Windows, which lets you select from a list or type in your own selection. To produce this behavior you must call setEditable( ). With a JComboBox box, you choose one and only one element from the list. In the following example, the JComboBox box starts with a certain number of entries, and then new entries are added to the box when a button is pressed. Feedback

The JTextField displays the “selected index,” which is the sequence number of the currently selected element, as well as the text of the selected item in the combo box. Feedback

List boxes

List boxes are significantly different from JComboBox boxes, and not just in appearance. While a JComboBox box drops down when you activate it, a JList occupies some fixed number of lines on a screen all the time and doesn’t change. If you want to see the items in a list, you simply call getSelectedValues( ), which produces an array of String of the items that have been selected. Feedback

A JList allows multiple selection; if you control-click on more than one item (holding down the “control” key while performing additional mouse clicks), the original item stays highlighted and you can select as many as you want. If you select an item, then shift-click on another item, all the items in the span between the two are selected. To remove an item from a group, you can control-click it. Feedback

You can see that borders have also been added to the lists. Feedback

If you just want to put an array of Strings into a JList, there’s a much simpler solution; you pass the array to the JList constructor, and it builds the list automatically. The only reason for using the “list model” in the preceding example is so that the list could be manipulated during the execution of the program. Feedback

JLists do not automatically provide direct support for scrolling. Of course, all you need to do is wrap the JList in a JScrollPane, and the details are automatically managed for you. Feedback

Tabbed panes

The JTabbedPane allows you to create a “tabbed dialog,” which has file-folder tabs running across one edge, and all you have to do is press a tab to bring forward a different dialog.

In Java, the use of some sort of “tabbed panel” mechanism is quite important, because in applet programming the use of pop-up dialogs is discouraged by automatically adding a little warning to any dialog that pops up out of an applet. Feedback

When you run the program, you’ll see that the JTabbedPane automatically stacks the tabs if there are too many of them to fit on one row. You can see this by resizing the window when you run the program from the console command line. Feedback

Message boxes

Windowing environments commonly contain a standard set of message boxes that allow you to quickly post information to the user or to capture information from the user. In Swing, these message boxes are contained in JOptionPane. You have many different possibilities (some quite sophisticated), but the ones you’ll most commonly use are probably the message dialog and confirmation dialog, invoked using the static JOptionPane.showMessageDialog( ) and JOptionPane. showConfirmDialog( ). The following example shows a subset of the message boxes available with JOptionPane:

To be able to write a single ActionListener, I’ve used the somewhat risky approach of checking the String labels on the buttons. The problem with this is that it’s easy to get the label a little bit wrong, typically in capitalization, and this bug can be hard to spot. Feedback

Note that showOptionDialog( ) and showInputDialog( ) provide return objects that contain the value entered by the user. Feedback

Menus

Each component capable of holding a menu, including JApplet, JFrame, JDialog, and their descendants, has a setJMenuBar( ) method that accepts a JMenuBar (you can have only one JMenuBar on a particular component). You add JMenus to the JMenuBar, and JMenuItems to the JMenus. Each JMenuItem can have an ActionListener attached to it, to be fired when that menu item is selected. Feedback

Unlike a system that uses resources, with Java and Swing you must hand assemble all the menus in source code. Here is a very simple menu example:

The use of the modulus operator in “i%3” distributes the menu items among the three JMenus. Each JMenuItem must have an ActionListener attached to it; here, the same ActionListener is used everywhere, but you’ll usually need an individual one for each JMenuItem. Feedback

JMenuItem inherits AbstractButton, so it has some button-like behaviors. By itself, it provides an item that can be placed on a drop-down menu. There are also three types inherited from JMenuItem: JMenu to hold other JMenuItems (so you can have cascading menus); JCheckBoxMenuItem, which produces a checkmark to indicate whether that menu item is selected; and JRadioButtonMenuItem, which contains a radio button. Feedback

As a more sophisticated example, here are the ice cream flavors again, used to create menus. This example also shows cascading menus, keyboard mnemonics, JCheckBoxMenuItems, and the way you can dynamically change menus:

In this program I placed the menu items into arrays and then stepped through each array calling add( ) for each JMenuItem. This makes adding or subtracting a menu item somewhat less tedious. Feedback

This program creates not one but two JMenuBars to demonstrate that menu bars can be actively swapped while the program is running. You can see how a JMenuBar is made up of JMenus, and each JMenu is made up of JMenuItems, JCheckBoxMenuItems, or even other JMenus (which produce submenus). When a JMenuBar is assembled, it can be installed into the current program with the setJMenuBar( ) method. Note that when the button is pressed, it checks to see which menu is currently installed by calling getJMenuBar( ), then it puts the other menu bar in its place. Feedback

When testing for “Open,” notice that spelling and capitalization are critical, but Java signals no error if there is no match with “Open.” This kind of string comparison is a source of programming errors. Feedback

The checking and unchecking of the menu items is taken care of automatically. The code handling the JCheckBoxMenuItems shows two different ways to determine what was checked: string matching (which, as mentioned above, isn’t a very safe approach although you’ll see it used) and matching on the event target object. As shown, the getState( ) method can be used to reveal the state. You can also change the state of a JCheckBoxMenuItem with setState( ). Feedback

The events for menus are a bit inconsistent and can lead to confusion: JMenuItems use ActionListeners, but JCheckBoxMenuItems use ItemListeners. The JMenu objects can also support ActionListeners, but that’s not usually helpful. In general, you’ll attach listeners to each JMenuItem, JCheckBoxMenuItem, or JRadioButtonMenuItem, but the example shows ItemListeners and ActionListeners attached to the various menu components. Feedback

Swing supports mnemonics, or “keyboard shortcuts,” so you can select anything derived from AbstractButton (button, menu item, etc.) by using the keyboard instead of the mouse. These are quite simple; for JmenuItem,you can use the overloaded constructor that takes as a second argument the identifier for the key. However, most AbstractButtons do not have constructors like this, so the more general way to solve the problem is to use the setMnemonic( ) method. The preceding example adds mnemonics to the button and some of the menu items; shortcut indicators automatically appear on the components. Feedback

You can also see the use of setActionCommand( ). This seems a bit strange because in each case, the “action command” is exactly the same as the label on the menu component. Why not just use the label instead of this alternative string? The problem is internationalization. If you retarget this program to another language, you want to change only the label in the menu, and not change the code (which would no doubt introduce new errors). So to make this easy for code that checks the text string associated with a menu component, the “action command” can be immutable, but the menu label can change. All the code works with the “action command,” so it’s unaffected by changes to the menu labels. Note that in this program, not all the menu components are examined for their action commands, so those that aren’t do not have their action command set. Feedback

The bulk of the work happens in the listeners. BL performs the JMenuBar swapping. In ML, the “figure out who rang” approach is taken by getting the source of the ActionEvent and casting it to a JMenuItem, then getting the action command string to pass it through a cascaded if statement. Feedback

The FL listener is simple even though it’s handling all the different flavors in the flavor menu. This approach is useful if you have enough simplicity in your logic, but in general, you’ll want to take the approach used with FooL, BarL, and BazL, in which each is attached to only a single menu component, so no extra detection logic is necessary, and you know exactly who called the listener. Even with the profusion of classes generated this way, the code inside tends to be smaller, and the process is more foolproof. Feedback

You can see that menu code quickly gets long-winded and messy. This is another case where the use of a GUI builder is the appropriate solution. A good tool will also handle the maintenance of the menus. Feedback

Pop-up menus

The most straightforward way to implement a JPopupMenu is to create an inner class that extends MouseAdapter, then add an object of that inner class to each component that you want to produce pop-up behavior:

The same ActionListener is added to each JMenuItem, so that it fetches the text from the menu label and inserts it into the JTextField. Feedback

Drawing

In a good GUI framework, drawing should be reasonably easy—and it is, in the Swing library. The problem with any drawing example is that the calculations that determine where things go are typically a lot more complicated that the calls to the drawing routines, and these calculations are often mixed together with the drawing calls, so it can seem that the interface is more complicated than it actually is. Feedback

For simplicity, consider the problem of representing data on the screen—here, the data will be provided by the built-in Math.sin( ) method, that produces a mathematical sine function. To make things a little more interesting, and to further demonstrate how easy it is to use Swing components, a slider will be placed at the bottom of the form to dynamically control the number of sine wave cycles that are displayed. In addition, if you resize the window, you’ll see that the sine wave refits itself to the new window size. Feedback

Although any JComponent may be painted and thus used as a canvas, if you just want a straightforward drawing surface, you will typically inherit from a JPanel. The only method you need to override is paintComponent( ), which is called whenever that component must be repainted (you normally don’t need to worry about this, because the decision is managed by Swing). When it is called, Swing passes a Graphics object to the method, and you can then use this object to draw or paint on the surface. Feedback

In the following example, all the intelligence concerning painting is in the SineDraw class; the SineWave class simply configures the program and the slider control. Inside SineDraw, the setCycles( ) method provides a hook to allow another object—the slider control, in this case—to control the number of cycles.

All of the fields and arrays are used in the calculation of the sine wave points; cycles indicates the number of complete sine waves desired, points contains the total number of points that will be graphed, sines contains the sine function values, and pts contains the y-coordinates of the points that will be drawn on the JPanel. The setCycles( ) method creates the arrays according to the number of points needed and fills the sines array with numbers. By calling repaint( ) , setCycles( ) forces paintComponent( ) to be called so the rest of the calculation and redraw will take place. Feedback

The first thing you must do when you override paintComponent( ) is to call the base-class version of the method. Then you are free to do whatever you like; normally, this means using the Graphics methods that you can find in the documentation for java.awt.Graphics (in the JDK documentation from java.sun.com) to draw and paint pixels onto the JPanel. Here, you can see that almost all the code is involved in performing the calculations; the only two method calls that actually manipulate the screen are setColor( ) and drawLine( ). You will probably have a similar experience when creating your own program that displays graphical data; you’ll spend most of your time figuring out what it is you want to draw, but the actual drawing process will be quite simple. Feedback

When I created this program, the bulk of my time was spent in getting the sine wave to display. Once I did that, I thought it would be nice to be able to dynamically change the number of cycles. My programming experiences when trying to do such things in other languages made me a bit reluctant to try this, but it turned out to be the easiest part of the project. I created a JSlider (the arguments are the left-most value of the JSlider, the right-most value, and the starting value, respectively, but there are other constructors as well) and dropped it into the JApplet. Then I looked at the JDK documentation and noticed that the only listener was the addChangeListener, which was triggered whenever the slider was changed enough for it to produce a different value. The only method for this was the obviously named stateChanged( ), which provided a ChangeEvent object so that I could look backward to the source of the change and find the new value. By calling the sines object’s setCycles( ), the new value was incorporated and the JPanel redrawn. Feedback

In general, you will find that most of your Swing problems can be solved by following a similar process, and you’ll find that it’s generally quite simple, even if you haven’t used a particular component before. Feedback

If your problem is more complex, there are other more sophisticated alternatives for drawing, including third-party JavaBeans components and the Java 2D API. These solutions are beyond the scope of this book, but you should look them up if your drawing code becomes too onerous. Feedback

Dialog Boxes

A dialog box is a window that pops up out of another window. Its purpose is to deal with some specific issue without cluttering the original window with those details. Dialog boxes are heavily used in windowed programming environments, but less frequently used in applets. Feedback

To create a dialog box, you inherit from JDialog, which is just another kind of Window, like a JFrame. A JDialog has a layout manager (which defaults to BorderLayout), and you add event listeners to deal with events. One significant difference when the dialog window is closed is that you don’t want to shut down the application. Instead, you release the resources used by the dialog’s window by calling dispose( ). Here’s a very simple example:

Once the JDialog is created, the show( ) method must be called to display and activate it. For the dialog to close, it must call dispose( ). Feedback

You’ll see that anything that pops up out of an applet, including dialog boxes, is “untrusted.” That is, you get a warning in the window that’s been popped up. This is because, in concept, it would be possible to fool users into thinking that they’re dealing with a regular native application and to get them to type in their credit card number, which then goes across the Web. An applet is always attached to a Web page and visible within your Web browser, while a dialog box is detached—so theoretically, it’s possible. As a result, it is not so common to see an applet that uses a dialog box. Feedback

The following example is more complex; the dialog box is made up of a grid (using GridLayout) of a special kind of button that is defined here as class ToeButton. This button draws a frame around itself and, depending on its state, a blank, an “x,” or an “o” in the middle. It starts out blank, and then depending on whose turn it is, changes to an “x” or an “o.” However, it will also flip back and forth between “x” and “o” when you click on the button. (This makes the tic-tac-toe concept only slightly more annoying than it already is.) In addition, the dialog box can be set up for any number of rows and columns by changing numbers in the main application window.

Because statics can only be at the outer level of the class, inner classes cannot have static data or nested classes. Feedback

The paintComponent( ) method draws the square around the panel and the “x” or the “o.” This is full of tedious calculations, but it’s straightforward. Feedback

A mouse click is captured by the MouseListener, which first checks to see if the panel has anything written on it. If not, the parent window is queried to find out whose turn it is, which establishes the state of the ToeButton. Via the inner class mechanism, the ToeButton then reaches back into the parent and changes the turn. If the button is already displaying an “x” or an “o,” then that is flopped. You can see in these calculations the convenient use of the ternary if-else described in Chapter 3. After a state change, the ToeButton is repainted. Feedback

The constructor for ToeDialog is quite simple; It adds into a GridLayout as many buttons as you request, then resizes it for 50 pixels on a side for each button. Feedback

TicTacToe sets up the whole application by creating the JTextFields (for inputting the rows and columns of the button grid) and the “go” button with its ActionListener. When the button is pressed, the data in the JTextFields must be fetched, and, since they are in String form, turned into ints using the static Integer.parseInt( ) method. Feedback

File dialogs

Some operating systems have a number of special built-in dialog boxes to handle the selection of things such as fonts, colors, printers, and the like. Virtually all graphical operating systems support the opening and saving of files, so Java’s JFileChooser encapsulates these for easy use. Feedback

The following application exercises two forms of JFileChooser dialogs, one for opening and one for saving. Most of the code should by now be familiar, and all the interesting activities happen in the action listeners for the two different button clicks:

Note that there are many variations you can apply to JFileChooser, including filters to narrow the file names that you will allow. Feedback

For an “open file” dialog, you call showOpenDialog( ), and for a “save file” dialog, you call showSaveDialog( ). These commands don’t return until the dialog is closed. The JFileChooser object still exists, so you can read data from it. The methods getSelectedFile( ) and getCurrentDirectory( ) are two ways you can interrogate the results of the operation. If these return null, it means the user canceled out of the dialog. Feedback

HTML on Swing components

Any component that can take text can also take HTML text, which it will reformat according to HTML rules. This means you can very easily add fancy text to a Swing component. For example:

You must start the text with “<html>,” and then you can use normal HTML tags. Note that you are not forced to include the normal closing tags. Feedback

The ActionListener adds a new JLabel to the form, which also contains HTML text. However, this label is not added during init( ), so you must call the container’s validate( ) method in order to force a re-layout of the components (and thus the display of the new label). Feedback

You can also use HTML text for JTabbedPane, JMenuItem, JToolTip, JradioButton, and JCheckBox. Feedback

Sliders and progress bars

A slider (which has already been used in SineWave.java) allows the user to input data by moving a point back and forth, which is intuitive in some situations (volume controls, for example). A progress bar displays data in a relative fashion from “full” to “empty” so the user gets a perspective. My favorite example for these is to simply hook the slider to the progress bar so when you move the slider, the progress bar changes accordingly:

The key to hooking the two components together is in sharing their model, in the line: Feedback

pb.setModel(sb.getModel());

Of course, you could also control the two using a listener, but this is more straightforward for simple situations.

The JProgressBar is fairly straightforward, but the JSlider has a lot of options, such as the orientation and major and minor tick marks. Notice how straightforward it is to add a titled border. Feedback

Trees

Using a JTree can be as simple as saying:

add(new JTree(new Object[] {"this", "that", "other"}));

This displays a primitive tree. The API for trees is vast, however—certainly one of the largest in Swing. It appears that you can do just about anything with trees, but more sophisticated tasks might require quite a bit of research and experimentation. Feedback

Fortunately, there is a middle ground provided in the library: the “default” tree components, which generally do what you need. So most of the time you can use these components, and only in special cases will you need to delve in and understand trees more deeply. Feedback

The following example uses the “default” tree components to display a tree in an applet. When you press the button, a new subtree is added under the currently selected node (if no node is selected, the root node is used): Feedback

 

The first class, Branch, is a tool to take an array of String and build a DefaultMutableTreeNode with the first String as the root and the rest of the Strings in the array as leaves. Then node( ) can be called to produce the root of this “branch.” Feedback

The Trees class contains a two-dimensional array of Strings, from which Branches can be made, and a static int i to count through this array. The DefaultMutableTreeNode objects hold the nodes, but the physical representation on screen is controlled by the JTree and its associated model, the DefaultTreeModel. Note that when the JTree is added to the applet, it is wrapped in a JScrollPane—this is all it takes to provide automatic scrolling. Feedback

The JTree is controlled through its model. When you make a change to the model, the model generates an event that causes the JTree to perform any necessary updates to the visible representation of the tree. In init( ), the model is captured by calling getModel( ). When the button is pressed, a new “branch” is created. Then the currently selected component is found (or the root is used if nothing is selected) and the model’s insertNodeInto( ) method does all the work of changing the tree and causing it to be updated. Feedback

An example like the preceding one may give you what you need in a tree. However, trees have the power to do just about anything you can imagine—everywhere you see the word “default” in the preceding example, you can substitute your own class to get different behavior. But beware: Almost all of these classes have a large interface, so you could spend a lot of time struggling to understand the intricacies of trees. Despite this, it’s a good design, and the alternatives are usually much worse. Feedback

Tables

Like trees, tables in Swing are vast and powerful. They are primarily intended to be the popular “grid” interface to databases via Java Database Connectivity (JDBC, discussed in Thinking in Enterprise Java), and thus they have a tremendous amount of flexibility, which you pay for in complexity. There’s easily enough here to allow the creation of a full-blown spreadsheet application and could probably justify an entire book. However, it is also possible to create a relatively simple JTable if you understand the basics. Feedback

The JTable controls how the data is displayed, but the TableModel controls the data itself. So to create a JTable, you’ll typically create a TableModel first. You can fully implement the TableModel interface, but it’s simpler to inherit from the helper class AbstractTableModel:

 

DataModel contains an array of data, but you could also get the data from some other source such as a database. The constructor adds a TableModelListener that prints the array every time the table is changed. The rest of the methods follow the Beans naming convention (using “get” and “set” methods, which will be described later in this chapter) and are used by JTable when it wants to present the information in DataModel. AbstractTableModel provides default methods for setValueAt( ) and isCellEditable( ) that prevent changes to the data, so if you want to be able to edit the data, you must override these methods. Feedback

Once you have a TableModel, you only need to hand it to the JTable constructor. All the details of displaying, editing, and updating will be taken care of for you. This example also puts the JTable in a JScrollPane. Feedback

Selecting Look & Feel

“Pluggable Look & Feel” allows your program to emulate the look and feel of various operating environments. You can even do all sorts of fancy things, like dynamically changing the look and feel while the program is executing. However, you generally just want to do one of two things: either select the “cross platform” look and feel (which is Swing’s “metal”), or select the look and feel for the system you are currently on so your Java program looks like it was created specifically for that system (this is almost certainly the best choice in most cases, to avoid confounding the user). The code to select either of these behaviors is quite simple, but you must execute it before you create any visual components, because the components will be made based on the current look and feel, and will not be changed just because you happen to change the look and feel midway during the program (that process is more complicated and uncommon, and is relegated to Swing-specific books). Feedback

Actually, if you want to use the cross-platform (“metal”) look and feel that is characteristic of Swing programs, you don’t have to do anything—it’s the default. But if you want instead to use the current operating environment’s look and feel, you just insert the following code, typically at the beginning of your main( ), but at least before any components are added:

try {

  UIManager.setLookAndFeel(UIManager.

    getSystemLookAndFeelClassName());

} catch(Exception e) {

  throw new RuntimeException(e);

}

You don’t need anything in the catch clause because the UIManager will default to the cross-platform look and feel if your attempts to set up any of the alternatives fail. However, during debugging the exception can be quite useful, so you may at least want see some results via the catch clause. Feedback

Here is a program that takes a command-line argument to select a look and feel, and shows how several different components look under the chosen look and feel:

You can see that one option is to explicitly specify a string for a look and feel, as seen with MotifLookAndFeel. However, that one and the default “metal” look and feel are the only ones that can legally be used on any platform; even though there are strings for Windows and Macintosh look and feels, those can only be used on their respective platforms (these are produced when you call getSystemLookAndFeelClassName( ) and you’re on that particular platform). Feedback

It is also possible to create a custom look and feel package, for example, if you are building a framework for a company that wants a distinctive appearance. This is a big job and is far beyond the scope of this book (in fact, you’ll discover it is beyond the scope of many dedicated Swing books!). Feedback

The clipboard

The JFC supports limited operations with the system clipboard (in the java.awt.datatransfer package). You can copy String objects to the clipboard as text, and you can paste text from the clipboard into String objects. Of course, the clipboard is designed to hold any type of data, but how this data is represented on the clipboard is up to the program doing the cutting and pasting. The Java clipboard API provides for extensibility through the concept of a “flavor.” When data comes off the clipboard, it has an associated set of flavors that it can be converted to (for example, a graph might be represented as a string of numbers or as an image), and you can see if that particular clipboard data supports the flavor you’re interested in. Feedback

The following program is a simple demonstration of cut, copy, and paste with String data in a JTextArea. One thing you’ll notice is that the keyboard sequences you normally use for cutting, copying, and pasting also work. But if you look at any JTextField or JTextArea in any other program, you’ll find that they also automatically support the clipboard key sequences. This example simply adds programmatic control of the clipboard, and you could use these techniques if you want to capture clipboard text into something other than a JTextComponent.

 

The creation and addition of the menu and JTextArea should by now seem a pedestrian activity. What’s different is the creation of the Clipboard field clipbd, which is done through the Toolkit. Feedback

All the action takes place in the listeners. The CopyL and CutL listeners are the same except for the last line of CutL, which erases the line that’s been copied. The special two lines are the creation of a StringSelection object from the String and the call to setContents( ) with this StringSelection. That’s all there is to putting a String on the clipboard. Feedback

In PasteL, data is pulled off the clipboard using getContents( ). What comes back is a fairly anonymous Transferable object, and you don’t really know what it contains. One way to find out is to call getTransferDataFlavors( ), which returns an array of DataFlavor objects indicating which flavors are supported by this particular object. You can also ask it directly with isDataFlavorSupported( ), passing in the flavor you’re interested in. Here, however, the bold approach is taken: getTransferData( ) is called, assuming that the contents supports the String flavor, and if it doesn’t, the problem is sorted out in the exception handler. Feedback

In the future you can expect more data flavors to be supported

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值