In this chapter we will add menus to our application. But before we begin to look at menus let's restructure our code from the last chapter. Since Java is an object-oriented language we should structure our code to take advantage of this feature. Also, let's take our first look at signals, the event mechanism in GTK.
All GNOME and GTK applications are event driven. This means that when actions take place in the application it causes an event to be sent from a source and acted upon by a reciever. In fact, when we made the call Gtk.main() in the program in the last chapter we were telling our application to wait for an event and when the event arrives, a function is called. The event is called a signal in GNOME and GTK and the function is called a callback.
The example below demonstrates the concept event handling. It is the example from the previous chapter (restructured a little) and adds callbacks to handle the delete_event and the destroy events.
Example 3-1. Second.java - first take
import org.gnu.gnome.About; import org.gnu.gnome.App; import org.gnu.gnome.Program; import org.gnu.gnome.UIInfo; import org.gnu.gtk.Gtk; import org.gnu.gtk.event.LifeCycleEvent; import org.gnu.gtk.event.LifeCycleListener; import org.gnu.gtk.event.MenuItemEvent; import org.gnu.gtk.event.MenuItemListener; public class Second implements MenuItemListener { private App app = null; public static final String appVersion = "0.1"; public Second() { createMainWindow(); app.showAll(); } private void createMainWindow() { app = new App("Second", "Second App"); app.setDefaultSize(200, 200); app.addListener(new LifeCycleListener() { public void lifeCycleEvent(LifeCycleEvent event) { if (event.isOfType(LifeCycleEvent.Type.DESTROY) || event.isOfType(LifeCycleEvent.Type.DELETE)) { Gtk.mainQuit(); } } }); } public static void main(String[] args) { Program.initGnomeUI("Second", Second.appVersion, args); Second second = new Second(); Gtk.main(); } }
First let's look at how we restructured the code. As you can see I have added two members to our class. I have also added a constructor and a method to build the window. I have also added an inner class to handle the events featured in this example.
The creation of the window is handled in the createMainWindow method which is called from the constructor. This method creates our App, sets size information, and provides a handler for the events.
Most window managers have a "Close" menu item on a menu or the toolbar. Selecting this menu option causes an event to be sent to your application. This event is the delete_event. Your application should intercept this event and perform any necessary cleanup. Things that you might want to do here is close files you have open, close any socket connections, prompt the user to save changed data, etc. The delete_event and other events that relate to the lifecycle of the application are represented by the LifeCycleEvent and are handle by LifeCycleListener. The example above handles this event by creating an inner class that implements LifeCycleListener to receive the event. Since there are several types of LifeCycleEvent's we must check the Type of event to make sure we are handling the proper event. This is performed with the following call:
Example 3-2. isOfType()
if (event.isOfType(LifeCycleEvent.Type.DESTROY) || event.isOfType(LifeCycleEvent.Type.DELETE)) { // do something here }
This has been a very brief introduction to event handling but since every example will be using them throughout the remainder of this tutorial we will stop here now and expand our discussions as we explore new topics. Now on to the menus.