Creating a menu bar
A menu bar is constructed separately from the rest of the graphical layouts and components and once defined is attached to the frame.
There are three classes used in combination in building a menu-bar:
JMenuBar: an object of this class defines the menu-bar as a whole and is the component that will be attached to the frame. It needs to contain one or moreJMenuobjectsJMenu: an object of this class defines a separate menu category, such as File, Edit, View, Help, etc. EachJMenuobject needs to contain one or moreJMenuItemobjectsJMenuItem: an object of this class defines each individual menu option, such as Save, About, Exit, etc.
You will now develop a simple menu-bar for the application, structured as follows:
File
- Feeding Time….....(will display a simple dialog box)
- ---------------------(will display a separator line)
- Exit…---------------(will prompt for confirmation)
Help
- About Virtual Zoo…(will display a simple dialog box)
In sub-package virtualzoo.ui create a new class ZooMenuBar that extends JMenuBar with instance variables for the owning frame, the menu items, and a constructor to build it:
package virtualzoo.ui;
import javax.swing.*;
public class ZooMenuBar extends JMenuBar {
private AdministratorFrame owner;
private JMenu fileMenu, helpMenu;
private JMenuItem fileFeedingTime, fileExit;
private JMenuItem helpAbout;
ZooMenuBar(AdministratorFrame owner) {
this.owner = owner;
buildFileMenu();
add(fileMenu);
buildHelpMenu();
add(helpMenu);
}
private void buildFileMenu() {
fileMenu = new JMenu("File");
fileFeedingTime = new JMenuItem("Feeding Time...");
fileMenu.add(fileFeedingTime);
fileMenu.addSeparator();
fileExit = new JMenuItem("Exit...");
fileMenu.add(fileExit);
}
private void buildHelpMenu() {
helpMenu = new JMenu("Help");
helpAbout = new JMenuItem("About Virtual Zoo...");
helpMenu.add(helpAbout);
}
}
- The constructor requires a reference to the
JFrameobject that will ultimately contain it. Although no use of is made of this as yet you will see how it comes into play as the options are coded later - The constructor then invokes helper methods to instantiate the
JMenuandJMenuItemobjects - Note how the individual menu items are added to the appropriate menu object, and then the menu objects are added to the
ZooMenuBar
To see the menu bar you need to attach it to the frame, so add the following line inside the AdministratorFrame constructor, just before the call to pack():
// Set the menu bar setJMenuBar(new ZooMenuBar(this));
If you run the application, you should see the menu bar appear just under the title bar, although none of the options do anything at present:
Coding the Help | About Virtual Zoo... Option
You now need to listen for the menu items being selected and take the appropriate action. The simpler item is Help | About Virtual Zoo… which just shows a dialog message. Inside ZooMenuBar define an inner class HelpAboutListener that implements ActionListener (you need to import java.awt.event):
private class HelpAboutListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog
(owner,
"Sample application for the course " +
"Java Programming Step-by-Step.",
"About Virtual Zoo",
JOptionPane.INFORMATION_MESSAGE);
}
}
- You will see that use was made of the owner instance variable so that the dialog attaches to the owning JFrame
You now need to attach the listener to the appropriate object, so after you have instantiated helpAbout (in the buildHelpMenu() method), add the following line:
helpAbout.addActionListener(new HelpAboutListener());
You should now find that the Help | About VirtualZoo... menu option causes the dialog to be displayed.
Coding the File | Exit... Option
The listener to handle File | Exit… is similar but this time uses the showConfirmDialog() static method of JOptionPane that prompts for a response and returns it as an int:
private class FileExitListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// Prompt for confirmation
int response = JOptionPane.showConfirmDialog
(owner,
"Are you sure you want to exit?",
"Exit Virtual Zoo",
JOptionPane.YES_NO_OPTION);
// See what response is
if (response == JOptionPane.YES_OPTION) {
owner.dispose();
}
}
}
You now need to attach the listener to the fileExit object in the buildFileMenu() method:
fileExit.addActionListener(new FileExitListener());
The File -> Exit… menu option should now prompt for confirmation and exit if Yes is chosen.
There is, though, an inconsistency in that the user could still click the window's close button without it prompting for confirmation, due to the following statement in AdministratorFrame:
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
To gain full control you first need to tell Java not to do anything automatically, so change the above to the following:
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
You should now write a method inside AdministratorFrame called confirmClose() which prompts for confirmation, in a similar manner to the exit listener you wrote earlier:
void confirmClose() {
// Prompt for confirmation
int response = JOptionPane.showConfirmDialog(this,
"Are you sure you want to exit?",
"Exit Virtual Zoo",
JOptionPane.YES_NO_OPTION);
// See what response is
if (response == JOptionPane.YES_OPTION) {
dispose();
}
}
Also inside AdministratorFrame define an inner class called ExitListener which extends the Java supplied WindowAdapter class (you will need to import java.awt.event):
private class ExitListener extends WindowAdapter {
@Override
public void windowClosing(WindowEvent e) {
confirmClose();
}
}
- The
WindowAdapterclass defines several empty event methods concerned with events that can happen with a window, and you just need to override the methods applicable. Above, you have overriddenwindowClosing(), being the method that gets called when a window is about to close. All your overridden method does in invoke theconfirmClose()method you previously defined
Because you have told the frame to do nothing when the close button is pressed you need to add a window listener to it, so insert this statement after the setDefaultCloseOperation() call in the constructor:
addWindowListener(new ExitListener());
Test the application to ensure that if you try and close the window using the window's close button you will be prompted for confirmation first.
Because you want to avoid code duplication you should now refactor the code in ZooMenuBar to use the frame's closing mechanism:
private class FileExitListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
owner.confirmClose();
}
}
Creating the File | Feeding Time... Option
For the File | Feeding Time… option you invoke the feedingTime() method of ZooAdministrator. At the moment that method sends its results to the Output window, which is only meant for the programmer's benefit. You will therefore modify the last part of the method to return a Collection of String objects instead. You can then obtain the collection from the user interface and display the messages in a list.
Change the feedingTime() method as follows:
public Collection<String> feedingTime() {
// Collect all the animals
Collection<Animal> animals = new HashSet<Animal>();
for (Pen pen : pens) {
animals.addAll(pen.getAnimals());
}
Collection<Animal> sortedAnimals =
new TreeSet<Animal>(new Animal.SortByAgeName());
sortedAnimals.addAll(animals);
// Feed them one at a time
Collection<String> messages = new ArrayList<String>();
for (Animal anAnimal : sortedAnimals) {
messages.add(anAnimal.getName() +
" is eating a " + anAnimal.favouriteFood());
}
return messages;
}
With that in place you can create a class in virtualzoo.ui that extends JDialog called FeedingTimeDialog:
package virtualzoo.ui;
import java.awt.*;
import java.util.*;
import javax.swing.*;
import virtualzoo.core.*;
public class FeedingTimeDialog extends JDialog {
FeedingTimeDialog(AdministratorFrame owner) {
super(owner, "Feeding Time", true);
setLayout(new BorderLayout());
ZooAdministrator admin = ZooAdministrator.getInstance();
Collection<String> messages = admin.feedingTime();
JList list = new JList(messages.toArray());
add(new JScrollPane(list));
setLocationRelativeTo(owner);
pack();
}
}
The call to super() passes three arguments:
- The owning frame
- The title for the dialog
truemeans that the dialog will be modal
The retrieved messages are converted to an array for passing into a JList.
You can now create a new inner class within ZooMenuBar to show the dialog:
private class FileFeedingTimeListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JDialog d = new FeedingTimeDialog(owner);
d.setVisible(true);
}
}
You now only need to attach the listener to the fileFeedingTime object in buildFileMenu():
fileFeedingTime.addActionListener(new FileFeedingTimeListener());
Verify that the File | Feeding Time... menu option results in a dialog being displayed, as follows:
With the menu bar in place we are ready to define a corresponding toolbar.
Comments