Saturday, June 13, 2009

Action Listeners

In my last blog I recorded a dismal failure to hand-code a data connection from within NetBeans, but an eventually successful connection using a hand coded app run from the command line. I therefore resigned myself to learning Swing, so that I could rebuild my Java Math Test by hand.

The lessons in the Swing Trail are generally very well written, in sharp contrast to this in the JDBC Trail. Each lesson is illustrated with a mini app, and a link to the complete code is provided early in the lesson, along with a screen shot to the app running, and a JNLP link to run it from within the browser. If you choose to download the code, it compiles and runs without a glitch.

My only criticism, or suggestion for an improvement, would be the addition of a few "application" (in the literal sense of the word) lessons, which combine features from different sub-trails.

My own particular interest is in combining GridBag layout with Event or Action Listeners. You'd think it would be simple enough, but I am having great difficulty either adding event listening code to a test app using the GridBag layout, or converting a sample event listening app to the GridBag layout.

My first preference would be to add an Action Listener to to an app using the GridBag layout, because I have already built a front end using code from the component and layout lessons.

Many of the component lessons include some even handling code, but I refer to the Introduction to Event Listeners lesson, because it lays out the theory from first principles. Like other lessons in the Swing trail it provides the full code for an example, and it then goes on to say: "Here is the code that implements the event handling for the button:

public class Beeper ... implements ActionListener {
... //where initialization occurs:
public void actionPerformed(ActionEvent e) {
...//Make a beep sound... } }

So it looks as if there are just three easy steps to adding event listener code to an existing class. First you add "implements ActionListener" to the class declaration, then you add the line "button.addActionListener(this);" somewhere in the code defining the button, and finally you write a method for the event: "public void actionPerformed(ActionEvent e) { ... }. That looks simple enough. I shall begin with a shortened version of the GridBag code, and add these lines one by one.

First I compile and run the existing code to check that it really works. It does. Then I add "implements ActionListener" to the class declaration. When I try to compile I get the error: cannot find symbol
symbol: class ActionListener
public class GBLD1 implements ActionListener {

So I add:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

to the import list and try again. I now get the error message: GBLD1 is not abstract and does not override abstract method  actionPerformed(java.awt.event.ActionEvent) in java.awt.event.ActionListener
public class GBLD1 implements ActionListener {

For completeness, I'll add the action listener to the button and try to compile again. Now there is a new error: non-static variable this cannot be referenced from a static context

This error message opened a whole can of worms, and prompted me to post a question in the swing forum.

To cut a long story short the answer was to replace the word "this" with an instance of the class as follows:

button.addActionListener(new GBLD2());

where GBLD2 was the classname of my test app. This enabled me to insert an action listener into my Gridbag test app, such that the main button gives a beeping sound when clicked. The method to produce the beep was:

public void actionPerformed(ActionEvent e) {

So far this is all I have managed by way of action code. Any attempt to reference objects on the form generates errors. According to the thread, I need to refer back to the lessons on "static, instance, and reference".