Previous Page TOC Next Page



- 13 -
More on Graphical Front Ends Using Visual J++


Up until now, your applets and applications have not done much. They have displayed some nice interfaces and you have learned how to manipulate them in your code. Today, we are going to bring your Visual J++ applets and applications to life using dialogs and handling events to manipulate data. Today you'll learn about the following:



This chapter is very long and covers a lot of material. You might want to budget some extra time for this day.


Windows, Menus, and Dialog Boxes


Today, you'll finish up the last bits of the AWT that didn't fit into yesterday's lesson. In addition to all the graphics, events, UI, and layout mechanisms that the AWT provides, it also provides windows, menus, and dialog boxes, which enable you to create fully featured applications either as part of your applet or independently for standalone Java applications.

Frames


The AWT Window class enables you to create windows that are independent of the browser window containing the applet—that is, separate pop-up windows with their own titles, resize handles, and menubars.



It's important to note here that the Window class has nothing to do with Microsoft Windows. The Window class is a generic class that handles windows on any platform.

The Window class provides basic behavior for windows. Most commonly, instead of using the Window class, you'll use Window's subclasses, Frame and Dialog. The Frame class enables you to create a fully functioning window with a menubar. Dialog is a more limited window for dialog boxes. You'll learn more about dialog boxes later in this section.

To create a frame, use one of the following constructors:

Like panels, frames are containers. You can add other components to them just as you would regular panels, using the add() method. The default layout for windows is BorderLayout:




win = new Frame("My Cool Window");



win.setLayout(new BorderLayout(10, 20));



win.add("North", new Button("Start"));



win.add("Center", new Button("Move"));

To set a size for the new window, use the resize() method. To set a location for where the window appears, use the move() method. Note that the location() method can tell you where the applet window is on the screen so that you can pop up the extra window in a position relative to that window (all these methods are defined for all containers, so you can use them for applets, windows, and the components inside them, subject to the current layout):




win.resize(100, 200);



Dimension d = location();



win.move(d.width + 50, d.height + 50);

When you initially create a window, it's invisible. You need to use the show() method to make the window appear on the screen (you can use hide() to hide it again):




win.show();

The following is an example of a simple applet that displays a simple pop-up window. This applet depends on the MyFrame class that you will also need to create. The MyFrame Class should be a separate .java file called MyFrame.java. Save this project because you will be extending it throughout this chapter.

Now start by creating a new applet to work with. Create a new Project Workspace using the Java Applet Wizard. Name your Project UIApp. Make sure that you select Yes to create a multithreaded applet and select No for animation support.

Once your Project Workspace is created, create a new text file and enter the following code to create the class MyFrame. Save this as MyFrame.java and insert into the project (Insert | Files into Project from the menu). You can omit the comments if you so wish.




import java.applet.*;



import java.awt.*;



class MyFrame extends Frame



{



    MyFrame(String title)



    {



        super(title); // Call the parent class function to set the title



        resize(300,300); // set default size



        this.show(); // show the frame



    }



}

In the UIApp.java file before the class definition, import the MyFrame class:




import MyFrame;

Add a new data member called m_frmFrame that is of type MyFrame:




MyFrame m_frmFrame;

In the UIApp applet init() method, add the following code:




m_frmFrame = new MyFrame( "My Frame Test" );

Compile and run the applet. A single blank pop-up window should be displayed. As you can tell, all this applet does now is display a simple window. By the way, the only way you can stop this applet is to select File | Close (or Exit) from your browser's menu. Keep reading and some cool functionality will be added.

Menus


Each new window you create can have its own menubar along the top of the screen. Each menubar can have a number of menus, and each menu, in turn, can have menu items. The AWT provides classes for all these things called, respectively, MenuBar, Menu, and MenuItem. Creating a menu system using plain Java code is akin to pulling teeth, although you might be forced to if you ever need to maintain older code or code developed with another development environment. Luckily, Visual J++ makes it extremely easy by using the Resource Editor.



If you still wish to create a menu without using the Resource Editor, you can use the Java API documentation included with Visual J++.


Creating a Menu Resource Item

The first step in creating a Menu Resource, like other resources, is to create a Resource Template (File | New | Resource Template) just as you did yesterday. Save this new Resource Template, in the UIApp project directory, as UIApp.rct. To insert a new Menu resource into the template, do the following:

  1. Right-click the UIApp folder and select Insert.
  2. Select Menu and click OK (an empty menubar displays).
  3. Right-click (or double-click) the empty Menu item and select Properties.
  4. Type File for the Caption (notice that you can't give the menu item an ID), and then close the window.
  5. Click the File Menu item, a box displays below it; double-click the empty box, the properties window displays.
  6. Type MN_EXIT for the ID and Exit for the Caption (see figure 13.1), and then close the window.
  7. Double-click any empty space on your menubar, type MyMenu for the ID, and then close the window.

Save the Resource Template. Run the Java Resource Wizard (Tools | Java Resource Wizard). Insert the newly created file MyMenu.java into your UIApp project.

Figure 13.1. A Menu Item Properties dialog box.

Using your Newly Created Menu Item

Add the following code to the MyFrame Class. At the top of the file add the line:




import MyMenu;

Under the MyFrame class definition add the line:




MyMenu m_mnuMine;

Under the constructor MyFrame(String title) add these lines of code:




m_menuMine = new MyMenu( this );



m_menuMine.CreateMenu();

Your window—with a menu—will now display. (See Figure 13.2) Even though you've easily created the window and menu item; it doesn't do very much, other than display. That's because there hasn't been any action assigned to the Exit menu item. Later in this chapter, we'll assign an action to the menu item event. Try adding some other items to your menu and experimenting with the property page settings.

Figure 13.2. My Frame window showing the File menu item.

Some browsers enable you to indicate a special help menu, which will display on the right side of the window's menubar. You can indicate that a specific menu is the help menu by calling the setHelpMenu method of the class MenuBar. You can view the MyMenu file created by the Java Resource Wizard to determine what data members represent which menu items.




mb.setHelpMenu(ID_HELP);

If, for any reason, you want to prevent a user from selecting a menu item or menu command, you can use the disable() command on the menu ID (and the enable() command to make it available again). When a menu item or command is disabled, it still appears on the menu; it is, however, grayed-out and unselectable by the user:




ID_HELP.disable();

Pop-ups, Separator Bars, and a Little More

When you use many Windows applications such as word-processing, spreadsheet, databases, and mail systems, the menu systems are quite elaborate. Often you open a single menu and if you select a given item, another menu opens. A simple example of this is the Start menu in Windows 95 or Windows NT 4.0. This kind of menu is called a pop-up menu.

To create a pop-up in Visual J++, it is a simple matter of setting properties in the Resource Editor. Follow the preceding steps listed (in the Creating a Menu Resource Item section) to create a new menu resource. Create a new child menu under the File menu and label it Test. View the properties of the Test item and check the Pop-up box. Immediately, a new pop-up menu appears to which you can add more menu items.

Another menu item that is often used to make menu systems easier to read is a separator bar. As with all pop-ups, adding a separator bar is as simple as checking a box in the properties page of a menu item. In this same little Test resource, add a new menu item under the Test item. Don't bother with a label or an ID, but simply view the properties and check Separator box. There you go: instant Separator bar.

Dialog Boxes


Dialog boxes are functionally similar to frames in that they pop up new windows on the screen. However, dialog boxes are intended to be used for transient windows—for example, windows that let you know about warnings, windows that ask you for specific information, and so on. Dialog boxes don't usually have titlebars (although you can create one with a titlebar) or many of the more general features that windows have. Dialog boxes can also be made non-resizable or modal.

A modal dialog box prevents input to any of the other windows in the applet or application until that dialog box is dismissed.

The AWT provides two kinds of dialog boxes: the Dialog class, which provides a generic dialog box, and FileDialog, which produces a platform-specific dialog box to choose files to save or open.

To create a generic dialog box, use one of these constructors:

Note that because you have to give a dialog box a Frame argument, you can attach dialog boxes only to windows that already exist independently of the applet itself.

The dialog box window, like the frame window, is a panel on which you can lay out and draw UI components and perform graphic operations, just as you would any other panel. Like other windows, the dialog box is initially invisible, but you can show it with show() and hide it with hide().

Now add a dialog box to that same example with the pop-up window that we have been working with: UIApp. You are simply going to modify the MyFrame class to attach a dialog box that you will define in the Resource Editor. You are also going to attach a dialog box to the Frame itself.

To create the DLG_GetData dialog box, do the following.

  1. Open UIApp.rct (or simply switch to the already open window).
  2. From the menubar, select Insert | Resource | Dialog.
  3. Select the Cancel button and press Delete.
  4. Select the OK button and drag it down to the middle of the right side.(You can also use Ctrl+F9 to center the button.)
  5. Double-click the OK button; the Properties window displays. The ID should be IDOK and the Caption should be OK.
  6. Double-click any empty space in the dialog box; the Properties window displays. Change the Dialog box ID to DLG_GetData.
  7. Click the Font button, change the Size to 14 (you might need to resize the window to see the changes), and then close the window.
  8. From the Controls Toolbar, select the Edit Box control.
  9. Click and drag to draw an Edit box on the Dialog box, and then press Ctrl+F9.
  10. Double-click the Edit box and change the ID to ID_DATA.

See Figure 13.3 for the completed dialog box.



The default font size for dialog boxes is 8 point. This is quite small! Setting the font on the dialog box to 14 sets the font size for all controls to 14 point.

Figure 13.3. Completed DLG_GetData Dialog box, showing the Edit Box control and OK Button control.

Now your going to create a new dialog box called DLG_ShowData. This new dialog box will be created in the same UIApp.rct file as DLG_GetData.

To create the DLG_ShowData, do the following:

  1. Open UIApp.rct (or simply switch to the already open window).
  2. From the menubar, select Insert | Resource | Dialog.
  3. Delete the OK and Cancel buttons.
  4. Change the Dialog box ID to DLG_ShowData.
  5. Click the Font button, change the Size to 14.
  6. Create an Edit Control in the dialog.
  7. Change the ID of the Edit box ID_DISPLAY_DATA.

There should be three resources in the resource file: DLG_ShowData, DLG_GetData, and MyMenu. To complete the Resource phase of this example, do the following:

  1. Save the resource file.
  2. Run the Java Resource Wizard.
  3. Insert the DLG_GetData.java and DLG_ShowData.java files into the project.

In the MyFrame class, add the following lines of code:




import DLG_GetData;



import DLG_ShowData;

Under the MyFrame class definition add the lines:




Font m_Font;



DLG_GetData m_dlgGet;



DLG_ShowData m_dlgShow;



Dialog m_dlgGetDlg;

In the constructor of MyFrame, before Show(), add the following lines of code:




m_Font = new Font("Arial", Font.PLAIN, 18);



setFont(m_Font);



// Create the ShowData dialog on the Frame;



setBackground(Color.lightGray);



m_dlgShow = new DLG_ShowData( this );



m_dlgShow.CreateControls();



// Create the GetData dialog Box



m_dlgGetDlg = new Dialog ( this, "Data Dialog", false);



// Create new generic Dialog object



m_dlgGetDlg.setBackground(color.lightGray);



m_dlgGetDlg.resize(300,300);



m_dlgGetDlg.setFont( m_Font );



// Create the Resource File generated Dialog



m_dlgGet = new DLG_GetData(m_dlgGetDlg);



m_dlgGet.CreateControls();



// display the two windows;



show()



m_dlgGetDlg.show();


It might seem unnecessary to add the line of code m_dlgGetDlg.setFont( m_Font );. But, without it, the applet doesn't run. This might be a bug in VJ++—we don't know.

To see all of your great work, compile and then run it. (See Figure 13.4.)

Figure 13.4. The GetData and ShowData dialog boxes in IE.

File Dialogs


FileDialog provides a basic file open/save dialog box that enables you to access the file system. The FileDialog class is system-independent, but depending upon the platform, the standard Open File dialog is brought up.



For applets, you can bring up the file dialog box, but due to security restrictions you can't do anything with it (or, if you can do anything, access to any files on the local system is severely restricted). FileDialog is much more useful in standalone applications.

To create a file dialog, use the following constructors:

After you create a FileDialog instance, use show() to display it:




FileDialog fd = new FileDialog(this, "FileDialog");



fd.show();

When the user chooses a file in the file dialog and dismisses it, you can then access the filename they chose by using the getDirectory() and getFile() methods; both return strings indicating the values the user chose. You can then open that file by using the stream and file handling methods (which you'll learn about next week) to read from or write to that file.

Handling UI Actions and Events


Java events are part of the Java AWT package. An event is the way that the AWT communicates to you, as the programmer, and to other Java AWT components that something has happened. That something can be input from the user (mouse movements or clicks, keypresses), changes in the system environment (a window opening or closing, the window being scrolled up or down), or a host of other things that might, in some way, be interesting to the operation of the program.

In other words, whenever just about anything happens to a Java AWT component, including an applet, an event is generated. Some events are handled by the AWT or by the browser without your needing to do anything. paint() methods, for example, are generated and handled by the browser—all you have to do is tell the AWT what you want painted when it gets to your part of the window. Some events, however (for example, a mouse click inside the boundaries of your applet), you might need to know about. Writing your Java programs to handle these kinds of events enables you to get input from the user and have your applet change its behavior based on that input.

Mouse Clicks


Now start with the most common event you might be interested in: mouse clicks. Mouse-click events occur when the user clicks the mouse somewhere in the body of your applet. You can intercept mouse clicks to do very simple things—for example, to toggle the sound on and off in your applet, to move to the next slide in a presentation, or to clear the screen and start over—or you can use mouse clicks in conjunction with mouse movements to perform more complex motions inside your applet.

mouseDown and mouseUp

When you click the mouse once, the AWT generates two events: a mouseDown event when the mouse button is pressed, and a mouseUp event when the button is released. Why two individual events for a single mouse action? Because you might want to do different things for the "down" and the "up." For example, look at a pull-down menu. The mouseDown extends the menu, and the mouseUp selects an item (with mouseDrags between—but you'll learn about that one later today). If you have only one event for both actions (mouseUp and mouseDown), you cannot implement that sort of user interaction.

Handling mouse events in your applet is easy—all you have to do is override the proper method definition in your applet. That method will be called when that particular event occurs. Here's an example of the method signature for a mouseDown event:




public boolean mouseDown(Event evt, int x, int y)



{



...



}

The mouseDown() method (and the mouseUp() method as well) takes three parameters: the event itself and the x and y coordinates where the mouseDown or mouseUp event occurred.

The event argument is an instance of the class Event. All system events generate an instance of the Event class, which contains information about where and when the event took place, the kind of event it is, and other information that you might want to know about this event. Sometimes having a handle to that event object is useful, as you'll discover later in this section.

The x and the y coordinates of the event, as passed in through the x and y arguments, are particularly nice to know because you can use them to determine precisely where the mouse click took place.

For example, here's a simple method that grabs the current x and y positions when a mouseDown event occurs:




public boolean mouseDown(Event evt, int x, int y)



{



    m_iMousex = x;



    m_iMousey = y;



    return true;



}

By including this method in an applet, every time the user clicks the mouse inside your applet, the data members m_iMousex and m_iMousey will be updated.

Note that this method, unlike the other system methods you've studied thus far, returns a Boolean value instead of not returning anything (void). This will become important later today when you create user interfaces and then manage input to these interfaces; having an event handler return true or false determines whether a given UI component can intercept an event or whether it needs to pass it on to the enclosing component. The general rule is that if your method deals with the event, it should return true.

The second half of the mouse click is the mouseUp() method, which is called when the mouse button is released. To handle a mouseUp event, add the mouseUp() method to your applet. mouseUp() looks just like mouseDown():




public boolean mouseUp(Event evt, int x, int y)



{



    ....



}

A Spots Applet Example

In this section, you'll create an example of an applet that uses mouse events—mouseDown events in particular. The Spots applet starts with a blank screen and then sits and waits. When you click the mouse on that screen, a blue dot is drawn. You can place up to ten dots on the screen. Figure 13.5 shows the Spots applet.

Figure 13.5. The Spots applet.

Start from the beginning and build this applet, starting from the initial class definition:



Because this is a very simple applet, we are not going to use the Resource Editor at all. Leave the UIApp running while you complete this next exercise though, you're going to use it later today.

Create a new Project Workspace and name it Spots. Create a new text file and add the following lines of code to it.




import java.awt.Graphics;



import java.awt.Color;



import java.awt.Event;



public class Spots extends java.applet.Applet



{



    final int MAXSPOTS = 10;



    int m_iXspots[] = new int[MAXSPOTS];



    int m_iYspots[] = new int[MAXSPOTS];



    int m_iCurrspots = 0;



}

This class uses three other AWT classes: Graphics, Color, and Event. That last class, Event, needs to be imported in any applets that use events. The class has four instance variables: a constant to determine the maximum number of spots that can be drawn, two arrays to store the x and y coordinates of the spots that have already been drawn, and an integer to keep track of the number of the current spot.



This class doesn't include the implements Runnable words in its definition. As you'll see later as you build this applet, it also doesn't have a run() method. Why not? Because it doesn't actually do anything on its own—all it does is wait for input and then do stuff when input happens. There's no need for threads if your applet isn't actively doing something all the time.

Start with the init() method, which has one line, to set the background to white:




public void init()



{



        setBackground(Color.white);



}

Set the background in init(), instead of in paint(), because you really need to set the background only once. Also, since paint() is called repeatedly each time a new spot is added, setting the background color in the paint() method unnecessarily slows down that method. Putting it here is a much better idea.

The main action of this applet occurs on the mouseDown() method, so add that one now:




public boolean mouseDown(Event evt, int x, int y)



{



    if (m_iCurrspots < MAXSPOTS)



            addspot(x,y);



    return true;



}

When the mouse click occurs, the mouseDown() method tests to see whether there are less than ten spots. If so, it calls the addspot() method (which you'll write soon). If not, it just prints an error message. Finally, it returns true, because all the event methods have to return a Boolean value (usually true).

What does addspot() do? It adds the coordinates of the spot to the arrays that store the coordinates, increments the currspots variable, and then calls repaint():




void addspot(int x, int y)



{



        m_iXspots[currspots] = x;



        m_iYspots[currspots] = y;



        m_iCurrspots++;



        repaint();



}

You might be wondering why you have to keep track of all the past spots in addition to the current spot. The reason is because of repaint(): each time you paint the screen, you have to paint all the old spots in addition to the newest spot. Otherwise, each time you painted a new spot, the older spots would get erased. Now, on to the paint() method:




public void paint(Graphics g)



{



    g.setColor(Color.blue);



    for (int i = 0; i < m_iCurrspots; i++)



    {



        g.fillOval(m_iXspots[i] -10, m_iYspots[i] - 10, 20, 20);



    }



}

Inside paint, you just loop through the spots you've stored in the m_iXspots and m_iYspots arrays, painting each one (actually, painting them a little to the right and upward so that the spots are painted around the mouse pointer rather than below and to the right).

That's it! That's all you need to create an applet that handles mouse clicks. Everything else is handled for you. You have to add the appropriate behavior to mouseDown() or mouseUp() to intercept and handle that event. Listing 13.1 shows the full text for the Spots applet.

Listing 13.1. The Spots applet.




 1: import java.awt.Graphics;



 2: import java.awt.Color;



 3: import java.awt.Event;



 4:



 5: public class Spots extends java.applet.Applet



 6: {



 7:     final int MAXSPOTS = 10;



 8:     int m_iXspots[] = new int[MAXSPOTS];



 9:     int m_iYspots[] = new int[MAXSPOTS];



10:     int m_iCurrspots = 0;



11:



12:     public void init()



13:     {



14:         setBackground(Color.white);



15:     }



16:



17:     public boolean mouseDown(Event evt, int x, int y)



18:     {



19:         if (m_iCurrspots < MAXSPOTS)



20:             addspot(x,y);



21:         return true;



22:     }



23:



24:     void addspot(int x,int y)



25:     {



26:         m_iXspots[m_iCurrspots] = x;



27:         m_iYspots[m_iCurrspots] = y;



28:         m_iCurrspots++;



29:         repaint();



30:     }



31:



32:     public void paint(Graphics g)



33:     {



34:         g.setColor(Color.blue);



35:         for (int i = 0; i < m_iCurrspots; i++)



36:         {



37:             g.fillOval(m_iXspots[i] - 10, m_iYspots[i] - 10, 20, 20);



38:         }



39:     }



40: }

Mouse Movements


Every time the mouse is moved a single pixel in any direction, a mouse move event is generated. There are two mouse movement events: mouse drags, where the movement occurs with the mouse button pressed down, and plain mouse movements, where the mouse button isn't pressed.

To manage mouse movement events, use the mouseDrag() and mouseMove() methods.

mouseDrag and mouseMove

The mouseDrag() and mouseMove() methods, when included in your applet code, intercept and handle mouse movement events. The mouseMove() method, for plain mouse pointer movements without the mouse button pressed, looks much like the mouse-click methods:




public boolean mouseMove(Event evt, int x, int y)



{



    ...



}

The mouseDrag() method handles mouse movements made with the mouse button pressed down (a complete dragging movement consists of a mouseDown event, a series of mouseDrag events for each pixel the mouse is moved, and a mouseUp event when the button is released). The mouseDrag() method looks like this:




public boolean mouseDrag(Event evt, int x, int y)



{



    ...



}

mouseEnter and mouseExit

Finally, there are the mouseEnter() and mouseExit() methods. These two methods are called when the mouse pointer enters the applet or when it exits the applet. (In case you're wondering why you might need to know this, it's more useful on components of user interfaces that you might put inside an applet. You'll learn more about UI tomorrow).

Both mouseEnter() and mouseExit() have similar signatures—three arguments: the event object and the x and y coordinates of the point where the mouse entered or exited the applet.




public boolean mouseEnter(Event evt, int x, int y)



{



    ...



}



public boolean mouseExit(Event evt, int x, int y)



{



    ...



}

Keyboard Events


Keyboard events are generated whenever users press a key on the keyboard. By using key events, you can get hold of the values of the keys that were pressed to perform an action or merely to get character input from the users of your applet.

The keyDown and keyUp Methods


To capture a keyboard event, use the keyDown() method:




public boolean keyDown(Event evt, int key)



{



    ...



}

The keys generated by keyDown events (and passed into keyDown() as the key argument) are integers representing ASCII character values, which include alphanumeric characters, function keys, tabs, returns, and so on. To use them as characters (for example, to print them), you need to cast them to characters:




currentchar = (char)key;

Here's a simple example of a keyDown() method that does nothing but set the data member m_cLastKey to the character value of the key you just typed.




public boolean keyDown(Event evt, int key)



{



    m_cLastKey = (char)key;



    return true;



}

As with mouse clicks, each keyDown event also has a corresponding keyUp event. To intercept keyUp events, use the keyUp() method:




public booklean keyUp(Event evt, int key)



{



   ...



}

Default Keys


The Event class provides a set of class variables that refer to several standard non-alphanumeric keys, such as the arrow keys. If your interface uses these keys, you can provide more readable code by testing for these names in your keyDown() method rather than testing for their numeric values. For example, to test whether the up arrow was pressed, you might use the following code fragment:




if (key == Event.UP)



{



    ...



}

Because the values these class variables hold are integers, you also can use the switch statement to test for them.

Table 13.1 shows the standard event class variables for various keys and the actual keys they represent.

Table 13.1. Standard keys defined by the event class.

Class Variable Represented Key
Event.HOME The Home key
Event.END The End key
Event.PGUP The Page Up key
Event.PGDN The Page Down key
Event.UP The up arrow
Event.DOWN The down arrow
Event.LEFT The left arrow
Event.RIGHT The right arrow

An Example of Entering, Displaying, and Moving Characters


Now look at an applet that demonstrates keyboard events. This one enables you to type a character, it then displays that character in the center of the applet window. You then can move that character around on the screen by using the arrow keys. Typing another character at any time changes the character as it's currently displayed. Figure 13.6 shows an example.

Figure 13.6. The Keys applet.

This applet is actually less complicated than the previous applets you've used. This one has only three methods: init(), keyDown(), and paint(). The data members are also simpler, because the only things you need to keep track of are the x and y positions of the current character and the values of that character itself. Here's the top of this class definition:




import java.awt.Graphics;



import java.awt.Event;



import java.awt.Font;



import java.awt.Color;



public class Keys extends java.applet.Applet



{



    char m_cCurrkey;



    int m_iCurrx;



    int m_iCurry;



}

The init() method is responsible for three things: setting the background color, setting the applet's font (here, 36 point Helvetica bold), and setting the beginning position for the character (the middle of the screen, minus a few points to nudge it up and to the right):




public void init()



{



   m_iCurrx = (size().width / 2) - 8;  // default



   m_iCurry = (size().height / 2) - 16;



   setBackground(Color.white);



   setFont(new Font("Helvetica", Font.BOLD, 36));



}

Because this applet's behavior is based on keyboard input, the keyDown() method is where most of the work of the applet takes place:




public boolean keyDown(Event evt, int key)



{



   switch (key)



         {



         case Event.DOWN:



             m_iCurry += 5;



             break;



         case Event.UP:



             m_iCurry -= 5;



             break;



         case Event.LEFT:



             m_iCurrx -= 5;



             break;



         case Event.RIGHT:



             m_iCurrx += 5;



             break;



         default:



             m_cCurrkey = (char)key;



         }



         repaint();



         return true;



}

In the center of the keyDown() applet is a switch statement that tests for different key events. If the event is an arrow key, the appropriate change is made to the character's position. If the event is any other key, the character itself is changed. The method finishes up with a repaint() and returns true.

The paint() method here is almost trivial; just display the current character at the current position. However, note that when the applet starts up, there's no initial character and nothing to draw, so you have to take that into account. The m_cCurrkey variable is initialized to 0, so you paint the applet only if m_cCurrkey has an actual value:




public void paint(Graphics g)



{



   if (m_cCurrkey != 0)



   {



      g.drawString(String.valueOf(m_cCurrkey), m_iCurrx,m_iCurry);



    }



}

Listing 13.2 shows the complete source for the Keys applet:

Listing 13.2. The Keys applet.




 1: import java.awt.Graphics;



 2: import java.awt.Event;



 3: import java.awt.Font;



 4: import java.awt.Color;



 5:



 6: public class Keys extends java.applet.Applet



 7: {



 8:   char m_cCurrkey;



 9:    int m_iCurrx;



10:     int m_iCurry;



11:



12:     public void init()



13:          {



14:        m_iCurrx = (size().width / 2) -8;  // default



15:        m_iCurry = (size().height / 2) -16;



16:



17:        setBackground(Color.white);



18:        setFont(new Font("Helvetica",Font.BOLD,36));



19:     }



20:



21:     public boolean keyDown(Event evt, int key)



22:     {



23:         switch (key)



24:         {



25:           case Event.DOWN:



26:             m_iCurry += 5;



27:             break;



28:           case Event.UP:



29:             m_iCurry -= 5;



30:             break;



31:           case Event.LEFT:



32:             m_iCurrx -= 5;



33:             break;



34:           case Event.RIGHT:



35:             m_iCurrx += 5;



36:             break;



37:           default:



38:             m_cCurrkey = (char)key;



39:         }



40:



41:         repaint();



42:         return true;



43:     }



44:



45:     public void paint(Graphics g)



46:     {    



47:         if (m_cCurrkey != 0)



48:         {



49:             g.drawString(String.valueOf(m_cCurrkey), m_iCurrx,m_iCurry);



50:         }



51:     }



52: }

Testing for Modifier Keys


Shift, control, and meta are modifier keys. They don't generate key events themselves, but when you get an ordinary mouse or keyboard event, you can test to see whether those keys were held down when the event occurred. Sometimes it might be obvious—shifted alphanumeric keys produce different key events than unshifted ones, for example. For other events, however—mouse events in particular—you might want to handle an event with a modifier key held down differently from a regular version of that event.



In the Windows environment, there is no equivalent to a meta key, so when running a Java program on a Windows system, the metaDown() event will never be triggered by a key press. Even though there is no meta on a Windows system, the metaDown() event is triggered when the right mouse button is clicked.

The Event class provides three methods for testing whether or not a modifier key is held down: shiftDown(), metaDown(), and controlDown(). All return Boolean values based on whether that modifier key is indeed held down. You can use these three methods in any of the event handling methods (mouse or keyboard) by calling them on the event object passed into that method:




public boolean mouseDown(Event evt, int x, int y )



{



    if (evt.shiftDown())



         // handle shift-click



    else // handle regular click



}

The AWT Event Handler


The default methods you've learned about today for handling basic events in applets are actually called by a generic event handler method called handleEvent(). The handleEvent() method is how the AWT generically deals with events that occur between application components and events based upon user input.

In the default handleEvent() method, basic events are processed and the methods you learned about today are called. To handle events other than those mentioned here, to change the default event handling behavior, or to create and pass your own events, you need to override handleEvent() in your own Java programs. The handleEvent() method looks like this:




public boolean handleEvent(Event evt)



{



    ...



}

To test for specific events, examine the ID data member of the Event object that gets passed in. The event ID is an integer, but fortunately, the Event class defines a whole set of event IDs as class variables that you can test for in the body of the handleEvent(). Because these class variables are integer constants, a switch statement works particularly well. For example, here's a simple handleEvent() method to print out debugging information about mouse events:




public boolean handleEvent(Event evt)



{



    switch (evt.id)



    {



      case Event.MOUSE_DOWN:



        System.out.println("MouseDown: " +



                evt.x + "," + evt.y);



        return true;



      case Event.MOUSE_UP:



        System.out.println("MouseUp: " +



                evt.x + "," + evt.y);



        return true;



      case Event.MOUSE_MOVE:



        System.out.println("MouseMove: " +



                evt.x + "," + evt.y);



        return true;



      case Event.MOUSE_DRAG:



        System.out.println("MouseDown: " +



                evt.x + "," + evt.y);



        return true;



      default:



        return false;



    }



}

You can test for the following keyboard events:

You can test for these mouse events:

Note that if you override handleEvent() in your class, none of the default event handling methods you learned about today will get called unless you explicitly call them in the body of handleEvent(), so be careful if you decide to do this. One way to get around this is to test for the event you're interested in, and if that event isn't it, to call super.handleEvent() so that the superclass that defines handleEvent() can process things. Here's an example of how to do this:




public boolean handleEvent(Event evt)



{



    if (evt.id == Event.MOUSE_DOWN)



    {



        // process the mouse down



        return true;



    } 



    else



    {



        return super.handleEvent(evt);



    }



}

In addition to these events, the Event class has a whole suite of methods for handling the UI components. You'll learn more about these events in the next section.

Handling UI Component Actions and Events


Now put everything you have learned today together. You have learned how to display windows and dialog boxes, and you have the basics of event handling under your belt. Now it's time to add some life to the UIApp that you created earlier today:

  1. Open UIApp.rct (or simply switch to the already open window).
  2. Double-click the MyMenu item to open the menu resource. (Expand the outline if the MyMenu item is not displayed.)
  3. Open the properties page for the blank box displayed to the right of the File menu; make the Caption Edit, and then close the Properties box.
  4. Open the properties page for the blank box under the Edit menu. Make the Caption GetData and the ID MN_GETDATA (see Figure 13.7), and then close the properties box.
  5. Save the resource file and then run the Java Resource Wizard.

Figure 13.7. GetData Properties box.

For your UI components to do something when they are activated, you need to hook up the UI's action with an operation. Testing for an action by a UI component is a form of event management—the things you learned yesterday about events will come in handy here. In particular, UI components produce the special kind of event called an action. To intercept an action by any UI component, you define an action() method in your applet or class:




public boolean action(Event evt, Object arg)



{



    ...



}

The action() method should look familiar to the basic mouse and keyboard event methods. Like those methods, it gets passed the event object that represents this event. It also gets an extra object, which can be of any type. What's that second argument for?

The second argument to the action method depends upon the UI component that's generating the event. The basic definition is that it's any arbitrary argument—when a component generates an event, it can pass along any extra information that might be needed later. Because that extra information might be useful for you, it's passed on through the action() method.

All the basic UI components (except for labels, which have no action) have different actions and arguments:

Note that with actions, unlike with ordinary events, you can have many different kinds of objects generating the event, as opposed to a single event such as a mouseDown. To deal with those different UI components and the actions they generate, you have to test for the type of object that sent/created the event in the first place inside the body of your action() method. That object is stored in the event's target data member and you can use the instanceof operator to find out what kind of UI component sent it, as shown in the following code sample:




public boolean action(Event evt, Object arg)



{



    if (evt.target instanceof TextField)



    {



        handleText(evt.target);



    }



    else if (evt.target instanceof Choice)



    {



        handleChoice(arg);



    }



...



}

Although you can handle UI actions in the body of the action() method, it's much more common simply to define a handler method and call that method from action() instead. Here, there are two handler methods: one to handle the action on the text field (handleText()) and one to handle the action on the choice menu (handleChoice()). Depending upon the action you want to handle, you might also want to pass on the argument from the action, the UI component that sent it, or any other information that the event might contain.

Now make the UIApp do something other than look pretty. In the MyFrame class, add the following method:




public boolean action(Event evt, Object arg)



{



    if (evt.target instanceof Button)



    {



        String Val = (String)arg;



        if ( Val.compareTo("OK") == 0)



        {



            m_dlgShow.ID_DISPLAY_DATA.setText(m_dlgGet.ID_DATA.getText());



            m_dlgGetDlg.hide();



            return true;



        }



    }



    return false;



}

The preceding code traps the event on the OK button in the dialog box. It then checks to see if the caption is OK, and if so, sets the text in the Frame to the same data as the text in the dialog box.

Menu Actions

The act of selecting a menu item causes an action event to be generated. You can handle that action the same way you handle other action methods—by overriding action(). Both regular menu items and checkbox menu items have actions that generate an extra argument representing the label for that menu. You can use that label to determine which action to take. Note, also, that because CheckBoxMenuItem is a subclass of MenuItem, you don't have to treat menu items of type CheckBoxMenuItem as a special case. Here is an example:




public boolean action(Event evt, Object arg)



{



    if (evt.target instanceof MenuItem)



    {



        String label = (String)arg;



        if (label.equals("Show Coordinates")) toggleCoords();



        else if (label.equals("Fill")) fillcurrentArea();



        return true;



    }



    else return false;



}

Now add some more functionality to the UPApp. In the MyFrame class, change the action method to read like the following:




public boolean action(Event evt, Object arg)



{



    String sVal = (String)arg;



    if (evt.target instanceof Button)



    {



        if ( sVal.compareTo("OK") == 0)



        {



            m_dlgShow.ID_DISPLAY_DATA.setText(m_dlgGet.ID_DATA.getText());



            m_dlgGetDlg.hide();



            return true;



        }



    }



    if (evt.target instanceof MenuItem)



    {



        if (sVal.equals ("Get Data"))



        {



            m_dlgGet.ID_DATA.setText(m_dlgShow.ID_DISPLAY_DATA.getText());



            m_dlgGetDlg.show();



            return true;



        }



        if (sVal.equals ("&Exit"))



        {



            m_dlgGetDlg.hide();



            hide();



            return true;



        }



    }



    return false;



}

Recompile your project, and then execute it. Now the UIApp applet should actually do something. When it starts, the frame window and the dialog box are displayed. When you enter some text in the text field and click OK, the text value of the frame is set to the same value as in the text field of the dialog box. If you change the text in the frame, and then select Edit | Get Data from the menu, the dialog box is displayed again. You can then change the text in the dialog box and continue to repeat the procedures. From the menu of the frame, you can also select File | Exit to close the windows.

Window Events


Today, you learned about writing your own event handler methods, and you noted that the Event class defines many standard events for which you can test. Window events are part of that list, so if you use windows, these events might be of interest to you. Table 13.2 shows those events.

Table 13.2. Window events from the Event class.

WINDOW_DESTROY Generated when a window is destroyed (for example, when the browser or applet viewer has quit)
WINDOW_EXPOSE Generated when the window is brought forward from behind other windows
WINDOW_ICONIFY Generated when the window is minimized to an icon
WINDOW_DEICONIFY Generated when the window is restored from an icon
WINDOW_MOVED Generated when the window is moved

More UI Events


To intercept a specific event, you need to test for that event's ID. The available IDs are defined as class variables in the Event class, so you can test for them by name. You learned about some of the basic events today; Table 13.3 shows additional events that might be useful to you for some of the more common components; other events can be found in the InfoView topic "1.14 Class Event."

Table 13.3. Additional events.

Event ID What It Represents
ACTION_EVENT Generated when a UI component action occurs
KEY_ACTION Generated when text field action occurs
LIST_DESELECT Generated when an item in a scrolling list is deselected
LIST_SELECT Generated when an item in a scrolling list is selected
SCROLL_ABSOLUTE Generated when a scrollbar's box has been moved
SCROLL_LINE_DOWN Generated when a scrollbar's bottom or left endpoint (button) is selected
SCROLL_LINE_UP Generated when a scrollbar's top or right endpoint (button) is selected
SCROLL_PAGE_DOWN Generated when the scrollbar's field below (or to the left of) the box is selected
SCROLL_PAGE_UP Generated when the scrollbar's field above (or to the right of) the box is selected

Summary


Today you finished exploring applets and the AWT by learning about two important concepts. First, you learned about windows, frames, menus, and dialogs, which enable you to create a framework for your applets—or enable your Java applications to take advantage of applet features.

The second topic was how to handle menu actions and events. Most of the time, all you need to do is stick the right method in your applet code, and your applet intercepts and handles that method. The following are some of the basic events you can manage in this way:


Q&A


Q: When I created a dialog box resource, I noticed that a new button bar displayed. What's it used for?

A: The button bar that appears at the bottom of the screen has a number of alignment options that make it easy to align the buttons on your newly created dialog box. Options are also available for sizing the dialog box buttons. At least one control (and in several cases two or more controls) must be selected before the option(s) become active. Experiment with the options on the button bar. The option on the extreme left of the toolbar (it looks like a light switch) that might be a particular interest allows you to run the dialog box to test its appearance and behavior.

Q: On the Controls Toolbar, I saw a number of controls I didn't use. What are they used for?

A: There are a number of options available on the Controls Toolbar that make designing a dialog box very easy. The options allow you to easily add check boxes, radio buttons, or a combination boxes with drop-down lists. There are options for adding scroll bars, hot keys, and sliders. Pictures and animation can also be added using options provided on this rather extensive toolbar. Experiment with the many options and see what you can come up with.

Q: The pop-up windows I create using VJ++ display a warning in my browser that an applet window is running. What does this mean and why does this warning display?

A: Depending on the browser that's used, the applet warning varies, however, the purpose for the warning is the same. The warning displays to tell you (and any users of your applet) that the window being displayed was generated by an applet and not by the browser itself. This security feature is a good thing; it keeps an applet programmer from popping up a window that masquerades as a browser window and, for example, asks users for their passwords. There's nothing you can do to hide or obscure the warning.

Q: What good is having a File dialog box if you can't read or write files from the local file system?

A: Depending on the browser, applets often can't read or write from the local file system, but you can use AWT components in Java applications as well as applets, and the File dialog box is very useful for applications.

Q: The mouseDown() and mouseUp() methods seem to apply to only a single mouse button. How can I determine which button on the mouse has been pressed?

A: At the moment, you can't. AWT assumes that you're using a one button mouse , or if you have a mouse with multiple buttons, that it's using only the left one. Although this assumption limits the kinds of actions you can perform in your applet, it does provide a cross-platform solution. Different systems have different mice, so writing your applet to do something specific with the right mouse button isn't a good idea if the people running your applet are using Macintoshes and have only a one button mouse. If you really want to have different mouse actions perform different things, test for modifier keys (Alt | Shift) in your mouseDown() and mouseUp() methods.

Previous Page Page Top TOC Next Page