Monkeys at Keyboards: The Javanomicon
© Michael James Heron
Topic: Java Programming
Level: 2
Version: delta

A verbal contract isn't worth the paper it's written on.
Goldwyn's Law of Contracts

14 - More GUI Goodness

PreviousTable of ContentsNext
Forum


Chapter Objectives

By the end of this chapter, the reader will be able to:

  • apply a range of layout managers in developing a user interface.
  • incorporate menus into an application.


14.1

Introduction

So far, we've been ignoring one of the fundamental tools of Java interface design - the layout manager. Thus far it has been simpler to place components on the screen where we want them to go, but this simplicity comes at a cost and this absolute positioning system cannot be used as a long-term strategy for developing attractive Java GUIs.

In the rest of this chapter we're going to look at how we can use layout managers to develop flexible layouts, and how the initial extra complexity of a layout manager can be used to significantly reduce our workload in the long term.

14.2

The Problem with setBounds

We've been using setBounds quite happily for in programs for the past few chapters - when writing a simple piece of code, it's not immediately apparent what the problem may be. The problem can be seen when we resize the window of an application with even a remotely complex user-interface - our components don't resize along with the window.

This means that we have a clump of components in one section of the window, and then wide acres of unused blank space. If we're resizing a window to be smaller, then resizing can mean components no longer even appear. This is not a desirable situation.

When you consider real applications, when you resize a window, the interface usually resizes as well. This makes the whole experience seamless and useful, whereas our Java projects so far have been largely experiments in GUI design since they placed the components in a particular location, and that location didn't change even if the size of the window did.

What would be nice would be if we had some kind of facility for saying roughly where we want components to appear, and then Java would do the hard work of determining exactly where things should go in relation to the size of the window and the location of the other components. Luckily, Java provides us with exactly such a facility in the form of layout managers.

14.3

Java's Layout Manager Model

The layout manager framework can seem a little bizarre at times - it doesn't give an awful lot of control as to how an application will appear. It is also largely useless without the ability to separate an interface into separate regions - we'll look at how we can do that in this chapter also.

Using a layout manager requires a degree of extra planning, but it's planning at a higher level than we've used for our storyboards up until this point. We define where components should appear in relation to each other, rather than the lower level planning we need to define setBounds co-ordinates.

In chapter four, we briefly used one of Java's layout managers - BorderLayout, which is the default manager for Swing applications. The BorderLayout manager separates a Java interface into five distinct regions:

BorderLayout regions
Fig 14.1: BorderLayout regions

The limitation of the BorderLayout manager is that it only allows for five components to be placed on the screen - this may seem like a huge problem, but we'll look at why it isn't really such a big deal later in this chapter.

When using this particular layout manager, we indicate when we add a component to the content pane where it is going to appear according to the BorderLayout regions. Java then worries about the fine details. We don't even need to provide components for all five regions - once again, Java will work out the details for us:

import javax.swing.*; 
import java.awt.event.*;
import java.awt.*;


public class BorderLayoutExample extends JFrame {
JButton myButton;
JLabel myLabel;
JLabel myOtherLabel;

public BorderLayoutExample() {
myButton = new JButton ("Press Me!");
add (myButton, BorderLayout.CENTER);
myLabel = new JLabel ("This is an example of BorderLayout");
add (myLabel, BorderLayout.NORTH);
myLabel = new JLabel ("We don't need to worry about the presentation!");
add (myLabel, BorderLayout.SOUTH);
}


public static void main (String args[]) {
BorderLayoutExample mainWindow;
mainWindow = new BorderLayoutExample();
mainWindow.setSize (400, 400);
mainWindow.setTitle ("Border Layout Example");
mainWindow.setVisible (true);
}

}

If we compile and run the application above, we will get the following application layout displayed:

BorderLayout Regions
Fig 14.2: BorderLayout Regions

The fact that we don't need to worry about the bounds of each component is a major benefit, but the other benefit is that our application will now resize properly! Obviously layout managers offer a great degree of power in designing interfaces, provided we have the tools we need to deal with the often counter-intuitive layout managers templates provided by Java.

14.4

A Word on User Interface Design

We don't talk about user interface design in this book - it's a subject of such depth and complexity that anything other than the most cursory of introductions is beyond the scope of anything we do as Java developers.

Mostly in this book we are concerned with function over presentation. We looked at setBounds as a way to get components on the screen - we were rarely very concerned about how the end interface actually looked. Likewise in this chapter, we're looking at layout managers as a tool to provide an interface, but the interface itself is a secondary concern.

This greatly simplifies our job of learning object oriented programming - interface design is its own subject and deserves a fuller treatment than we can give it. It does however mean that we can easily slip into bad habits. Many user interfaces are badly designed, with little concern for the end-user (the person who will actually be using the software).

There's a reason why large companies like Microsoft and Apple spend millions of dollars every year on user interface research - usability is one of the real selling points of things like Windows XP and Microsoft Office. Operating systems like Linux will never take over the desktop market until they have as much effort spent on their interface as they do on their internals.

As software developers, we often forget that we're not writing software for ourselves in many cases, we're writing it for end users. This is a blindness that we will refer to as programmer syndrome. In the majority of cases, end users are not programmers. They are civil servants, students, accountants, nurses, casual web browsers - people who do not have the time or the inclination to learn about programming in order to use an application.

The following examples of Programmer Syndrome are all taken from an excellent website called The Interface Hall of Shame. The URL for this may be found in the further reading section of the chapter.

14.5

Examples of Programmer Syndrome

As programmers, we are often unhelpful, and assume that unusual situations simply will not occur. We often provide error messages that are unhelpful and give no indication as to how a problem can be solved. This is a case of addressing the symptoms and not the underlying cause.

Unhelpful Error Message
Fig 14.3: Unhelpful Error Message

As programmers, we often make use of programming jargon when we should attempt to explain clearly in simple English. This particular example, while amusing (well...) to someone who knows about SMTP protocols, will give absolutely no hint to an end-user as to what has happened - and more importantly, what they can do to fix the problem.

Jargon
Fig 14.4: Jargon

As programmers, we often confuse good intentions with good practice. Upon learning that it is a good idea to provide a user with a dialog box that lets them confirm potentially irreversible decisions, we can be careless or indifferent and end up being less helpful than we'd like to think we are.

Choiceless Choices
Fig 14.5: Choiceless Choices

We often make use of internal error codes which would mean something to a fellow programmer (perhaps), but are nothing more than random gobbledegook to the majority of computer users.

Internal Error Codes
Fig 14.6: Internal Error Codes

Or we provide error messages that are clearly only there to make sure a program doesn't crash, with absolutely no regard for the user. We will see many examples of this in this very book when we look at exception handling.

Missing text
Fig 14.7: Missing text

These are all common mistakes, and they are not limited to people just learning how to write programs. They can be seen many, many times in many, many applications. They are a symptom of thinking like a computer programmer and not thinking like and end-user.

This is often unavoidable - after all, we are computer programmers!

However, as programmers we often leave user interface considerations to the last minute. With Java, we have no excuse for this - Java is a language with very powerful user interface design support built into its fundamental class libraries.

With layout managers, we must spend a little extra time when planning an interface, but what we end up with is usually a much more effective application that provides easy access to all our functionality - in the end, that's a very desirable objective and one that will allow us, in the long term, to develop much stronger applications.

Java tip

Outside of this book, you will be coding for real people (even if it's just yourself). Bear that in mind when developing error messages, or user feedback. Not everyone will Get You as easily as you do.


14.6

Panels

Before we look at layout managers again, we should look at the idea of panels. Without the use of panels and other such devices, it is very difficult to develop anything approaching a useful interface.

Essentially, panels are just components that can hold other components. The Container object we get from the getContentPane call is an example of another component that holds other components. getContentPane returns the main container (which is an object of type JRootPane) for the whole applet or application, but we can create our own localised containers that let us treat groups of components as a single 'clump'.

The panel class we use for Swing is called JPanel, and we create it in the same way we do all objects:

JPanel myPanel = new JPanel(); 

And that's all we need to create our panel. A panel can have its own layout manager, and it has an add method, like that of our content pane, that lets us place things where we would like them to go.

Panels are not automatically added to the content pane of a Java program, so we must manually add them - we do this the same way we would add a JTextField, or a JButton, or any other component - the fact that it can contain other components is immaterial.

/*
create a new JPanel
*/

JPanel myPanel = new JPanel();
/*
Create a new button.
*/

JButton myButton = new JButton ("Bing!");
/*
Add the button to the panel
*/

myPanel.add (myButton);
/*
Add the panel to the content pane
*/

add (myPanel, BorderLayout.NORTH);

This is a powerful tool, as it lets us treat whole groups of components as a single, discreet unit for placement. Suddenly the five component limitation of the BorderLayout manager doesn't seem like such a big deal when all five of these components can be panels (and each of those panels can contain other panels!).

myPanel
Fig 14.8: myPanel
myOtherPanel
Fig 14.9: myOtherPanel
Content Pane
Fig 14.10: Content Pane


public void init() {
add (myPanel, BorderLayout.SOUTH);
add (myOtherPanel, BorderLayout.WEST);
}

Java tip

Use the BorderLayout manager as a base for other layouts through the use of JPanels.


14.7

Layout Managers Again

We've already looked at the BorderLayout manager, but we haven't yet discussed how we can actually tell Java that that is the layout manager we want to use. By default, Swing applications use this manager, but this is not the case for AWT applications which use a different layout manager called FlowLayout.

Layout managers are classes, like most things in Java, so we simply need to create an instance of the class and then pass it as a parameter to setLayout (like we did with setLayout (null)):

BorderLayout myLayout = new BorderLayout(); 
setLayout (myLayout);

Since it is only very rarely that we are going to want to do anything with the layout manager once it has been created, we can combine this into a single line of code:

setLayout (new BorderLayout()); 

Some layout managers are a little more complicated and require parameters to be passed to their constructor methods. We'll talk about these in a moment or two.

We can specify any of the provided layout managers for our panels or content pane. If so inclined, we can even write our own to meet very specialised needs. The main pre-defined Java layout managers are:

  • BorderLayout
  • FlowLayour
  • CardLayout
  • GridBadLayout
  • GridLayout
  • BoxLayout

As mentioned above, each panel can have its own layout manager, so you can mix and match managers to meet your requirements. Planning this correctly is the key to useable interfaces in Java.

14.8

The FlowLayout Manager

The FlowLayout manager is the default manager for AWT applications, and simply places the components from left to right, moving onto a new line when it reaches the right hand size of your content pane. Effectively it works like a typewriter, fitting what it can on one line before moving onto the next, and so on.

It places the components in the order you provide them using add, so the order in which you call the method is significant.

The FlowLayout manager takes no parameters, so you can make use of it using the following syntax:

setLayout (new FlowLayout()); 

The end layout is arranged in this fashion:

FlowLayout Manager
Fig 14.11: FlowLayout Manager

The FlowLayout manager is perhaps the simplest and least useful, but it is still handy for placing multiple instances of particular components. A row of buttons, or a series of checkboxes, and so on. Consider the following code:

myPanel = new JPanel(); 
myPanel.setLayout (new FlowLayout());
myButton1 = new JButton ("One");
myButton2 = new JButton ("Two");
myButton3 = new JButton ("Three");
myPanel.add (myButton1);
myPanel.add (myButton2);
myPanel.add (myButton3);

The layout created by the code above is as follows:

FlowLayout Screenshot
Fig 14.12: FlowLayout Screenshot

As can be seen from the example code, we don't need to provide a second parameter to the add method as we do for BorderLayout - this is because we have no choice where things go beyond the order in which we call the add method.

14.9

The BoxLayout Manager

The BoxLayout manager works similarly to the FlowLayout manager in that it also arranges things according to the order in which they are added, but it also has an orientation which means we can arrange things into either rows or columns.

The BoxLayout manager takes two parameters when it is created - one is the panel or content pane to which it belongs, and the second is the orientation.

The orientation is expressed as a constant value in the BoxLayout class - we spoke about this idea when we looked at JOptionPane's showInputDialog method.

setLayout (new BoxLayout (myPanel, BoxLayout.X_AXIS); 
setLayout (new BoxLayout (myPanel, BoxLayout.Y_AXIS);

The first of these will arrange components into a row, and the second will arrange the components into a column. The buttons above, using a BoxLayout manager:

BoxLayout Screenshot
Fig 14.13: BoxLayout Screenshot
Java tip

The BoxLayout manager does not grab as much of the screen space as it can - it often looks quite puny in comparison to other greedier layout managers (for example, look at how ragged the buttons are on the Y_AXIS above). See the Calculator Revisited case study for an example and solution to this problem.


14.10

The GridLayout Manager

The GridLayout manager allows the developer to arrange a container into equally proportioned rows and columns - you can decide on how many of each. The manager then places your components into these segments in an order equivalent to the order in which you add them.

The GridLayout manager will automatically resize components so that they are all of an equal size. This may cause your applications to look strange if you group together too many different kinds of components in a single container.

setLayout (new GridLayout (2, 2)); 

You pass in the number of rows and columns as parameters to the constructor - the example above creates a GridLayout manager with two rows and two columns.

If you don't provide enough components to fill the grid, the remaining segments will be left blank:

GridLayout Screenshot 1
Fig 14.14: GridLayout Screenshot 1

If you add more components than will fit into the grid you specified, it will automatically resize itself to accommodate the extra components:

GridLayout Screenshot 2
Fig 14.15: GridLayout Screenshot 2

14.11

CardLayout Manager

The CardLayout manager is somewhat specialised, and has recently been made more or less obsolete by the JTabbedPane class. There are still a number of situations in which it may be quite useful - for example in constructing questionnaire applications or wizard-style dialogs.

The CardLayout manager arranges separate components into a 'pack of cards' within which only the topmost panel is visible at any one time. It is a little bit more complex to set up than the other layout managers we have discussed so far in this chapter, so we'll look at another example.

In this example, we're going to have three panels arranged in a deck - the top one is the only one of these that gets displayed. The CardLayout manager has a method called next and another called previous, and these two methods allow us to navigate through the 'deck' - contrary to our experience with the other layout managers, we may very well want to do something with these methods outside of the configuration of a panel, and so we need to create an object for the layout manager that we can later refer to:

CardLayout myCards = new CardLayout(); 

We'll create a panel called cards that is going to use this manager:

JPanel cards = new JPanel(); 
cards.setLayout (myCards);

We're also going to create three labels, each on a separate panel, and two buttons, also on a separate panel. The three panels containing labels will be the cards of our deck, and we add them to the panel that is using the CardLayout manager. We need to pass a second parameter to the add call, and this is a textual description of the panel:

cards.add (panel1, "Panel 1"); 

Then we add the buttons to the buttons panel:

buttons.add (next); 
buttons.add (prev);

Then we add these two panels to the content pane:

add (cards, BorderLayout.CENTER); 
add (buttons, BorderLayout.SOUTH);

Execute this, and we get the following display:

CardLayout 1
Fig 14.16: CardLayout 1

Only one of our panels is visible (the first one we added), and we haven't added any event handling code to the buttons. This is where our CardLayout object comes in handy - we're going to add the code we need to move to the next and previous cards using this.

We need to call the method next on the card layout object, and pass as a parameter the panel that has been setup with that layout manager:

myCards.next (cards); 

And the same for previous:

myCards.previous (cards); 

Applying these methods to the example above gives us the following code for actionPerformed:


public void actionPerformed (ActionEvent e) {
if (e.getSource() == next) {
myCards.next (cards);
}

if (e.getSource() == prev) {
myCards.previous (cards);
}

}

And now when we run the application and press 'next' we go on to the next panel:

CardLayout 2
Fig 14.17: CardLayout 2

As you can see, this is a very specialised layout manager which is unsuitable for many situations. You may however find a use for it when developing particular kinds of applications - it is included in this book for completeness and to give you an idea of some of the things Java provides even when they are not immediately useful.

When making use of the CardLayout manager, take a minute and consider if the JTabbedPane component (covered later) may not meet your needs better.

14.12

The GridBagLayoutManager

The GridBagLayout manager is the most powerful of the predefined layout managers and, unsurprisingly, also the most complicated. The GridBagLayout manager breaks a container into a regular grid of cells - components placed using this layout manager can occupy one or more cells. The set of cells occupied by a particular component is called its display area.

Not all of the rows in a GridBagLayout need be the same height, and likewise not all the columns will be of the same width - the developer has precise control on exactly how the interface is to be laid out.

The GridBagLayout manager works through an interaction of two objects. One of the container that has the layout set, and the other is an instance of a class called GridBagConstraints, which handles all the configuration details for adding a particular component.

setLayout (new GridBagLayout()); 
GridBagConstraints myConstraints = new GridBagConstraints();

When adding multiple components to a grid bag, we can reuse the same GridBagConstraints object for each - the details of a particular component's configuration are used once when a component is added, and then the GridBagConstraints object is never referenced to again.

However, it is important to remember that the state of your constraints object is not changed - if you wish to reset the constraints object back to some default value, you'll need to do it yourself.

When adding components to a container that has a GridBagLayout, we pass in two parameters - one is the component, as usual. The second is our GridBagConstraints object which contains the configuration details.

add (myButton, myConstraints); 

We can indicate where we want a component to appear in our grid using our GridBagConstraints object - this contains two attributes of use for this task. One is gridx and the other is gridy. We can change these to indicate which cell we want to reference to:

myConstraints.gridx = 0; 
myConstraints.gridy = 0;

This has the effect of pointing our constraints object at cell 0,0 - the one at the top left hand of the screen. The GridBagLayout will automatically resize as we indicate new cells - we don't need to declare a size in advance.

This is all we need to do to specify where a component is going to go, but this has a problem - by default, all components get equal priority when sizing the interface and this unattractive displays are the norm without further specification of layout details..

GridBagConstraints contains another two variables called weightx and weighty - these indicate the 'importance' of a particular component when determining the resize behaviour of a particular container. Conventionally, we use values between 0 and 1 to express how important a particular component is - the larger the value we assign, the more important the component is, and the higher a priority it should have when assigning sizes.

This is a very difficult thing to get right - setting these weights correctly is a skill that comes only with large amounts of practice. Don't worry if you can't get your interface looking correct to begin with - just play around with different numbers and see what effect these values have on the way your interface is presented.

Next, we'll look at how we can 'span' components across multiple cells. We do this using the gridheight and gridwidth variables of our constraints:

myConstraints.gridwidth = 2; 

The GridBagLayout manager attempts to place components according to their preferred size, so if your component is already quite happy in its display area, then it won't look any bigger even if you indicate it should span multiple cells. You can solve this by changing the fill property of the constraints object to an appropriate constant value as set in GridBagConstraints:

myConstraints.fill = GridBagConstraints.HORIZONTAL; 
myConstraints.fill = GridBagConstraints.VERTICAL;
myConstraints.fill = GridBagConstraints.BOTH;

This indicates that the component should completely fill its display area in the requested axis.

There is much more that can be done with the GridBagLayout - the interested student is referred to the Java documentation where other properties of the GridBagConstraints object are detailed.

GridBagLayout Manager
Fig 14.18: GridBagLayout Manager

As can be seen, it can be very time consuming to develop an interface using GridBagLayout, and there are a number of problems when you do. The main one is that if you later change your mind and want to insert a new component, it can be very difficult to update your constraints accordingly - gridx and gridy values will change, as will weightings and spanning values. In the vast majority of cases, using JPanels within simpler layout managers will allow you to implement all but the most pernickety of user interfaces without requiring GridBagLayout to be used. If you don't have a particular need to use this layout manager, you are more likely to have success with a combination of other managers within separate JPanels.

14.13

Another Type of Container

We've looked at the simple Container and JPanel classes, and how these can be used to develop flexible user interfaces. There is another container class that we will look at in this chapter. It is not useful in as quite so many situations as the other two we have discussed, but it has a certain charm when applied to certain kinds of situations.

Consider the toolbar at the top of Microsoft Word. You can click on it and drag it to another part of the screen, or leave it floating in the middle of your monitor if that so pleases you - this is known as a dockable toolbar, and this allows a user to have considerable control in how they interact with your application.

Java provides us with just such a component in the form of the JToolBar control. It is created in the same way as a JPanel, set up with a layout manager in the same way, and added to an application in the same way. We don't need to know anything more than the name of the class to make use of this component.

When we run an application using JToolBar, we get an interface much like we'd expect, but it has a little addition at the side that indicates it is a dockable component:

Dockable Containers
Fig 14.19: Dockable Containers

If we click on the dockable tag, we can drag the toolbar to wherever we may want it to appear on our desktop. Modern user interfaces make use of this kind of component to allow the user to configure their application experience - after all, who could possibly know more about the way a user finds an interface to be effective than the user him/herself?

The JToolBar component will resize itself to fit the dimensions afforded to it by the user. This is all handled seamlessly by Java and requires very little work on the part of the developer other than allowing for it to be present in the first place:

Moved JToolBar
Fig 14.20: Moved JToolBar

As far as components go, the JtoolBar is perhaps one of the coolest - not the most obvious choice for most development interfaces, but still something that finds a worthy place in our toolbox.

14.14

The JTabbedPane Class

As mentioned above, the CardLayout manager has largely been superseded by the JTabbedPane class - this is a special kind of panel that allows for a tabbed dialog to be presented to the user. Tabbed dialogs are an excellent way of providing complex functionality in a clear and well-defined manner that does not confuse the user with an over-abundance of options presented without context.

A tabbed dialog is made up of a number of tabs - these appear at the top of the component, just like the tabs of a folder or in a filing cabinet. Clicking on a tab brings up the contents for that particular tab.

Creating a JTabbedPane is simple - first we create all the components and panels that we want, and then we create a JTabbedPane object. We then use the addPane method to add a new tab to the pane. The first parameter for the method is the string of text that is to appear on the tab. The second is the component that should be added to that tab.

As with most containers, this doesn't have to be a simple component. It can quite happily accept a JPanel, which allows for a tab to be setup with virtually infinite complexity should the developer desire.

For example:

import javax.swing.*; 
import java.awt.*;


public class JTabbedPaneExample extends JFrame {
JTabbedPane myPane;
JPanel stuff, things;
JButton myButton;
JTextField myTextField;
JTextArea myTextArea;
JScrollPane myScrollPane;

public JTabbedPaneExample() {
stuff = new JPanel();
things = new JPanel();
myTextField = new JTextField (10);
stuff.add (myTextField);
myButton = new JButton ("Press me, touch me, caress my font.");
stuff.add (myButton);
myTextArea = new JTextArea (10, 10);
myScrollPane = new JScrollPane (myTextArea);
things.add (myScrollPane);
myPane = new JTabbedPane();
myPane.addTab ("Stuff", stuff);
myPane.addTab ("Things", things);
add (myPane, BorderLayout.CENTER);
}


public static void main (String args[]) {
JTabbedPaneExample mainWindow = new JTabbedPaneExample();
mainWindow.setSize (300, 300);
mainWindow.setVisible (true);
}

}

When we compile and run this application, we can gain access to each of the panels by clicking on the tab that it belongs to:

The JTabbedPane
Fig 14.21: The JTabbedPane

Tabbed dialogs allow for vast amounts of complexity to be presented in context, and for what would otherwise be very complicated and intimidating choices of options to be broken up into more easily digestible chunks. Many of the preferences or options dialogs of modern software applications are presented using this kind of component.

Java tip

The JTabbedPane component provides most of the functionality of the CardLayout manager in a simpler, neater package. Consider if this component could be used in place of any CardLayout managers you may be considering.


14.15

Waiter, Menu please!

The final thing we will talk about in this chapter is Java's menu system. Most applications have menus, even if it is only to provide an 'about' option, and it makes sense that we should be able to add them to our Java applications.

Java menus work in the same way as Java interfaces in general in that we build up the contents of containers before adding them to our applications. There are three classes in particular we need to use:

  • JMenuBar
  • JMenu
  • JMenuItem

We use these three to create a menu system for our application. The collection of a number of menus for an application is the JMenuBar. The individual menus are created from a class called JMenu, and each item on a menu is a JMenuItem:

Interaction of Menu Classes
Fig 14.22: Interaction of Menu Classes

We need one JMenuBar for an application. We need one or more instance of the JMenu class to go on that menu bar, and we need one or more objects of type JMenuItem for each JMenu. To create a JMenuBar that had a file menu that contained options for new, open and save, we would first create a JMenuBar in the constructor of our Java application or init method of our Java application:

JMenuBar myMenuBar = new JMenuBar(); 

Then we need to create a JMenu called 'file' - we pass in the string we wish to appear as the menu title as a parameter to the constructor:

JMenu fileMenu = new JMenu ("File"); 

And then we add a JMenuItem for each of the options on the file menu:

JMenuItem newOption = new JMenuItem ("New"); 
JMenuItem openOption = new JMenuItem ("Open");
JMenuItem saveOption = new JMenuItem ("Save");

Next, we add each of the JMenuItem objects to the appropriate JMenu, and each of the JMenu objects to the JMenuBar, using the add methods of each:

fileMenu.add (newOption); 
fileMenu.add (openOption);
fileMenu.add (saveOption);
myMenuBar.add (fileMenu);

Finally, we need to tell Java to use our menu:

setJMenuBar (myMenuBar); 

And then voila:

Screenshot of Java Menus
Fig 14.23: Screenshot of Java Menus

We can select each of these menu items, click on them and so forth - but nothing will happen. We must also register each menu item with an ActionListener if we want something to actually happen when they are clicked. This is done in the traditional way, just like with objects of type JButton:

newOption.addActionListener (this); 

And the code in the actionPerformed method should be familiar:


public void actionPerformed (ActionEvent e) {
if (e.getSource() == newOption) {
JOptionPane.showMessageDialog (null, "Hey! Stop clicking my menu items!");
}

}

We can also make use of the addSeparator method of a JMenu object to add a line that separates out contextually related chunks of functionality.

So, now we've seen the flexibility we have at our fingertips through the use of menus in Java - PHENOMENAL COSMIC POWER!

Java tip

Use menus to provide logical access to elements of functionality that don't belong on the main interface.


14.16

Conclusion

We've covered quite a lot of ground in this chapter - the most important things to take away with you are the use of objects of the JPanel class for acting as containers for components, and the use of the standard layout managers to simplify (in the long run) your task of setting up an interface. You should also by now have a firm grounding in the difference between an applet and application, and the kind of circumstances to which each are best suited.

For most GUI designs, you will never have to use a CardLayout or GridBagLayout manager - these are very specialised tools that will only be of use for very particular kinds of applications. Undoubtedly you will know the situations in which they are appropriate tools if and when you encounter them. For the vast majority of Java applications, you can develop interfaces of virtually any level of complexity by combining instances of JPanel with the basic layout managers: BorderLayout, FlowLayout, GridLayout and BoxLayout.

14.17

Reader Projects

The Imperial

You have been approached by a local cinema manager who has heard great tales of your programming talents. He has offered Large Cash Sums in Unmarked Bills for you to develop a prototype application suitable for deployment on the desktop of his staff in the foyer of his movie theatre (called The Imperial).

The intention of the application is to record user feedback regarding the movies they have just viewed. This will take the form of a simple text editor with the usual tools provided via a menu. There should be menu items for loading, saving, printing and closing documents. There should be menu items for copy, cut and paste. There should be an 'about' menu option that brings up details about who wrote the application and what it is for.

At the moment, the manager is not particularly interested in the functionality... he just wants it to look good and be functional. He does care that the application should behave like a normal application however... when he resizes the window, he wants the application to resize appropriate. Likewise, he wants clicking on the window icons to perform the expected tasks.

Most of the functionality will wait for the approval of the interface. There are certain functions that he wants the first prototype to be able to perform:

  • He wants to have one text area for the name of the movie, and another for the customer comments the movie receives.
  • He wants to be able to clear both text areas by the press of a button (or by clicking on a menu)
  • He wants to see a message box that appears whenever a menu item is selected, indicating what will happen in the next version of the software.
  • He wants all message boxes to display some suitable title and icon.
  • He wants the 'about' menu option of the application to display some relevant information about the author and the name of the cinema.
  • He wants all components to have useful tool-tip text.
  • There should be buttons that allow the user to perform specific actions on the main editing area. You do not need to code the functionality, but you should have message boxes that indicate what should happen when the button is pressed. He wants a button on the main screen for each of the following:
    • Inserting the current date into the main editing window.
    • Changing the font of the main editing window.
    • Spellchecking the main editing window.

Further Reading

The following table details further reading on the topic in this chapter, and also any external resources that you may find useful.

ResourceDescription
Example Programs from this chapterThis is a zip file of all the programs shown in this chapter.
The Interface Hall Of ShameThe Interface Hall of Shame is refrenced above - well worth a read, as it's very funny.

PreviousTable of ContentsNext

© 2004-2006 Michael James Heron