August 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Focus Events, Click Events, and Drag-and Drop in AJAX Using the GWT and Java

  • March 27, 2007
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

Java Programming Notes # 2556


Preface

General

Historically, the development of Ajax web applications has been a complex process. This is due mainly to the requirement to learn and use a variety of technologies, such as HTML, JavaScript, XML, ASP.NET, Java servlets, various scripting languages, etc.

Recently several products have emerged that make it possible to develop Ajax web applications using the Java development environment. Some use exclusively Java, while others use mainly Java.  I have discussed several of these new programming environments in previous lessons in this series (see Resources).

The Google Web Toolkit (GWT)

One development environment that allows you to use mainly Java for the development of web applications is the Google Web Toolkit (GWT) (see Resources and Download), which is the primary topic of this tutorial lesson.

Most of the client-side code for a GWT Ajax application can be written in Java.  There is no requirement to write JavaScript code.

Fourth in a series

This is the fourth lesson in a series designed to help you learn how to use the GWT to create rich Ajax web applications.  You will find links to the previous lessons in the series in the Resources section.

Purpose of the tutorial

The main purpose of the tutorial is to teach you how to write the Java code necessary to perform drag-and-drop operations in AJAX using the GWT and Java.  In addition, I will teach you hot to use of the FocusListener and ClickListener interfaces.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.  You may also find it useful to open a third browser window at the Resources section near the end of the document.  That will make it easy for you to open those resources when they are mentioned in the text.

Figures

  • Figure 1. The application GUI at startup.
  • Figure 2. The application GUI after clicking the TextBox.
  • Figure 3. The application GUI after clicking the Right button.
  • Figure 4. Gaining the focus with the tab key.
  • Figure 5. Firing a click event with the space bar.
  • Figure 6. The application GUI at startup.
  • Figure 7. Firing a click event with the space bar.
  • Figure 8. Results for mouse events.
  • Figure 9. Application GUI for GwtApp018 at startup.
  • Figure 10. Application GUI after dragging the custom button.

Listings

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials.  You will find a consolidated index at www.DickBaldwin.com.

General background information

Focus events

What is focus?

No matter how many applications are running concurrently on a computer and no matter how many GUIs are showing on the desktop, only one component in one GUI belonging to one application can respond to the keyboard at any point in time.  The component that can respond to keyboard input is said to have the focus.

Focus event handling has a long history

Focus events have been available in standard Java since at lease version 1.1 in 1997. With the release of J2SE version 1.4, Sun completely revamped the focus subsystem.  Because they added a large number of new capabilities at that time, dealing with focus in standard Java became much more difficult with the release of J2SE version 1.4.

Some resources on focus event handling

For an explanation of what is currently possible and an indication of the complexity of the Focus subsystem in standard Java, see "The AWT Focus Subsystem" in Resources.

For additional information on the use of the revamped focus subsystem in standard Java, see the following tutorials in Resources:

  • "Focus Traversal Policies in Java Version 1.4"
  • "Focusability in Java Version 1.4"
  • "Changing Focus Traversal Keys in Java V1.4"

Something a little less complicated

For a somewhat less complex discussion of focus and the handling of focus events, see my early tutorial named "Event Handling in JDK 1.1, Requesting the Focus" in Resources.

That early tutorial was published long before the release of the revamped focus subsystem in version 1.4.  However, much of the material in that tutorial maps directly into the GWT focus subsystem, which is much simpler than the revamped focus subsystem in standard Java.  The focus subsystem in the GWT looks a lot more like the early focus subsystem in standard Java than the revamped focus subsystem in J2SE v1.4.

Handling focus events

The programming process for handling focus events in the GWT is essentially the same as the process in standard Java except for the names of a couple of methods and the types of parameters that those methods receive.

Focus event handlers in standard Java
The focus event handling methods and parameter types in standard Java are:
  • void focusGained(FocusEvent e)
  • void focusGained(FocusEvent e)
The programming process

The programming process for handling focus events in the GWT consists of the following steps:

  • Define a class that implements the FocusListener interface.
  • Override and provide concrete definitions for the following abstract methods that are declared in the interface.  The behavior that results from the firing of a focus event is established by the code in the overridden methods.
    • void onFocus(Widget sender)
    • void onLostFocus(Widget sender)
  • Instantiate an object of the new class and register it on the GUI component that is expected to fire the focus event.

The GWT API Map
The GWT API Map in Resources is a very helpful tool for supplementing the javadocs when searching for this kind of information.
Which GUI components can fire focus events?

Any GUI component that either defines or inherits the registration method named addFocusListener can fire focus events.  This includes at least the following GWT GUI components and possibly some others that I overlooked in my search:

  • ListBox
  • Frame
  • PasswordTextBox
  • TextBox
  • TextArea
  • Button
  • Checkbox
  • RadioButton
  • FocusPanel
  • Tree

The sample applications in this lesson will concentrate on focus events fired by Button, TextBox, and FocusPanel objects.

Focus events often occur in pairs

Recall that only one component can have the focus at any point in time.  When a component gains the focus, it will fire an onFocus event as a result of gaining the focus.  If some other component had the focus before, it will fire an onLostFocus event as the result of losing the focus.  Therefore, focus events often occur in pairs.

Don't always occur in pairs

Be aware, however, that there are situations where one component can lose the focus without another component (in the same application at least) gaining the focus.  Similarly, there are situations where a component can gain the focus but there was no component in the same application that previously had the focus.  An example of this latter situation is the case where the application first starts running and a component gains the focus at startup.  Since the application was not previously running, it is not possible that some component belonging to that application could have had the focus.

A visual indication of focus

Most GUI components provide a visual indication to the user that the component has the focus.  (Note the sidebar later in this document that discusses an apparent bug in the GWT regarding the visual indication of focus, or the lack thereof.)  The actual visual indicator will depend on the look and feel ascribed to the components being used.

Perhaps the most consistent visual indication of focus among all of the GUI components across many operating systems is the existence of a blinking cursor in components that allow the user to enter text into the component.  Just about everyone who uses a computer recognizes the blinking cursor as an indication that it is OK to enter text.  You will see some visual indications of focus in the sample applications in this tutorial.

Focus traversal

In most cases, repeatedly pressing the tab key will cause the focus to move among the components in a GUI according to a specified traversal path.  Also, in most cases, holding down the Shift key and repeatedly pressing the tab key will cause the focus to move among the same components in the reverse of the specified traversal path.

Two ways to establish the traversal path

Standard Java is more complex
If you have looked into the Sun document named "The AWT Focus Subsystem" (see Resources), you have probably noticed that the techniques for establishing the traversal path in post-v1.4 standard Java are much more sophisticated and much more complicated than those described here for the GWT.  The techniques described here for the GWT are very similar to those that existed for pre-v1.4 standard Java.
There appear to be at least two ways for the programmer to establish the focus traversal path in the GWT.  The most straightforward way is to allow the traversal path to be established automatically on the basis of the order in which the components are placed in their container.

The setTabIndex method

A more complicated way of establishing the traversal path is to invoke a method named setTabIndex on each component in the GUI passing an int value as a parameter to the method.  According to the GWT documentation, this

"Sets the widget's position in the tab index. If more than one widget has the same tab index, each such widget will receive focus in an arbitrary order. Setting the tab index to -1 will cause this widget to be removed from the tab order."

Having set a tab index value on each component, repeatedly pressing the tab key will cause the focus to move among the components in increasing numeric tab-index order.  Holding down the Shift key while repeatedly pressing the tab key will reverse the traversal path.

Click events

What is a click event?

A click event is an event that is fired by a component to indicate that a specific action has occurred with respect to the component.  The most common way to cause a component to fire a click event is to click it with the mouse (hence the interface name addClickListener and the method name onClick).  In addition, some components can fire click events as a result of certain keyboard actions while the component has the focus.

Two examples of keyboard actions and click events

For example, pressing the space bar when a Button object has the focus will cause the button to fire a click event in the GWT and will cause the button to fire an ActionEvent in standard Java.  (A click event in the GWT is analogous to an action event in standard Java.)

On the other hand, pressing the Enter key when a standard Java TextField object has the focus will cause it to fire an ActionEvent, but pressing the Enter key when a GWT Textbox object has the focus will not cause it to fire a click event.  (The similarity between the two breaks down in this case.)

ActionEvent handling in standard Java
Click events in the GWT are analogous to Action events in standard Java.  The programming process for handling Action events consists of the following steps:
  • Define a class that implements the ActionListener interface.
  • Override and provide a concrete definition for the following abstract method that is declared in the interface.  The behavior that results from the firing of an Action event is established by the code in the overridden method.
    • void actionPerformed(ActionEvent e)
  • Instantiate an object of the new class and register it on the GUI component that is expected to fire the Action event.
Handling click events

The programming process for handling click events in the GWT is essentially the same as the process in standard Java except for the name of the interface, the name of the single event handling method, and the type of parameter that the event handling method receives. 

The programming process

The programming process for handling click events in the GWT consists of the following steps:

  • Define a class that implements the ClickListener interface.
  • Override and provide a concrete definition for the following abstract method that is declared in the interface.  The behavior that results from the firing of a click event is established by the code in the overridden method.
    • void onClick(Widget sender)
  • Instantiate an object of the new class and register it on the GUI component that is expected to fire the click event.

Which GUI components can fire click events?

Any component that either defines or inherits the registration method named addClickListener can fire a click event.  This includes at least the following GWT GUI components and possibly some others that I overlooked during my search:

  • ListBox
  • Frame
  • PasswordTextBox
  • TextBox
  • TextArea
  • Button
  • Checkbox
  • RadioButton
  • FocusPanel
  • Hyperlink
  • Image
  • Label
  • HTML

The first sample application in this lesson will concentrate on click events fired by Button and TextBox objects.

Drag-and-drop

Credit to Mr. Eric Sessoms

The GWT drag-and-drop sample application in this lesson is not a creation of my own design.  Rather, the technical information and the ideas behind the sample application were taken (with written permission via Email) from the original author whose name is Eric Sessoms.  (See Drag and Drop using the GWT in Resources.)

Will defer to Eric Sessoms blog for background information

Mr. Sessoms does a much better job than I could do with regard to the General background information on performing drag-and-drop with the GWT.  Therefore, I will refer you to his blog for that information.  I will content myself with attempting to explain how and why the sample application behaves as it does.

Depends heavily on handling mouse events

I will point out, however, that the drag-and-drop technique described herein depends heavily on the use of mouse events, the MouseListener interface, and the MouseListenerAdapter class.  If you haven't already studied my earlier lesson named "Event driven programming in AJAX using the GWT and Java" (see Resources) where I explain the handling of mouse events in some detail, now would be a good time to do so.

Preview

Three sample GWT web applications

I will present and explain three sample GWT applications in this lesson.  The names of the three applications are shown in the following list.  This list also shows the primary topic that each application is designed to illustrate.

  • GwtApp016 - Focus events and click events.
  • GwtApp017 - Creating a custom button component that fires mouse events.
  • GwtApp018 - Performing drag-and-drop operations on the custom button component.

Discussion and sample code

Complete program listings

I will discuss the code for the following applications in fragments.  A complete listings of each application is provided in Listing 22 through Listing 27 near the end of the lesson.

The HTML host pages

The HTML host pages used for the applications in this lesson are essentially the same as those used for the applications in my earlier tutorials.  Therefore, I won't discuss them in this lesson.  However, a complete listing of each HTML host page is provided in Listing 22 through Listing 27 along with the Java source code for the application.

GwtApp016 - Focus events and click events

The application GUI at startup

Figure 1 shows a screen shot of the application named GwtApp016 at startup when running in Internet Explorer 6.

Figure 1. The application GUI at startup.

The row of Label objects shown at the bottom in Figure 1 contains column headers for three columns that will contain the following information:

  • Which component (if any) lost the focus?
  • Which component (if any) gained the focus?
  • Which component (if any) fired a click event?

There is no information showing under those column headers at startup because no component has yet gained the focus, no component has yet lost the focus, and no component has yet fired a click event.

The application GUI after clicking the TextBox

Figure 2 shows the state of the GUI after the user started the application running and then clicked the TextBox object once with the mouse.

Figure 2. The application GUI after clicking the TextBox.

The information in the middle column shows that this caused the text box to gain the focus.  However, the left column is still blank because at this point, no component lost the focus because no component had the focus at startup.

The right column in Figure 2 shows that the text box fired a click event when the user clicked the text box with the mouse.

The application GUI after clicking the Right button

Figure 3 shows the state of the GUI as a result of the user clicking the Right button while the text box had the focus.

Figure 3. The application GUI after clicking the Right button.

Why no visual indication of focus?
Note that even though the Right button has the focus in Figure 3, the button is not displaying a visual indication of focus.  This problem manifests itself when the application is run in either IE6 or hosted mode.  However, the problem does not manifest itself when the application is run in Firefox.  A visual indication of focus appears as it should when the application is run in Firefox.  This strongly suggests that this is a bug in the GWT, and a fairly serious one from a user perspective.
The left column in Figure 3 shows that the text box lost the focus.  The middle column shows that the Right button gained the focus.  The right column shows that the Right button also fired a click event as a result of the user clicking the Right button with the mouse.

Gaining the focus with the tab key

Figure 4 shows the result of restarting the application and pressing the tab key repeatedly until the Right button gains the focus.

Figure 4. Gaining the focus with the tab key.

A visual indication of focus.
Note that unlike Figure 3, there is a visual indication of focus on the Right button in Figure 4.  This is what we would expect to always be the case when the button has the focus.  However, it appears that clicking the button in either IE6 or hosted mode does not cause the button to provide a visual indication of focus, even though it clearly gains the focus.  As mentioned earlier, this is not a problem in Firefox.
The focus traversal path

Because of the order in which the components were placed in their container, the forward focus traversal path for the tab key is from left to right across the two buttons and the text box.  Thus, when the Right button gained the focus, the text box lost the focus as shown by the information in the two left columns in Figure 4.

No click event showing

Note that the right column in Figure 4 is still blank because no click events have been fired since the application was restarted.

Firing a click event with the space bar

Figure 5 shows the result of pressing the space bar while the Right button has the focus as shown in Figure 4.

Figure 5. Firing a click event with the space bar.

A click event was fired

The right column in Figure 5 shows that a click event was fired by the Right button as a result of pressing the space bar on the keyboard while the Right button had the focus.

Description of the application

This application demonstrates FocusListener, ClickListener, and tool tips.

It places two Button objects and a TextBox object in a HorizontalPanel object as shown in Figure 1.

Listeners

The application defines inner classes (not anonymous inner classes) that implement listener interfaces.  One inner class implements the FocusListener interface and the other class implements the ClickListener interface.

The application instantiates and registers FocusListener and ClickListener objects on each of the buttons and on the text box.

Titles for tooltips

The application also sets a title on each button and on the text box to cause each of them to show tooltips whenever the mouse pointer hovers over the component.  (Figure 2 shows a tooltip immediately below the Right button.  Note however, that the screen shot did not capture the image of the mouse pointer in Figure 2.)

A simple table to display event information

As shown in Figure 3, the application uses HorizontalPanel objects, Label objects, and a VerticalPanel object to create a simple table that shows which components fired events of the following types (going from left to right in Figure 3):

  • onLostFocus
  • onFocus
  • onClick

Not always reliable
Note: The table does not display reliable focus lost and focus gained information in those cases where the focus leaves all three of the components shown in Figure 3.
The tooltip titles are also used to identify the components that fired each specific event when the information is displayed in the table.

Application testing

The application was tested using J2SE 5.0, GWT version 1.2.22, and jakarta-tomcat-5.0.27 running as a localhost server under WinXP.

Beginning of the class definition

Listing 1 shows the beginning of the class definition and the beginning of the onModuleLoad method for the application named GwtApp016.

Listing 1. Beginning of the class definition for GwtApp016.

package GwtApp.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.*;

public class GwtApp016 implements EntryPoint{
  //These three labels are used for text output. They are
  // declared as instance variables to make them accessible
  // by the methods in the inner classes.
  private Label label20;
  private Label label21;
  private Label label22;

  //This is the entry point method.
  public void onModuleLoad(){
    //Create the basic structure of the GUI.
    HorizontalPanel topPanel = new HorizontalPanel();
    topPanel.setSpacing(5);
    
    HorizontalPanel middlePanel = new HorizontalPanel();
    middlePanel.setSpacing(5);
    
    HorizontalPanel bottomPanel = new HorizontalPanel();
    bottomPanel.setSpacing(5);    
    
    VerticalPanel vertPanel = new VerticalPanel();
    vertPanel.add(topPanel);
    vertPanel.add(middlePanel);
    vertPanel.add(bottomPanel);

I have explained code similar to the code in Listing 1 in numerous sample applications in previous lessons.  Therefore, there should be no need for a further explanation of the code in Listing 1 beyond the explanation provided by the embedded comments.

Populate the top HorizontalPanel object

Listing 2 populates the top HorizontalPanel object with two Button objects and a TextBox object.

Listing 2. Populate the top HorizontalPanel object.

    //Populate the topPanel with two buttons and a TextBox
    Button button00 = new Button("Left");
    TextBox textBox = new TextBox();
    textBox.setText("TextBox");
    Button button02 = new Button("Right");

    //Make the buttons the same width.
    button00.setWidth("50px");
    button02.setWidth("50px");

    //Add the three components to the horizontal panel
    topPanel.add(button00);
    topPanel.add(textBox);
    topPanel.add(button02);

Once again, there is nothing new in Listing 2, so I won't discuss it further.

Some more common code

Listing 3 populates the middle and bottom panels using code similar to the code that you have seen in numerous previous sample applications.  Therefore, I won't discuss the code in Listing 3 any further.

Listing 3. Some more common code.

    //Populate the middle panel with three labels. These
    // labels serve simply to explain the contents of the
    // three labels below them.
    Label label10 = new Label("Lost Focus");
    Label label11 = new Label("Gained Focus");
    Label label12 = new Label("Was Clicked");
    label10.setWidth("85px");
    label11.setWidth("85px");
    label12.setWidth("85px");
    middlePanel.add(label10);
    middlePanel.add(label11);
    middlePanel.add(label12);
    
    //Populate the bottom panel with three output labels.
    // The contents of these three labels are modified by
    // the code in the event handlers to explain the
    // events.
    label20 = new Label("");
    label21 = new Label("");
    label22 = new Label("");
    label20.setWidth("85px");
    label21.setWidth("85px");
    label22.setWidth("85px");
    bottomPanel.add(label20);
    bottomPanel.add(label21);
    bottomPanel.add(label22);

Set the tooltip text

We've finally gotten to some code that is new to this lesson.  The code in Listing 4 sets the tooltip text for each of the three components, by invoking the setTitle method on each of the components.  Invoking the setTitle method on a component in the GWT is all that is required to cause the component to display a tooltip.

Listing 4. Set the tooltip text.

    button00.setTitle("Left Button");
    textBox.setTitle("TextBox");
    button02.setTitle("Right Button");

The titles that are set in Listing 4 serve not only as tooltip text, but also serve as text identifiers for the components that gain the focus, lose the focus, and fire click events.  These text identifiers are displayed in the table shown in Figure 3.

Register listener objects

Listing 5 begins by instantiating a listener object of the inner class named FocusLstnr.  Then it registers that single common listener object on each of the buttons and on the text box.

Listing 5. Register listener objects.

    //Register a common focus listener on each button and
    // on the text box.
    FocusLstnr focusLstnr = new FocusLstnr();

    button00.addFocusListener(focusLstnr);
    textBox.addFocusListener(focusLstnr);
    button02.addFocusListener(focusLstnr);
    
    //Register a common click listener on each button and
    // on the text box.
    ClickLstnr clickLstnr = new ClickLstnr();

    button00.addClickListener(clickLstnr);
    textBox.addClickListener(clickLstnr);
    button02.addClickListener(clickLstnr);
    
    //Add the vertical panel to the browser window. The
    // vertical panel serves as a backbone and the three
    // horizontal panels serve as ribs.
    RootPanel.get().add(vertPanel);
    
  }//end onModuleLoad method

The code in Listing 5 also instantiates a common listener object of the inner class named ClickLstnr.  Then it registers that common listener object on each of the buttons and on the text box.  As a result, both a focus listener and a click listener are registered on both buttons and on the text box.

Add the VerticalPanel to the RootPanel and end the method

Finally, the code in Listing 5 adds the populated VerticalPanel object to the RootPanel, thereby completing the construction of the application GUI.

Listing 5 also signals the end of the onModuleLoad method.

Define the inner class named ClickLstnr

A member class
An inner class is also known as a member class.  (See "The Essence of OOP using Java, Member Classes" in Resources for more information.)
Listing 6 defines the inner class named ClickLstnr.  It was defined as an inner class in this application so that the interface method named onClick would have direct access to one of the three output Label objects.

As you can see, this class implements the ClickListener interface and defines the onClick method that is declared in that interface.  This is the only method that is declared in the ClickListener interface.

Listing 6. Define the inner class named ClickLstnr.

  class ClickLstnr implements ClickListener{
    public void onClick(Widget sender){
      label22.setText(sender.getTitle());
    }//end onClick
  }//end class ClickLstnr

Need to identify the source of the event

The onClick method in Listing 6 is executed any time that any of the three components fires a click event.  Therefore, it is necessary for the method to identify the component that fired the event.  Fortunately, the incoming parameter named sender of type Widget points back to the component that fired the event.

The code in Listing 6 invokes the getTitle method on that reference to get the tooltip title that was established for the component earlier.  Then it displays that title in the rightmost column in the table in Figure 3 to identify the component that fired the click event.

Define member class named FocusLstnr

Listing 7 defines the inner (member) class named FocusLstnr.  This class implements the interface named FocusListener and defines the two event handler methods declared in that class.  As before, this class was made an inner class so that the code in the each method would have direct access to the label used to display results for that method.

Listing 7. Define member class named FocusLstnr.

  class FocusLstnr implements FocusListener{
    
    public void onLostFocus(Widget sender){
      label20.setText(sender.getTitle());
    }//end onLostFocus
    //---------------------------------------------------//
    
    public void onFocus(Widget sender){
      label21.setText(sender.getTitle());
    }//end onFocus
  }//end class FocusLstnr
  //=====================================================//

}//end class GwtApp016

When are the two methods executed?

As you probably already know, one of the methods in Listing 7 is executed when a component loses the focus and fires an event whose type corresponds to the onLostFocus method.  The other method is executed when a component gains the focus and fires an event whose type corresponds to the onFocus method.

The code in each of the methods in Listing 7 is essentially the same as the code in Listing 6, except that the identification of the component that fired the event is displayed in one of the two columns on the left in Figure 3.

The end of the class

Listing 7 also signals the end of the class named GwtApp016.

At this point, you have learned much of what there is to know about the focus subsystem in the GWT.  What you have learned will be useful in understanding the next two sample applications.

A few things that you haven't learned

As indicated earlier, the GWT focus subsystem is much simpler than the focus subsystem in post-v1.4 standard Java.  However, there are a few features of the GWT focus subsystem that weren't discussed here.  You can learn about them by going to the index in the javadocs, searching for the word "focus" and reading about any interesting methods that you turn up in that process.

GwtApp017 - Creating a custom button component

Do you understand the handling of GWT mouse events?

In order to understand the material in this application, you will need to understand quite a lot about the handling of mouse events in the GWT.  I explained mouse event handling in the earlier lesson named "Event driven programming in AJAX using the GWT and Java" (see Resources).  If you haven't studied that lesson yet, I suggest that you do so at this time.

Which components can fire mouse events?

Any component that either defines or inherits the registration method named addMouseListener can fire a mouse event.  This includes the following GWT GUI components and possibly some others that I may have missed in my search:

  • Label
  • HTML
  • Image
  • FocusPanel
  • Tree

All in all, that is a rather short list, at least in comparison to the number of GUI components that can fire mouse events in standard Java.

Forcing a GUI component to fire mouse events

Other event types
This application is written around the concept of forcing a component to fire mouse events, but it could just as well have been written around the concept of forcing a component to fire click events or focus events.
What if you have a need for a GWT GUI component to fire mouse events but that component is not included in the above list?  I'm going to show you how to force a Button to fire mouse events in this application.  I will show you why you may want to do that in the next application.

Not restricted to Button objects

The technique that I will describe here is not restricted to Button objects.  You should be able to use what I am going to show you in this application to force any component to fire mouse events, click events, or focus events.

The application GUI at startup

Figure 6 shows the application GUI at startup.  The large button in Figure 6 is a custom button that fires mouse events.

Figure 6. The application GUI at startup.

The output data

The five labels below the button show the results of handling mouse events and click events that are fired by the button as the user manipulates the mouse and the keyboard with respect to the button.  Each of the labels shows the default values at startup in Figure 6.

The five labels display the following information:

  1. Whether the mouse pointer is inside or outside the area occupied by the custom button.  As you can see the default value is Out.  This label will display In when the mouse pointer is inside the custom button's area.
  2. The coordinates of the last location recorded as the mouse is moved within the area occupied by the custom button.  These coordinate values are dynamic values that continuously change as the mouse is moved within that area.  As you can see, the default coordinate values at startup are both 0.  The coordinate values are given in pixels relative to the upper left corner of the custom button.
  3. The coordinates of a point within the custom button's area where a mouse button was most recently pressed.  These coordinate values change each time the user presses a mouse button while the mouse pointer is inside the area occupied by the custom button.
  4. The identification of the component (if any) that fired the most recent click event.
  5. The identification of another component (if any) that fired the most recent click event.  The meaning of these two output values will become clearer once you understand the code that is used to create the custom button.

Firing a click event with the space bar

Figure 7 shows the result of:

  • Starting the program.
  • Repeatedly pressing the tab key until the custom button gains the focus.
  • Pressing the space bar.

Figure 7. Firing a click event with the space bar.

No mouse events

As you can see, the top three labels that are used to show the results of handling mouse events still have their default values in Figure 7.  That is because no mouse events had yet been fired when the screen shot was taken.  However, using the tab key to cause the custom button to gain the focus and then pressing the space bar caused two components to fire click events as shown by the bottom two labels.

Why two components?

It is probably time to provide a little more explanation about the two components that fired click events.  A you can see, the two components are identified in Figure 7 as:

  • Button
  • Custom Button

The custom button is actually the composite of a Button object and a FocusPanel object.  The button is wrapped in the focus panel, and the composite of the two is considered to be the custom button.  However, there are two separate components involved and each has the native ability to fire a click event.

The Button referred to in Figure 7 is the ordinary button that is wrapped in the focus panel.  The Custom Button that is referred to in Figure 7 is actually the FocusPanel that wraps the Button.  These are the two components for which click events are recorded in the bottom two labels in Figure 7.

Results for mouse events

Where is the mouse pointer?
Note that the process of capturing the screen shot in Figure 8 did not capture the image of the mouse pointer, which was pointing to the "n" when the screen shot was taken.
Figure 8 shows the result of using the mouse to point to and click on the upper-case "C" in the button caption, and then moving the mouse pointer to the right and letting it rest on the lower-case "n".

Figure 8. Results for mouse events.

How many components fired mouse events?
Unlike the click events discussed earlier, in this case only the FocusPanel that wraps the standard Button object fired mouse events, because the Button object does not have the native ability to fire Mouse Events.
Are you in or out?

The first label under the button shows that the mouse pointer was In the area occupied by the custom button when the screen shot was taken.

The Last Move Location

The second label under the button shows the coordinates of the lower-case "n", which was the location of the mouse pointer when the screen shot was taken. 

The Last Down Location

Mouse moved versus mouse dragged
The mouse-event results would have been the same if the mouse button had been held down while making the move, because unlike standard Java, the GWT makes no distinction between "mouse moved" and "mouse dragged."
The third label under the button shows the coordinates of the upper-case "C", which was the location of the mouse pointer when the mouse button was pressed and then released before moving it to the lower-case "n".

The click event

The bottom two labels show the results of the click event that was fired when the mouse button was pressed and then released.

Description of the application

This application demonstrates the creation of a custom button that can fire mouse events and otherwise behaves more or less like a standard Button component.

What is a FocusPanel?
According to the javadocs, a FocusPanel object is "A simple panel that makes its contents focusable, and adds the ability to catch mouse and keyboard events."

One way to establish the contents of a FocusPanel is to pass another object's reference as a parameter to the constructor when the panel is constructed.

Wrap a Button in a FocusPanel

The application wraps a standard Button object in a FocusPanel object to create the custom button.  An object of the FocusPanel that wraps the standard button then behaves more or less like a standard button except that it can fire mouse events in addition to click events and focus events.

Set tooltip titles

Which tooltip is displayed?
The tool tip that is displayed is the title that is set on the standard button and is not the title that is set on the custom button
The application sets titles on the standard button and the custom button in order to display tool tips when the mouse pointer hovers on the custom button.

Another use for tooltip titles

The titles are also used to identify the component that fires a click event when the mouse button is pressed in the area occupied by the custom button or when the space bar is pressed while the standard button wrapped in the FocusPanel has the focus.  When this happens, both the standard button and the custom button fire a click event.

Construction of the GUI

The application puts the custom button along with five Label objects in a VerticalPanel object as shown in Figure 6.  The labels are used to display the following output data when the user manipulates the custom button with the mouse or the keyboard:

  1. Whether the mouse pointer is inside or outside the area occupied by the custom button.
  2. The mouse pointer location as the mouse is moved within the area occupied by the custom button.
  3. The location of the mouse pointer when a mouse button is pressed within the area occupied by the custom button.
  4. The title of the standard button that fired a click event when the mouse button was pressed within the area occupied by the custom button or when the space bar was pressed while the standard button that is wrapped in the FocusPanel had the focus.
  5. The title of the custom button that fired a click event when the mouse button was pressed within the area occupied by the custom button or when the space bar was pressed while the standard button that is wrapped in the FocusPanel had the focus.

Register a mouse listener

The application registers an anonymous MouseListener object on the custom button to provide the information displayed in the first three labels described above.

Register a click listener

The application also registers an anonymous ClickListener object on the standard button to provide the information displayed in the fourth label described above.  This information demonstrates that the standard button fires click events despite the fact that it is wrapped in a FocusPanel object.

Register another click listener

Finally, the application also registers an anonymous ClickListener object on the custom button to provide the information for the fifth label.  This information demonstrates that the custom button also fires click events when the mouse button is pressed while the mouse pointer is inside the area occupied by the custom button.  It also demonstrates that the custom button fires a click event if the user presses the space bar while the standard button that is wrapped in the FocusPanel has the focus.

Firing a click event from the keyboard

When a standard button has the focus and the user presses the space bar, the standard button fires a click event.  When the standard button that is wrapped in the FocusPanel representing the custom button has the focus and the user presses the space bar, the standard button and the custom button both fire a click event.  Therefore, a click listener that is registered on the custom button will see the event.

Causing the standard button to gain the focus

One way to cause the standard button that is wrapped in the FocusPanel to gain the focus is to click it with the mouse.  That will, of course, cause both a click event and a focus event to be fired. 

Another way to cause the standard button to gain the focus is to press the tab key repeatedly.  When you do that, you will see the standard button that is wrapped in the FocusPanel gain the focus.  However, you will not see the FocusPanel gain the focus.  (The application purposely uses the setTabIndex method to disable the ability of the FocusPanel to gain the focus.)

Application testing

The application was tested using J2SE 5.0, GWT version 1.2.22, and jakarta-tomcat-5.0.27 running as a localhost server under WinXP.

Beginning the class definition for GwtApp017

The class definition for the application named GwtApp017 begins in Listing 8.

Listing 8. Begin class definition for GwtApp017.

package GwtApp.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.*;

public class GwtApp017 implements EntryPoint{

  //This is the entry point method.
  public void onModuleLoad(){
    //Create a VerticalPanel to contain a custom button
    // along with several labels that are used to display
    // output data.
    VerticalPanel vertPanel = new VerticalPanel();
    
    //Create labels used to display output data. Must be
    // final to make them accessible by an object of an
    // anonymous inner class.
    final Label inOrOut = new Label("In or Out: Out");
    final Label lastMoveLocation = 
             new Label("Last Move Location: x = 0, y = 0");
    final Label lastDownLocation = 
             new Label("Last Down Location: x = 0, y = 0");
    final Label clickSenderA = 
                          new Label("Click SenderA: None");
    final Label clickSenderB = 
                          new Label("Click SenderB: None");

The code in Listing 8 is the same as, or very similar to code that you have seen in numerous previous applications.  Therefore, no explanation beyond the embedded comments should be needed at this point.

Create the custom button

The code in Listing 9 creates a custom button that will respond to mouse events by wrapping a standard button in a FocusPanel object.

Listing 9. Create the custom button.

    Button button = new Button("Custom Button");
    button.setSize("100px","50px");
    
    FocusPanel customButton = new FocusPanel(button);
    customButton.setSize("100px","50px");

Listing 9 also forces the FocusPanel object to be the same size as the standard button that it contains.

Cause the focus to skip the FocusPanel

When you repeatedly press the tab key in this case, you don't want the focus to first land on the FocusPanel and then move to the standard button on the next press of the tab key.  Rather, you want the focus to skip the FocusPanel and land directly on the standard button.

Listing 10. Cause the focus to skip the FocusPanel.

    customButton.setTabIndex(-1);

The setTabIndex method
According to the javadocs, the setTabIndex method "Sets the widget's position in the tab index. ... Setting the tab index to -1 will cause this widget to be removed from the tab order."
The code in Listing 10 causes the focus to skip the FocusPanel and go straight to the button that is wrapped in the FocusPanel.

Miscellaneous code

The code in Listing 11 is straightforward and shouldn't require an explanation beyond that provided by the embedded comments.

Listing 11. Miscellaneous code.

    //Set titles that are used for tootips and are also
    // used to identify the source of click events.
    button.setTitle("Button");
    customButton.setTitle("Custom Button");

    //Add the components to the vertical panel.
    vertPanel.add(customButton);
    vertPanel.add(inOrOut);
    vertPanel.add(lastMoveLocation);
    vertPanel.add(lastDownLocation);
    vertPanel.add(clickSenderA);
    vertPanel.add(clickSenderB);
    
    //Add the vertical panel to the browser window.
    RootPanel.get().add(vertPanel);

Register a mouse listener on the custom button

Listing 12 registers a mouse listener on the custom button by defining and instantiating an object of an anonymous inner class that extends the class named MouseListenerAdapter.

Listing 12. Register a mouse listener on the custom button.

    //Register a MouseListener on the custom button.
    customButton.addMouseListener(
      new MouseListenerAdapter(){
        public void onMouseEnter(Widget sender){
          inOrOut.setText("In or Out: In");
        }//end onMouseEnter
        //-----------------------------------------------//
        
        public void onMouseLeave(Widget sender){
          inOrOut.setText("In or Out: Out");
          
          //Clear the clickSender labels when the mouse
          // pointer moves out of the area occupied by the
          // custom button to prepare for displaying the
          // results of the next click event.
          clickSenderA.setText("Click SenderA: None");
          clickSenderB.setText("Click SenderB: None");
        }//end onMouseLeave
        //-----------------------------------------------//
        
        public void onMouseMove(Widget sender,int x,int y){
          lastMoveLocation.setText(
            "Last Move Location: x = " + x + ", y = " + y);
        }//end onMouseMove
        //-----------------------------------------------//
        
        public void onMouseDown(Widget sender,int x,int y){
          lastDownLocation.setText(
            "Last Down Location: x = " + x + ", y = " + y);
        }//end onMouseMove
        //-----------------------------------------------//
      }//end constructor
    );//end addMouseListener

By now, the code in Listing 12 should be "old stuff" to you.  If it isn't, see the earlier lesson named "The Essence of OOP using Java, Anonymous Classes" in Resources.

Register click listeners on the standard button and the custom button

Listing 13 registers click listeners on the standard button and the custom button.

Listing 13. Register click listeners on the standard button and the custom button.

    //Register a ClickListener on the standard button. This
    // listener demonstrates that you can still receive
    // click events from the standard button despite the
    // fact that it is wrapped in a FocusPanel object.
    button.addClickListener(
      new ClickListener(){
        public void onClick(Widget sender){
          clickSenderA.setText(
                    "Click SenderA: " + sender.getTitle());
        }//end onClick
      }//end constructor
    );//end addClickListener
    //===================================================//
    
    //Register a ClickListener on the custom button. This
    // listener demonstrates that you can also receive
    // click events from the custom button.
    customButton.addClickListener(
      new ClickListener(){
        public void onClick(Widget sender){
          clickSenderB.setText(
                    "Click SenderB: " + sender.getTitle());
        }//end onClick
      }//end constructor
    );//end addClickListener
    //===================================================//
    
  }//end onModuleLoad method
  //=====================================================//

}//end class GwtApp017

Once again, by now, the code in Listing 13 should also be "old stuff" to you.  If it isn't, see the earlier lesson named "The Essence of OOP using Java, Anonymous Classes" in Resources.

End of the GwtApp017 class

Listing 13 also signals the end of the definition of the class named GwtApp017, and the end of the discussion of the application having the same name.

GwtApp018 - Drag-and-drop on a custom button component

Application GUI for GwtApp018 at startup

Figure 9 shows the application GUI at startup.

Figure 9. Application GUI for GwtApp018 at startup.

The custom button
The custom button used in this application is the same as the custom button used in the earlier application named GwtApp017.
The GUI for this application is fairly simple.  It consists of a custom button that can be dragged using the mouse along with a couple of labels that were purposely placed there to show what happens when the component being dragged encounters another component.

Application GUI after dragging the custom button

Figure 10 shows a screen shot of the application GUI after the custom button has been dragged down the screen far enough to encounter the two Label objects.

Figure 10. Application GUI after dragging the custom button.

As you can see, the custom button in its new location appears to be on top of one of the Label objects and under the other Label object.  I will explain how this comes about once we get into the code.

Description of the application

This application demonstrates the use of mouse events to perform a drag-and-drop operation on a custom button component.

Not very smooth in hosted mode
The drag operation is not very smooth when the application is run in hosted mode.  However, it runs smoothly in both Firefox 1.5.0.8 and Internet Explorer 6.0.29
Create a custom button

The application creates a custom button that can fire mouse events and otherwise behave more or less like a standard button.  The ability to fire mouse events is critical to the operation of the drag-and-drop algorithm implemented by this application.

Wrap a standard Button in a FocusPanel

A standard Button object is wrapped in a FocusPanel object to create the custom button.  The FocusPanel object then behaves more or less like a standard button except that it can fire mouse events in addition to click events and focus events.

Application testing

The application was tested using J2SE 5.0, GWT version 1.2.22, and jakarta-tomcat-5.0.27 running as a localhost server under WinXP.

Begin the class definition

The class definition begins in Listing 14.

Listing 14. Begin the class definition for GwtApp018.

package GwtApp.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.*;
import com.google.gwt.user.client.ui.*;

public class GwtApp018 implements EntryPoint{

  //This is the entry point method.
  public void onModuleLoad(){
    
    //Create a custom button that will fire mouse events
    // by wrapping a standard button in a FocusPanel.
    // Force the FocusPanel to be the same size as the
    // standard button.
    Button button = new Button("Custom Button");
    button.setSize("120px","50px");
    FocusPanel customButton = new FocusPanel(button);
    customButton.setSize("120px","50px");

    //Cause the focus to skip the FocusPanel and go
    // straight to the button that is wrapped in the
    // FocusPanel.
    customButton.setTabIndex(-1);

There is nothing new in Listing 14 so I won't discuss it further.

Define an anonymous class

Listing 15 shows the beginning of the code that defines an anonymous MouseListener class and registers an anonymous MouseListener object instantiated from the anonymous class on the custom button. The methods of this class will be used to perform a drag-and-drop operation on the custom button.

Listing 15. Define an anonymous class.

    customButton.addMouseListener(
      new MouseListenerAdapter(){
        
        //Declare some local working varibles.
        private boolean dragging;
        private int     xOffset;
        private int     yOffset;

The code in Listing 15 declares some local working variables that will be used later to implement the drag-and-drop operation on the custom button.

The setCapture method

Listing 16 shows the beginning of the onMouseDown method and the invocation of the static setCapture method of the Dom class.

Listing 16. The setCapture method.

        public void onMouseDown(Widget sender,int x,int y){
          DOM.setCapture(sender.getElement());

The use of the Dom class is new to this lesson.  According to the javadocs, the Dom class:

"provides a set of static methods that allow you to manipulate the browser's Document Object Model (DOM). It contains methods for manipulating both elements and events."

Many static methods

The Dom class defines dozens of static methods, including the method named setCapture.  According to the javadocs, the setCapture method:

"Sets mouse-capture on the given element. This element will directly receive all mouse events until releaseCapture(Element) is called on it."

Capturing the custom button

The custom button in this application is captured for dragging when any of the three mouse buttons is pressed while the mouse pointer is inside the area occupied by the custom button.  Note, however, that pressing any mouse button other than the left button may also cause browser-specific behavior associated with the button to occur.

A somewhat complicated discussion

You need to be aware that at this point, the discussion fuses the concepts of Java objects and HTML elements.  This is because the Java source code is ultimately compiled into JavaScript code that acts on HTML elements.

What Java object?
I suppose that in reality, the Java object that fires the onMouseDown event mentioned here never really exists.  The Java source code is compiled directly into JavaScript code before the application is executed and Java objects don't exist unless Java source code is compiled and executed under control of a Java virtual machine.  Having thought about and talked about Java objects for years, I find it a little difficult to wrap my mind around the concept of writing Java source code that will never be executed by a Java virtual machine but will still result in a program that executes and behaves the way I expect it to behave.  Those folks at Google are pretty smart.
Capturing an HTML element

Invocation of the setCapture method in Listing 16 sets mouse-capture on the HTML element that is represented by the Java object that fired the onMouseDown event.

Receive all mouse events

As described earlier, the specified element (the custom button in this case) will directly receive all mouse events until the method named releaseCapture is called on it.  (The releaseCapture method will be called later in the onMouseUp event handler method.)

Stop receiving all mouse events

In other words, when the user releases the mouse button to drop the custom button in a new location, this will cause the custom button to fire an onMouseUp event, the releaseCapture method will be called on the custom button, and the custom button will no longer receive all mouse events.

Getting back to the getElement method...

Now let's get back to the getElement method used in Listing 16.  According to the javadocs, the Element object returned by the getElement method provides an opaque handle to a native DOM Element when the Java code is compiled into JavaScript later.

Why did I set mouse event capture?

In this case, the mouse event capture feature was set so that the custom button will not lose the mouse events if it is dragged under another component.  For example, if you disable the statement in Listing 16 and run the application, the custom button will sometimes get stuck when you drag it under the Bottom Obstacle label shown in Figure 10.

Remaining code in the onMouseDown method

Listing 17 shows the remaining code in the onMouseDown event handler method.

Listing 17. Remaining code in the onMouseDown method.

          xOffset = x;
          yOffset = y;

          dragging  = true;
        }//end onMouseDown

Listing 17 records the location of the mouse pointer relative to the upper-left corner of the custom button when the mouse button is pressed.  These two values will be needed later to determine the absolute location of the custom button as it is dragged across the screen.

Listing 17 also set the dragging flag to indicate that a drag operation is underway.  This flag will be tested later by the onMouseMove method.

Implement the actual drag operation

Listing 18 shows the beginning of the onMouseMove event handler method.  This is the method that actually implements the operation of dragging the custom button across the screen.

Listing 18. Implement the actual drag operation.

        public void onMouseMove(Widget sender,int x,int y){
          if (dragging){
            int xAbs = x + sender.getAbsoluteLeft();
            int yAbs = y + sender.getAbsoluteTop();

The two statements in Listing 18 (and other statements to follow) are executed only if a drag operation is in progress as indicated by the state of the dragging flag.

The two statements in Listing 18 compute the absolute location of the mouse pointer relative to the upper-left corner of the browser window by adding the x and y coordinate offset values (relative to the upper left corner of the custom button) to the absolute coordinate values of the upper left corner of the custom button.

Redraw the custom button in a new location

As the user attempts to move the mouse across the custom button, the custom button attempts to fire a series of onMouseMove events.  However, each time an onMouseMove event is fired, the custom button is redrawn in a new location slightly displaced from its previous location by the code in Listing 19.  This causes the upper left corner of the custom button to maintain the same distance and direction from the mouse pointer that it had when the mouse button was first pressed to begin the dragging operation.

Listing 19. Redraw the custom button in a new location.

            ((RootPanel)sender.getParent()).
                   setWidgetPosition(
                     sender,xAbs - xOffset,yAbs - yOffset);
          }//end if
        }//end onMouseMove

Thus, the purpose of the statement in Listing 19 is to relocate the custom button to a new position determined by the absolute location of the mouse pointer each time an onMouseMove event is fired.

How does this work?

The sender is the object that fired the onMouseMove event, which is the custom button in this case.

When getParent is invoked on the reference to the custom button, a reference to the container of the custom button is returned as type Widget(In this case, the container of the custom button is the RootPanel object.)

Moving the custom button to a new location

The custom button is relocated as described above by invoking the setWidgetPosition method on the container, passing the custom button's reference as a parameter to the method along with a specification of the coordinates of the new position.

A downcast is required

In order to invoke the setWidgetPosition method on the reference of type Widget returned by the getParent method, the reference must be downcast at least as far as AbsolutePanel, which is the class in the hierarchy where the setWidgetPosition method is defined.  However, in Listing 19, the reference is cast all the way down to RootPanel, (which is a subclass of AbsolutePanel), and is the type of the container of the custom button.

An interesting exercise.
As an interesting exercise, and also as a demonstration of the responsiveness of AJAX, start the application so as to produce a screen as shown in Figure 9.  Expand the browser to fill the entire screen.  Use the mouse to highlight a few characters in the text immediately above the custom button.

Then drag the custom button around in ovals as fast as you can to see if you can cause the mouse pointer to get ahead of the custom button or to lose the custom button. 

On my machine, which is relatively slow, I am unable to cause the mouse pointer to get ahead of, or lose the custom button running under either IE6 or Firefox.

Also note that the highlighted text remains highlighted when you do this, demonstrating that the page is not being repeatedly downloaded to cause the custom button to appear in a different location on the page.

The coordinates of the new location for the custom button

The new position for the upper-left corner of the custom button is computed by subtracting the offset coordinates of the mouse pointer (relative to the upper-left corner of the custom button) from the absolute coordinates of the mouse pointer relative to the upper-left corner of the RootPanel.  The RootPanel completely fills the browser window.  Therefore, these new coordinates specify the new position relative to the upper left corner of the browser window as well.

End of the onMouseMove method

Listing 19 also signals the end of the onMouseMove event handler method.

The onMouseUp method

The onMouseUp method is shown in its entirety in Listing 20.

Listing 20. The onMouseUp method.

        public void onMouseUp(Widget sender,int x,int y){
          DOM.releaseCapture(sender.getElement());
          dragging = false;
        }//end onMouseUp
        //-----------------------------------------------//

      }//end constructor
    );//end addMouseListener

When the user releases the mouse button, the custom button has been relocated to the new location by the code in Listing 19.

For the reasons described earlier, the code in Listing 20 invokes the releaseCapture method on the custom button.

Listing 20 also sets the dragging flag to false to indicate that the drag operation is terminated.

End of anonymous class definition

Listing 20 also signals the end of the definition of the anonymous class that began in Listing 15.

Add two labels as drag obstacles

Listing 21 adds two Label objects to the GUI to illustrate what happens when a component that is being dragged physically encounters another component in the same space.

Listing 21. Add two labels as drag obstacles.

    //Add a label.
    RootPanel.get().add(new Label("Top Obstacle"),75,200);
    
    //Add the custom button to the browser window.
    RootPanel.get().add(customButton);
    
    //Add another label.
    RootPanel.get().add(new Label(
                                "Bottom Obstacle"),75,225);
    
  }//end onModuleLoad method
  //=====================================================//

}//end class GwtApp018

Who's on top?
Whether a component that is being dragged passes over or under another component depends on the order in which they are added to the RootPanel.  The component being dragged will pass over those components added to the RootPanel before the component being dragged was added, and will pass under those components added to the RootPanel after the component being dragged was added.
Behavior when encountering obstacles

Listing 21 begins by adding the Label object that reads Top Obstacle to the RootPanel, which places it in the browser window as shown in Figure 9.  The custom button will pass over this Label when being dragged.

Then Listing 21 adds the custom button to the RootPanel.

After adding the custom button, Listing 21 adds another Label object that reads Bottom Obstacle to the RootPanel.  The custom button will pass under this Label when being dragged.

End of class definition for GwtApp018

Listing 21 also signals the end of the definition of the class named GwtApp018, and the end of the discussion of the application having the same name.

Only half the story

In this lesson, I taught you how to write a simple application that you can use to drag a component that fires mouse events across the browser window, changing its position coordinates from point A to point B.  Note, however that this is only half the story.  While moving components around on the screen may look impressive, in order for drag-and-drop to be really useful, there are many issues associated with the drop operation that were not addressed here.

Copy, cut, and paste
Copy, cut, and paste is what appears to take place from a functional viewpoint, but the drag-and-drop operation probably doesn't actually make another physical copy of the file.  Rather, the operation is probably implemented by manipulating pointers on the disk instead.
Dragging and dropping a file

For example, if you drag a file from one directory to another directory with the Windows operating system, you are doing much more than simply causing a small icon to move from one location on the screen to another location on the screen.  For this to be really useful, the target directory must be willing to accept and assimilate the file behind the icon, and the source directory must be willing to give it up.  In effect, such a drag and drop operation appears to execute a copy, cut, and paste operation.  In other words, the operation appears to copy the file from the original directory, cut the file out of the original directory, and paste the copy into the new directory.

Future plans regarding drag-and-drop with the GWT and Java

I plan to write a sequel to this lesson, which will teach you how to expand the drag-and-drop behavior that you learned about in this lesson to produce new behavior that is somewhat more substantive.

Run the program

I encourage you to copy the code from Listing 22 through Listing 27 into your text editor, compile it, and execute it.  Experiment with it, making changes, and observing the results of your changes.

Learn how to write web applications using this exciting new technology. Above all, enjoy the process. Programming can be fun.

Summary

In this lesson, I taught you how to write the Java code necessary to perform drag-and-drop operations in AJAX using the GWT.  Along the way, I taught you about the use of the FocusListener and ClickListener interfaces.

What's next?

Future lessons will concentrate on the Java programming techniques required to produce rich Ajax web applications using the GWT framework.  This will include discussions and explanations of such issues as the available GWT user interface components, possibly some more on event-driven programming using the GWT, possibly some more on styling, possibly some more on the behavior of drop targets, and a little about Remote Procedure Calls with the GWT. 

At this point, I'm not certain what the order of the topics in above list will be, but I have decided that the next lesson will concentrate on the use of the methods in the DOM class for a variety of purposes.

Complete program listings

A complete listing of each of the applications discussed in this lesson is provided in Listing 22 through Listing 27 below.

Listing 22. Java code for GwtApp016.

/*File GwtApp016.java
Copyright 2006, R.G.Baldwin

This application demonstrates FocusListener, ClickListener,
and tool tips.

Places two Button objects and a TextBox object in a 
HorizontalPanel object.

Defines inner classes that implement FocusListener and
ClickListener.

Registers FocusListener and ClickListener objects on each
of the two buttons and the text box.

Sets a title on each button and on the text box to cause
each of them to show tooltips.

Uses HorizontalPanel objects, Label objects, and a 
VerticalPanel object to create a simple table to show which
components fired events of the following types:

onFocus
onLostFocus
onClick

The tooltip titles are used to identify the components in
the table that fired each specific event. 

Note: The table does not display reliable focus lost and
focus gained information in those cases where the focus
leaves all three of the components.

Tested using J2SE 5.0, GWT version 1.2.22, and 
jakarta-tomcat-5.0.27 running as a localhost server
under WinXP.
**********************************************************/

package GwtApp.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.*;

public class GwtApp016 implements EntryPoint{
  //These three labels are used for text output. They are
  // declared as instance variables to make them accessible
  // by the methods in the inner classes.
  private Label label20;
  private Label label21;
  private Label label22;

  //This is the entry point method.
  public void onModuleLoad(){
    //Create the basic structure of the GUI.
    HorizontalPanel topPanel = new HorizontalPanel();
    topPanel.setSpacing(5);
    
    HorizontalPanel middlePanel = new HorizontalPanel();
    middlePanel.setSpacing(5);
    
    HorizontalPanel bottomPanel = new HorizontalPanel();
    bottomPanel.setSpacing(5);    
    
    VerticalPanel vertPanel = new VerticalPanel();
    vertPanel.add(topPanel);
    vertPanel.add(middlePanel);
    vertPanel.add(bottomPanel);
    
    //Populate the topPanel with two buttons and a TextBox
    Button button00 = new Button("Left");
    TextBox textBox = new TextBox();
    textBox.setText("TextBox");
    Button button02 = new Button("Right");
    //Make the buttons the same width.
    button00.setWidth("50px");
    button02.setWidth("50px");
    //Add the three components to the horizontal panel
    topPanel.add(button00);
    topPanel.add(textBox);
    topPanel.add(button02);
    
    //Populate the middle panel with three labels. These
    // labels serve simply to explain the contents of the
    // three labels below them.
    Label label10 = new Label("Lost Focus");
    Label label11 = new Label("Gained Focus");
    Label label12 = new Label("Was Clicked");
    label10.setWidth("85px");
    label11.setWidth("85px");
    label12.setWidth("85px");
    middlePanel.add(label10);
    middlePanel.add(label11);
    middlePanel.add(label12);
    
    //Populate the bottom panel with three output labels.
    // The contents of these three labels are modified by
    // the code in the event handlers to explain the
    // events.
    label20 = new Label("");
    label21 = new Label("");
    label22 = new Label("");
    label20.setWidth("85px");
    label21.setWidth("85px");
    label22.setWidth("85px");
    bottomPanel.add(label20);
    bottomPanel.add(label21);
    bottomPanel.add(label22);
    
    //Set tooltips on the two buttons and the text box.
    // The title not only serves as a tooltip, it also
    // serves as an identifier for the component that
    // gains the focus, loses the focus, or fires a click
    // event.
    button00.setTitle("Left Button");
    textBox.setTitle("TextBox");
    button02.setTitle("Right Button");
    
    //Register a common focus listener on each button and
    // on the text box.
    FocusLstnr focusLstnr = new FocusLstnr();
    button00.addFocusListener(focusLstnr);
    textBox.addFocusListener(focusLstnr);
    button02.addFocusListener(focusLstnr);
    
    //Register a common click listener on each button and
    // on the text box.
    ClickLstnr clickLstnr = new ClickLstnr();
    button00.addClickListener(clickLstnr);
    textBox.addClickListener(clickLstnr);
    button02.addClickListener(clickLstnr);
    
    //Add the vertical panel to the browser window. The
    // vertical panel serves as a backbone and the three
    // horizontal panels serve as ribs.
    RootPanel.get().add(vertPanel);
    
  }//end onModuleLoad method
  //=====================================================//
  
  //This is an inner class.  It was defined as an inner
  // class so that the methods would have direct access to
  // two of the three output Label objects.
  class FocusLstnr implements FocusListener{
    
    public void onLostFocus(Widget sender){
      label20.setText(sender.getTitle());
    }//end onLostFocus
    //---------------------------------------------------//
    
    public void onFocus(Widget sender){
      label21.setText(sender.getTitle());
    }//end onFocus
  }//end class FocusLstnr
  //=====================================================//
  
  //This is another inner class. It was defined as an inner
  // class so that the method would have direct access to
  // one of the three output Label objects.
  class ClickLstnr implements ClickListener{
    public void onClick(Widget sender){
      label22.setText(sender.getTitle());
    }//end onClick
  }//end class ClickLstnr
}//end class

Listing 23. HTML host page for GwtApp016.

<!---------------------------------------------------------
File GwtApp016.html
GWT host page.
Revised: 11/19/06
---------------------------------------------------------->
<html>
<head>
<title>Wrapper HTML for GwtApp016</title>
<meta name='gwt:module' content='GwtApp.GwtApp016'>

</head>

<body>
<script language="javascript" src="gwt.js"></script>
<iframe id="__gwt_historyFrame" 
              style="width:0;height:0;border:0"></iframe>

<h3>GwtApp016</h3>

<p>Demonstrates FocusListener, ClickListener, and
Tool Tips.</p>


</body>
</html>

Listing 24. Java code for GwtApp017.

/*File GwtApp017.java
Copyright 2006, R.G.Baldwin

Demonstrates the creation of a custom button that can fire 
mouse events and otherwise behaves more or less like a 
standard button.

Wraps a standard Button object in a FocusPanel object to 
create the custom button.  An object of the FocusPanel 
behaves more or less like a standard button except that it
can also fire mouse events in addition to click events and
focus events.

Sets titles on the standard button and the custom button in
order to display tool tips when the mouse pointer hovers
on the custom button.  The tool tip that is displayed is
the title that is set on the standard button and not the
title that is set on the custom button.  

The titles are also used to identify the component that 
fires a click event when the mouse button is pressed in the
area occupied by the custom button or when the space bar is
pressed while the standard button wrapped in the FocusPanel
has the focus. When this happens, both the standard button 
and the custom button fire a click event.

Puts the custom button along with five Label objects in
a VerticalPanel object.  The labels are used to display
the following output data when the user manipulates the
custom button with the mouse or the keyboard:

1. Whether the mouse pointer is inside or outside the area
occupied by the custom button.

2. The mouse pointer location as the mouse is moved within
the area occupied by the custom button.

3. The location of the mouse pointer when a mouse button is
pressed within the area occupied by the custom button.

4 and 5. The title of the component firing a click event 
when the mouse button is pressed within the area occupied 
by the custom button or when the space bar is pressed while
the standard button that is wrapped in the FocusPanel has 
the focus. (Two separate labels are used to display this 
information.)

Registers an anonymous MouseListener object on the custom
button to provide the information displayed in the first 
three labels described above.

Registers an anonymous ClickListener object on the standard
button to provide the information displayed in the fourth
label described above.  This demonstrates that the standard
button fires click events despite the fact that it is
wrapped in a FocusPanel object.

Registers an anonymous ClickListener object on the custom
button to provide the information for the fifth label. This
demonstrates that the custom button also fires click events
when the mouse button is pressed while the mouse pointer is
inside the area occupied by the custom button.  It also
demonstrates that the custom button fires a click event if
the user presses the space bar while the standard button
that is wrapped in the FocusPanel has the focus.

When a standard button has the focus and the user presses 
the space bar, the standard button fires a click event. 
When the standard button that is wrapped in the FocusPanel
representing the custom button has the focus and the user 
presses the space bar, the standard button and the custom 
button both fire a click event. Thus, a click listener that
is registered on the custom button will see the event. One
way to cause the standard button that is wrapped in the 
FocusPanel to gain the focus is to click it with the mouse.
Another way is to press the tab key several times in 
succession. When you do that, you will see the standard 
button that is wrapped in the FocusPanel gain the focus.

Tested using J2SE 5.0, GWT version 1.2.22, and 
jakarta-tomcat-5.0.27 running as a localhost server
under WinXP.
**********************************************************/

package GwtApp.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.*;

public class GwtApp017 implements EntryPoint{

  //This is the entry point method.
  public void onModuleLoad(){
    //Create a VerticalPanel to contain a custom button
    // along with several labels that are used to display
    // output data.
    VerticalPanel vertPanel = new VerticalPanel();
    
    //Create labels used to display output data. Must be
    // final to make them accessible by an object of an
    // anonymous inner class.
    final Label inOrOut = new Label("In or Out: Out");
    final Label lastMoveLocation = 
             new Label("Last Move Location: x = 0, y = 0");
    final Label lastDownLocation = 
             new Label("Last Down Location: x = 0, y = 0");
    final Label clickSenderA = 
                          new Label("Click SenderA: None");
    final Label clickSenderB = 
                          new Label("Click SenderB: None");
    
    //Create a custom button that will respond to mouse 
    // events by wrapping a standard button in a 
    // FocusPanel. Force the FocusPanel to be the same size
    // as the standard button.
    Button button = new Button("Custom Button");
    button.setSize("100px","50px");
    FocusPanel customButton = new FocusPanel(button);
    customButton.setSize("100px","50px");
    
    //Cause the focus to skip the FocusPanel and go
    // straight to the button that is wrapped in the
    // FocusPanel.
    customButton.setTabIndex(-1);
    
    //Set titles that are used for tootips and are also
    // used to identify the source of click events.
    button.setTitle("Button");
    customButton.setTitle("Custom Button");

    //Add the components to the vertical panel.
    vertPanel.add(customButton);
    vertPanel.add(inOrOut);
    vertPanel.add(lastMoveLocation);
    vertPanel.add(lastDownLocation);
    vertPanel.add(clickSenderA);
    vertPanel.add(clickSenderB);
        
    //Add the vertical panel to the browser window.
    RootPanel.get().add(vertPanel);
    
    //Register a MouseListener on the custom button.
    customButton.addMouseListener(
      new MouseListenerAdapter(){
        public void onMouseEnter(Widget sender){
          inOrOut.setText("In or Out: In");
        }//end onMouseEnter
        //-----------------------------------------------//
        
        public void onMouseLeave(Widget sender){
          inOrOut.setText("In or Out: Out");
          
          //Clear the clickSender labels when the mouse
          // pointer moves out of the area occupied by the
          // custom button to prepare for displaying the
          // results of the next click event.
          clickSenderA.setText("Click SenderA: None");
          clickSenderB.setText("Click SenderB: None");
        }//end onMouseLeave
        //-----------------------------------------------//
        
        public void onMouseMove(Widget sender,int x,int y){
          lastMoveLocation.setText(
            "Last Move Location: x = " + x + ", y = " + y);
        }//end onMouseMove
        //-----------------------------------------------//
        
        public void onMouseDown(Widget sender,int x,int y){
          lastDownLocation.setText(
            "Last Down Location: x = " + x + ", y = " + y);
        }//end onMouseMove
        //-----------------------------------------------//
      }//end constructor
    );//end addMouseListener
    //===================================================//
    
    //Register a ClickListener on the standard button. This
    // listener demonstrates that you can still receive
    // click events from the standard button despite the
    // fact that it is wrapped in a FocusPanel object.
    button.addClickListener(
      new ClickListener(){
        public void onClick(Widget sender){
          clickSenderA.setText(
                    "Click SenderA: " + sender.getTitle());
        }//end onClick
      }//end constructor
    );//end addClickListener
    //===================================================//
    
    //Register a ClickListener on the custom button. This
    // listener demonstrates that you can also receive
    // click events from the custom button.
    customButton.addClickListener(
      new ClickListener(){
        public void onClick(Widget sender){
          clickSenderB.setText(
                    "Click SenderB: " + sender.getTitle());
        }//end onClick
      }//end constructor
    );//end addClickListener
    //===================================================//
    
  }//end onModuleLoad method
  //=====================================================//

}//end class GwtApp017

Listing 25. HTML host page for GwtApp017.

<!---------------------------------------------------------
File GwtApp017.html
GWT host page.
Revised: 11/26/06
---------------------------------------------------------->
<html>
<head>
<title>Wrapper HTML for GwtApp017</title>
<meta name='gwt:module' content='GwtApp.GwtApp017'>

</head>

<body>
<script language="javascript" src="gwt.js"></script>
<iframe id="__gwt_historyFrame" 
              style="width:0;height:0;border:0"></iframe>

<h3>GwtApp017</h3>

<p>Demonstrates a custom button that fires 
mouse events.</p>


</body>
</html>

Listing 26. Java code for GwtApp018.

/*File GwtApp018.java
This application was based substantially (with written 
permission via email) on a program that was published by 
Eric Sessoms at:

http://code.nubgames.com/index.cgi/gwt/drag-and-drop-with-
the-google-web-toolkit.html

Therefore, his copyright statement follows:

 * Copyright (c)2006 Nub Games, Inc.
 * 
 * Permission is hereby granted, free of charge, to any
 * person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the
 * Software without restriction, including without
 * limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the
 * following conditions:
 * 
 * The above copyright notice and this permission notice
 * shall be included in all copies or substantial portions
 * of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
 * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.

This application demonstrates the use of mouse events to
perform a drag-and-drop operation on a custom button 
component.

The application creates a custom button that can fire 
mouse events and otherwise behave more or less like a 
standard button.  A standard Button object is wrapped in
a FocusPanel object to create the custom button. An object 
of the FocusPanel then behaves more or less like a standard
button except that it can also fire mouse events in 
addition to click events and focus events.

Note, the operation is not smooth when the application is
run in hosted mode.  However, it runs smoothly in 
Firefox 1.5.0.8 and Internet Explorer 6.0.29x

Tested using J2SE 5.0, GWT version 1.2.22, and 
jakarta-tomcat-5.0.27 running as a localhost server
under WinXP.
**********************************************************/

package GwtApp.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.*;
import com.google.gwt.user.client.ui.*;

public class GwtApp018 implements EntryPoint{

  //This is the entry point method.
  public void onModuleLoad(){
    
    //Create a custom button that will fire mouse events
    // by wrapping a standard button in a FocusPanel.
    // Force the FocusPanel to be the same size as the
    // standard button.
    Button button = new Button("Custom Button");
    button.setSize("120px","50px");
    FocusPanel customButton = new FocusPanel(button);
    customButton.setSize("120px","50px");

    //Cause the focus to skip the FocusPanel and go
    // straight to the button that is wrapped in the
    // FocusPanel.
    customButton.setTabIndex(-1);

    //Register an anonymous MouseListener object
    // instantiated from an anonymous class on the custom
    // button. The methods of this class will be used to
    // perform a drag-and-drop operation on the custom
    // button.
    customButton.addMouseListener(
      new MouseListenerAdapter(){
        
        //Declare some local working varibles.
        private boolean dragging;
        private int     xOffset;
        private int     yOffset;
          
        public void onMouseDown(Widget sender,int x,int y){
          //The custom button is captured for dragging when
          // any of the three mouse buttons is pressed
          // while the mouse pointer is inside the area
          // occupied by the custom button.  Note, however,
          // that pressing any mouse button other than the
          // left button may cause browser-specific
          // behavior associated with the button to also
          // occur.
          //The following statement sets mouse-capture on
          // the specified element. The specified element
          // will directly receive all mouse events until
          // releaseCapture(Element) is called on it later
          // in the onMouseUp method.
          //The Element object returned by the getElement
          // method provides an opaque handle to a native
          // DOM Element when the Java code is compiled 
          // into JavaScript later.
          //The capture is set so that the custom button
          // will not lose the mouse if it is dragged
          // under another component. If you disable this
          // statement, the custom button will sometimes
          // get stuck when you drag it under one of the
          // labels that are provided as obstacles in this
          // application.
          DOM.setCapture(sender.getElement());
          
          //Record the location of the mouse pointer 
          // relative to the upper-left corner of the
          // custom button when the mouse button is
          // pressed.
          xOffset = x;
          yOffset = y;
          
          //Set the dragging flag to indicate that a drag
          // operation is underway. This flag will be
          // tested later by the onMouseMove method.
          dragging  = true;
        }//end onMouseDown
        //-----------------------------------------------//
        
        public void onMouseMove(Widget sender,int x,int y){
          //Perform the following operations only if a drag
          // operation is in progress.
          if (dragging){
            //Compute the location of the mouse pointer
            // relative to the upper-left corner of the
            // browser window by adding the x and y
            // coordinate offset values to the absolute
            // coordinate values of the custom button.
            int xAbs = x + sender.getAbsoluteLeft();
            int yAbs = y + sender.getAbsoluteTop();
            
            //The purpose of the next statement is to
            // relocate the custom button to a new position
            // determined by the absolute location of the
            // mouse pointer when this event was fired.
            //The sender is the custom button. When
            // getParent is invoked on it, a reference to
            // the container of the custom button is
            // returned as type Widget. In order to invoke
            // the setWidgetPosition method on that
            // reference, it must be downcast at least as
            // far as AbsolutePanel, which is where the
            // setWidgetPosition method is defined. In
            // this case, the reference is cast all the way
            // down to RootPanel, which is a subclass of
            // AbsolutePanel, and is the actual container
            // of the custom button.
            //The new location for the upper-left corner of
            // the custom button is computed by subtracting
            // the offset coordinates of the mouse pointer
            // relative to the upper-left corner of the
            // custom button from the absolute coordinates
            // of the mouse pointer relative to the
            // upper-left corner of the RootPanel, which
            // completely fills the browser window.  
            ((RootPanel)sender.getParent()).
                   setWidgetPosition(
                     sender,xAbs - xOffset,yAbs - yOffset);
          }//end if
        }//end onMouseMove
        //-----------------------------------------------//
        
        public void onMouseUp(Widget sender,int x,int y){
          //The custom button has been relocated to the new
          // location when the user releases the mouse
          // button.
          //Release the mouse capture condition that was
          // established earlier in the onMouseDown method
          // and set the dragging flag to false to indicate
          // that the drag operation is terminated.
          DOM.releaseCapture(sender.getElement());
          dragging = false;
        }//end onMouseUp
        //-----------------------------------------------//

      }//end constructor
    );//end addMouseListener
    //===================================================//
    
    //Add a Label to the browser window to serve as an
    // obstacle. The custom button will pass over this
    // Label when being dragged. Whether one component
    // passes over or under another component depends on
    // the order in which they are added to the RootPanel.
    // The component being dragged will pass over those
    // components added to the RootPanel before the
    // component being dragged was added, and will pass
    // under those components added to the RootPanel after
    // the component being dragged was added.
    RootPanel.get().add(new Label("Top Obstacle"),75,200);
    
    //Add the custom button to the browser window.
    RootPanel.get().add(customButton);
    
    //Add another Label to the browser window to serve as
    // another obstacle. The custom button will pass under
    // this Label when being dragged.
    RootPanel.get().add(new Label(
                                "Bottom Obstacle"),75,225);
    
  }//end onModuleLoad method
  //=====================================================//

}//end class GwtApp018

Listing 27. HTML host page for GwtApp018.

<!---------------------------------------------------------
File GwtApp018.html
GWT host page.
Revised: 11/26/06
---------------------------------------------------------->
<html>
<head>
<title>Wrapper HTML for GwtApp018</title>
<meta name='gwt:module' content='GwtApp.GwtApp018'>

</head>

<body>
<script language="javascript" src="gwt.js"></script>
<iframe id="__gwt_historyFrame" 
              style="width:0;height:0;border:0"></iframe>

<h3>GwtApp018</h3>

<p>Demonstrates drag-and-drop of a custom button 
component.</p>


</body>
</html>

Copyright

Copyright 2007, Richard G. Baldwin.  Except for the code in the application named GwtApp018, reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.  Reproduction rights for the code in the application named GwtApp018 are governed by the copyright statement that appears at the beginning of Listing 26.

Download

Resources

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel