Main Page

Previous Next

Adding a Toolbar

A toolbar is a bar, usually positioned below the menu bar, which contains a row of buttons that typically provides a more direct route to menu options. We could add a toolbar to the Sketcher program for the menu items that are likely to be most popular. Just so that you know where we are heading, the kind of toolbar we will end up with ultimately is shown below.

The four buttons in the first group are for the most used functions in the file menu. The other two groups of four buttons select the element type and element color respectively. So how are we going to put this toolbar together?

Adding the toolbar itself couldn't be easier. A toolbar is a Swing component defined by the JToolBar class. You can add a member to the SketchFrame class for a toolbar by adding the following field to the class definition:

private JToolBar toolBar = new JToolBar();      // Window toolbar

You can position this following the declaration of the menuBar member. It simply creates a JToolBar object as a member of the class. To add it to the frame window, you need to add the following statement after the existing code in the SketchFrame constructor:

getContentPane().add(toolBar, BorderLayout.NORTH);

This adds the (empty) toolbar to the top of the content pane for the frame window. The content pane has the BorderLayout manager as the default, which is very convenient. A JToolBar object should be added to a Container using the BorderLayout manager since it is normally positioned at one of the four sides of a component. An empty toolbar is not much use though, so let's see how to add buttons.

Adding Buttons to a Toolbar

The JToolBar class inherits the add() methods from the Container class, so you could create JButton objects and add them to the toolbar. However, since a toolbar almost always has buttons corresponding to menu functions, a much better way is to use the add() method defined in the JToolBar class to add an Action object to the toolbar. We can use this to add any of the Action objects that we created for our menus, and have the toolbar button events taken care of without any further work.

For example, we could add a button for the openAction object corresponding to the Open menu item in the File menu with the statement:

toolBar.add(openAction);          // Add a toolbar button

That's all you need basically. The add() method will create a JButton object based on the Action object passed as the argument. A reference to the JButton object is returned in case you want to store it to manipulate it in some way – adding a border for instance. Let's see how that looks.

Try It Out – Adding a Toolbar Button

Assuming you have added the declaration for the toolBar object to the SketchFrame class, you just need to add a couple of statements preceding the last statement in the constructor to add the toolbar to the content pane:

public SketchFrame(String title) {
  // Constructor code as before...

  JButton button = toolBar.add(openAction);                  // Add toolbar button
  button.setBorder(BorderFactory.createRaisedBevelBorder()); // Add button border
  getContentPane().add(toolBar, BorderLayout.NORTH);         // Add the toolbar

If you recompile Sketcher and run it, the window should look like that shown below.

How It Works

There's not much to say about this. The add() method for the toolBar object created a button based on the openAction object that we passed as an argument. We store the reference returned in button so that we can add a border to the button.

A feature that comes for free with a JToolBar object is that it is automatically dockable, and can float as an independent window. You can drag the toolbar using the mouse by clicking the cursor in the gray area to the left of the button, and it will turn into a free-floating window.

You can also drag the toolbar to any of the four sides of the content pane to dock it again. You must drag with the cursor in the gray area of the toolbar to dock it. Dragging with the cursor in the toolbar title area just moves the window. It's not always convenient to have the toolbar floating or docked against borders other than its normal position. You can inhibit the ability to drag the toolbar around by calling the setFloatable() method for the JToolBar object, passing a boolean argument of false. Let's do this for Sketcher, so add the following statement to the SketchFrame constructor before the statement that adds the toolbar to the content pane:

  toolBar.setFloatable(false);    // Inhibit toolbar floating
  getContentPane().add(toolBar, BorderLayout.NORTH);

A true argument to the method will allow the toolbar to float, so you can switch this on and off in your program as you wish. You can also test whether the toolbar can float by calling the isFloatable() method for the JToolBar object. This will return true if the toolbar is floatable, and false otherwise. If you recompile SketchFrame and run Sketcher again you will see that the gray bit at the left hand end of the toolbar is no longer there, and you cannot drag the toolbar around.

The button that has been created uses the name from the Action object as its label by default. We really want toolbar buttons with icons, so that's got to be the next step.

Adding Icons

A reference to an icon is generally stored in a variable of type Icon. Icon is an interface that declares methods to obtain the height and width of an icon in pixels – these are the getHeight()and getWidth() methods respectively, and to paint the icon image on a component – the paint()method. One class that implements the Icon interface is ImageIcon and it is this class that you use to create an icon object in your program from a file containing the icon image. The class provides several constructors that create an ImageIcon object and the one we will use accepts a String argument that specifies the file where the icon image is to be found. The String object can be just a file name, in which case the file should be in the current directory – the one that contains the .class files for the application or applet. You can also supply a string that specifies the path and file name where the file containing the image is to be found. The ImageIcon constructors accept icon files in PNG (Portable Network Graphics format, which have .png extensions), GIF (Graphics Interchange Format, or .gif files), or JPEG (Joint Photographic Experts Group format, .jpg files) formats, but we will assume GIF files in our code.

We will put the icons for Sketcher in a subdirectory of the Sketcher directory called Images, so create a subdirectory to your Sketcher application directory with this name. To create an icon for the openAction object from an image in a file open.gif in the Images directory, we could write:

openAction.putValue(Action.SMALL_ICON, new ImageIcon ("Images/open.gif"));

This stores the ImageIcon object in our Action object associated with the SMALL_ICON key. The add() method for the toolbar object will then look for the icon for the toolbar button it creates using this key. Let's see if it works.


You will need to create the GIF files containing the icons. Any graphics editor that can save files in the GIF format will do, Paint Shop Pro, Microsoft Paint, or gimp, for instance. I created my icons as 16x16 pixels since it is a fairly standard size for toolbar buttons. Make sure the file for the openAction object is called open.gif, and stored in the Images subdirectory. We will need GIF files for other buttons too, and they will each have a file name that is the same as the label on the corresponding menu item.

If you want to put them together in one go, for the file menu toolbar button you will need save.gif, new.gif and print.gif, for the element types you will need line.gif, rectangle.gif, circle.gif, and curve.gif, and for the colors you will need red.gif, yellow.gif, green.gif and blue.gif. GIF files for all these icons are available along with the Sketcher source code at the Wrox web site: .

Try It Out – A Button with an Icon

You can add the statement to create the icon for the Action object just before we create the toolbar button:

  public SketchFrame(String title) {
    // Constructor code as before...

    openAction.putValue(Action.SMALL_ICON, new ImageIcon ("Images/open.gif"));
    JButton button = toolBar.add(openAction);                // Add toolbar button
    button.setBorder(BorderFactory.createRaisedBevelBorder());// Add button border

    toolBar.setFloatable(false);                       // Inhibit toolbar floating
    getContentPane().add(toolBar, BorderLayout.NORTH);        // Add the toolbar

In fact you could put the statement anywhere after the openAction object is created, but here will be convenient. If you recompile Sketcher and run it again, you should see the window below.

How It Works

The ImageIcon object that we store in our openAction object is automatically used by the add() method for the toolBar object to add the icon to the button. Fortunately we don't get the label on the toolbar button as well as the icon since the label is automatically inhibited by the presence of an icon. If you look at the corresponding menu item though, we get both the label and the icon. This might not be what you want so we will return to this point a little later in this chapter.

It would be better if we altered the inner classes that define the Action objects to add icons automatically when a suitable .gif file is available. Let's try that now.

Try It Out – Adding All the Toolbar Buttons

We can modify the constructor for each inner class to add the corresponding icon. Here's how we can implement this in the FileAction class:

FileAction(String name) {
  String iconFileName = "Images/" + name + ".gif";
  if(new File(iconFileName).exists())
    putValue(SMALL_ICON, new ImageIcon(iconFileName));

Because we refer to the File class here, we need to add an import statement for to the beginning of the source file. This code assumes all icon files follow the convention that their name is the same as the String associated with the NAME key. If you want to have any file name, you could pass the String defining the file name to the constructor. If the icon file is not available then nothing happens, so the code will work whether or not an icon is defined. We only need to add the code to this constructor since the other constructors in the FileAction class call this one.

The code that you add to the constructors for the TypeAction and ColorAction inner classes is exactly the same as here, so go ahead and copy it across.

We can reduce the code we need in the SketchFrame constructor a little by defining a helper method in the SketchFrame class to create toolbar buttons as follows:

private JButton addToolBarButton(Action action) {
  JButton button = toolBar.add(action);              // Add toolbar button
  button.setBorder(BorderFactory.createRaisedBevelBorder());// Add button border
  return button;

The argument is the Action object for the toolbar button that is to be added, and the code is essentially the same as the specific code we had in the SketchFrame constructor to create the button for the openAction object. We can remove that from the SketchFrame constructor and replace it by the following code to create all the buttons that we need:

public SketchFrame(String title) {
  // Constructor code as before...

  // Add file buttons
  toolBar.addSeparator();                                 // Space at the start
  // Add element type buttons

  // Add element color buttons
  toolBar.addSeparator();                            // Space at the end
  toolBar.setBorder(BorderFactory.createCompoundBorder(       // Toolbar border

  toolBar.setFloatable(false);                       // Inhibit toolbar floating
  getContentPane().add(toolBar, BorderLayout.NORTH); // Add the toolbar

Now you should get the window with the toolbar that we showed at the beginning, with a nice neat toolbar. You can see the color buttons in action since they will change the background color.

How It Works

The extra code in the inner class constructors stores an icon in each object if there is a GIF file with the appropriate name in the Images subdirectory. We create each of the toolbar buttons by calling our addToolBarButton() helper method with an Action item corresponding to a menu item. The helper method passes the Action object to the add() method for the JToolBar object to create a JButton object. It also adds a border to the button. The addToolBarButton() method returns a reference to the button object in case we need it.

We have added a further statement to add a border to the toolbar. We use the createCompoundBorder() method to create a border with an outer border that is a single line, and an inner border that is empty but inserts space around the inside of the outer border as specified by the arguments. The arguments to createEmptyBorder() are the width in pixels of the border in the sequence top, left, bottom and right.

Fixing the Menus

Things are perhaps still not quite as we would have them. If you take a look at the menus you will see what I mean.

All of the menu items now have icons too. While this is a helpful cue to what the toolbar icons are, maybe you would rather not have them as they look a little cluttered. We could get rid of the icons very easily by modifying the menu items that are created by the add() method for the JMenu objects in the addMenuItem() method. The JMenuItem class has a setIcon() method that accepts a reference of type Icon to set an icon for a menu item. If we want to remove the icon, we just pass null to it.

Try It Out – Removing Menu Item Icons

We just need to add one statement to addMenuItem() method in the SketchFrame class to remove the icons for all the menu items, like this:

private JMenuItem addMenuItem(JMenu menu, Action action) {
  JMenuItem item = menu.add(action);                  // Add the menu item

  KeyStroke keystroke = (KeyStroke)action.getValue(action.ACCELERATOR_KEY);
  if(keystroke != null)
  item.setIcon(null);                                 // Remove the icon
  return item;                                        // Return the menu item

When you run Sketcher with this modification to SketchFrame, you should see the menu items without icons.

How It Works

When we construct each of the menu items using our helper method addMenuItem() we remove the icon from the JMenuItem that is created by passing null to its setIcon() method. Thus none of the menu item objects has an icon associated with it. Of course, the toolbar buttons are unaffected and retain the icons defined by the Action objects they are created from.

Adding Tooltips

I'm sure you have seen tooltips in operation. These are the little text prompts that appear automatically when you let the mouse cursor linger over certain GUI elements on the screen for a second or two. They disappear automatically when you move the cursor. I think you will be surprised at how easy it is to implement support for tooltips in Java.

The secret is in the Action objects that we are using. Action objects have a built-in capability to store tooltip text because it is already provided for with the SHORT_DESCRIPTION key that is defined in the interface. All we have to do is store the tooltip text in our inner classes that are derived from AbstractAction. The tooltip will then be automatically available on the toolbar buttons that we create. Let's work through our Action classes and provide for tooltip text.

Try It Out – Implementing Tooltips

We can provide for tooltip text in each of our inner classes by adding constructors with an extra parameter for it. We need two additional constructors in the FileAction class, one for when the Action item has an accelerator key, and the other for when it doesn't. The definition of the first new FileAction class constructor will be:

FileAction(String name, KeyStroke keystroke, String tooltip) {
  this(name, keystroke);                         // Call the other constructor
  if(tooltip != null)                             // If there is tooltip text
    putValue(SHORT_DESCRIPTION, tooltip);         // ...squirrel it away

This just calls the constructor that accepts arguments defining the name and the keystroke. It then stores the tooltip string using the SHORT_DESCRIPTION key, as long as it isn't null. Although you wouldn't expect a null to be passed for the tooltip text reference, it's best not to assume it as this could crash the program. If it is null we do nothing.

The other constructor will take care of a tooltip for an Action item without an accelerator keystroke:

FileAction(String name, String tooltip) {
  this(name);                                // Call the other constructor
  if(tooltip != null)                        // If there is tooltip text
    putValue(SHORT_DESCRIPTION, tooltip);    // ...squirrel it away

Of course, we must now change the code in the SketchFrame constructor that creates FileAction items so that we incorporate the tooltip argument:

    // Create the action items for the file menu
newAction = new FileAction("New", KeyStroke.getKeyStroke('N',Event.CTRL_MASK ), 
                           "Create new sketch");
openAction = new FileAction("Open", KeyStroke.getKeyStroke('O',Event.CTRL_MASK),
                           "Open existing sketch");
closeAction = new FileAction("Close", "Close sketch");
saveAction = new FileAction("Save", KeyStroke.getKeyStroke('S',Event.CTRL_MASK),
                            "Save sketch");
saveAsAction = new FileAction("Save As...", "Save as new file");
printAction = new FileAction("Print", KeyStroke.getKeyStroke('P',Event.CTRL_MASK), 
                             "Print sketch");

We can do exactly the same with the TypeAction class – just add the following constructor definition:

TypeAction(String name, int typeID, String tooltip) {
  this(name, typeID);
  if(tooltip != null)                               // If there is a tooltip
    putValue(SHORT_DESCRIPTION, tooltip);           // ...squirrel it away

We must then modify the code in the SketchFrame constructor to pass a tooltip string when we create a TypeAction object:

    // Construct the Element pull down menu
addMenuItem(elementMenu, lineAction = new TypeAction("Line", LINE, "Draw lines")); 
addMenuItem(elementMenu, rectangleAction = new TypeAction("Rectangle",RECTANGLE, 
                                                          "Draw rectangles"));
addMenuItem(elementMenu, circleAction = new TypeAction("Circle", CIRCLE, 
                                                          "Draw circles"));
addMenuItem(elementMenu, curveAction = new TypeAction("Curve", CURVE, 
                                                      "Draw curves"));

And a constructor that does exactly the same needs to be added to the ColorAction class:

public ColorAction(String name, Color color, String tooltip) {
  this(name, color);
  if(tooltip != null)                               // If there is a tooltip
    putValue(SHORT_DESCRIPTION, tooltip);           // ...squirrel it away

The corresponding changes in the SketchFrame constructor are:

JMenu colorMenu = new JMenu("Color");                // Color sub-menu
elementMenu.add(colorMenu);                          // Add the sub-menu
addMenuItem(colorMenu, redAction = new ColorAction
("Red",, "Draw in red"));
addMenuItem(colorMenu, yellowAction = new ColorAction
("Yellow", Color.yellow, "Draw in yellow"));
addMenuItem(colorMenu, greenAction = new ColorAction
("Green",, "Draw in green"));
addMenuItem(colorMenu, blueAction = new ColorAction
("Blue",, "Draw in blue"));

Of course, if you want to put your own tooltip text for any of these, you can. You should keep it short since it is displayed on the fly. We can try our tooltips out now we have the last piece in place. Just recompile the SketchFrame class and run Sketcher again. You should be able to see the tooltip when you let the cursor linger over a button.

How It Works

Action objects act as a repository for the tooltip text for a toolbar button. If an Action object contains a tooltip property, a toolbar button that you create from it will automatically have the tooltip operational. Try lingering the cursor over a menu item. Since the menu items are also created from Action items, tooltips are available for them, too.

Disabling Actions

You won't want to have all of the menu items and toolbar buttons enabled all of the time. For instance, while there is no sketch active, the Save and Print menu items should not be operational, and neither should the corresponding buttons. The Action objects provide a single point of control for enabling or disabling menu items and the corresponding toolbar buttons. To disable an action, you call the setEnabled() method for the Action object with an argument of false. You can restore the enabled state by calling the method with a true argument. The isEnabled() method for an Action object returns true if the action is enabled, and false otherwise.

Let's see toolbar button inaction in action in Sketcher.

Try It Out – Disabling Actions

We will disable the actions corresponding to the Save, Close and Print actions. Add the following statements to the end of the SketchFrame constructor:

// Disable actions

That's all that's necessary. If you run the modified version of Sketcher, menu items and toolbar buttons corresponding to the Action objects we have disabled will be grayed out and non-operational.

If you extend the File menu, you will see that the corresponding menu items are grayed out, too.

How It Works

The state of both the JMenuItem and JButton objects created from an Action object is determined by the state of the Action object. Disabling the Action object disables any menus or toolbar buttons created from it. If you want a demonstration that they really are disabled, try disabling a couple of the color actions.

Previous Next
JavaScript Editor Java Tutorials Free JavaScript Editor