Java Forum / GUI / May 2006
How to use actionListers within static methods
Ian Wilson - 12 May 2006 16:11 GMT In the code below I am attempting to define an ActionListener for a button so I can do something useful when the button is pressed.
At the statement ButtonListener buttonListener = new ButtonListener(); Eclipse says "No enclosing instance of type Hats is accessible, Must qualify the allocation with an enclosing instance of type Hats (e.g. x.new A() where x is an instance of Hats".
The trouble is I never intend to instantiate Hats since I don't ever expect to need multiple Hats objects in existence at the same time.
Q.1 Is there a fix?
import java.awt.event.ActionEvent; import java.awt.event.ActionListener;
import javax.swing.*;
public class StaticGUI { public static JFrame frame = new JFrame(); public static void main(String[] args) { // main GUI with menu that invokes ... Hats.editHats(); } }
class Hats { // so can refer to addButton in buttonListener: public static JButton addButton;
public static void editHats() { addButton = new JButton("Add"); JButton editButton = new JButton("Edit"); JButton removeButton = new JButton("Remove"); ButtonListener buttonListener = new ButtonListener(); addButton.addActionListener(buttonListener); editButton.addActionListener(buttonListener); removeButton.addActionListener(buttonListener); JPanel buttonPanel = new JPanel(); buttonPanel.add(addButton); buttonPanel.add(editButton); buttonPanel.add(removeButton); JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); JTextArea textArea = new JTextArea(); panel.add(textArea); panel.add(buttonPanel); JOptionPane pane = new JOptionPane( panel, // "message" JOptionPane.PLAIN_MESSAGE, // messagetype JOptionPane.OK_CANCEL_OPTION // optiontype ); JDialog dialog = pane.createDialog(StaticGUI.frame,"Test"); dialog.setResizable(true); dialog.setVisible(true); } // method editHats
// an inner class within Hats, to listen to Hat-related button events class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { JComponent c = (JComponent) e.getSource(); if (c == addButton) { System.out.println ("You pressed 'Add'"); } } } } // class Hats
Q.2 should I rethink my whole approach to my design of this application?
Vova Reznik - 12 May 2006 16:41 GMT > In the code below I am attempting to define an ActionListener for a > button so I can do something useful when the button is pressed. [quoted text clipped - 9 lines] > > Q.1 Is there a fix? Yes, define class Hats as static
> import java.awt.event.ActionEvent; > import java.awt.event.ActionListener; [quoted text clipped - 52 lines] > > Q.2 should I rethink my whole approach to my design of this application? Yes, put Hats into another .java file
Thomas Fritsch - 12 May 2006 17:17 GMT >> At the statement >> ButtonListener buttonListener = new ButtonListener(); [quoted text clipped - 5 lines] > > Yes, define class Hats as static You probably meant: Yes, define class ButtonListener as static
>> class Hats { >> // so can refer to addButton in buttonListener: [quoted text clipped - 5 lines] >> JButton removeButton = new JButton("Remove"); >> ButtonListener buttonListener = new ButtonListener(); [...]
>> } // method editHats >> >> // an inner class within Hats, to listen to Hat-related button events >> class ButtonListener implements ActionListener { static class ButtonListener implements ActionListener {
>> public void actionPerformed(ActionEvent e) { >> JComponent c = (JComponent) e.getSource(); [quoted text clipped - 4 lines] >> } >> } // class Hats
 Signature "Thomas:Fritsch$ops:de".replace(':','.').replace('$','@')
Ian Wilson - 12 May 2006 17:23 GMT >> In the code below I am attempting to define an ActionListener for a >> button so I can do something useful when the button is pressed. [quoted text clipped - 11 lines] > > Yes, define class Hats as static Thanks, I changed class Hats { to static class Hats
Eclipse says "Illegal modifier for the class Hats, only public, abstract & final are permitted"
<snip: code>
>> Q.2 should I rethink my whole approach to my design of this application? > > Yes, put Hats into another .java file Thanks, I did that too, I get the same error messages as before.
Warning: long rambling question ahead, skip the remainder of this posting if you dislike long rambling questions.
In my real application I do have classes in separate files. I put them together in my example to make it easier for others to cut, paste and compile.
What I had in mind when I wrote Q2 was more general. My app has a main JFrame with a JMenubar from which the user can select various transactions. Some of these maintain reference data, i.e. relatively static lists of things which are stored in a database.
Take, for example, a list of ISO country codes. I did wonder whether my main() should instantiate an instance of CountryList (say) at the start and then invoke instance methods in response to menu selections.
Since I'd never need more than one instance of CountryList this seemed a bit of overkill, I'd have to instantiate one of each type of reference data at the program startup or keep track of whether I'd instantiated each of them before. Maybe I could instantiate one object as needed, just to act as a reference for method calls.
It seemed simpler (my procedural programming roots may be showing) to use a class simply to group together a bunch of static methods relating to a specific type of reference data (e.g. class CountryList contains all the things you can do with the DB table of countries: view a list of them, add a country to the list, retrieve attributes of a specific country, ...)
However I keep bumping up against issues. E.g. ActionListener documentation examples are often along the lines of component.addActionListener(this) where "this" isn't usable in a class method. This kind of mismatch makes me wonder if my fundamental approach is ill-chosen.
Vova Reznik - 12 May 2006 17:33 GMT I'm sorry for previous response you need to define ButtonListener as static
> In the code below I am attempting to define an ActionListener for a > button so I can do something useful when the button is pressed. [quoted text clipped - 66 lines] > > Q.2 should I rethink my whole approach to my design of this application? Fred Kleinschmidt - 12 May 2006 19:40 GMT > In the code below I am attempting to define an ActionListener for a button > so I can do something useful when the button is pressed. [quoted text clipped - 66 lines] > > Q.2 should I rethink my whole approach to my design of this application? You should rethink your approach. You make all Hats methods static because you never intend to instantiate Hats since don't expect to need multiple Hats objects in existence at the same time. First, if it is static, you never have even one object... Second, that's not really a good reason to make the class static.
But Hats does instantiate a JDialog, so why not just make Hats the JDialog itself? And have it implement ActionListener, so you don't have to have inner classes:
public class Hats extends JDialog implements ActionListener { // constructor public Hats() { // Create buttons, panels, etc. ... // set up ActionListener addButton.addActionListener( this ); editButton.addActionListener( this ); removeButton.addActionListener( this ); }
// ActionListener method public void actionPerformed( ActionEvent e ) { // body here } }
Ian Wilson - 15 May 2006 10:22 GMT >>In the code below I am attempting to define an ActionListener for a button >>so I can do something useful when the button is pressed. [quoted text clipped - 94 lines] > } > } Thanks Fred, Thomas & Vova. I've made ButtonListener static and will make an attempt at a non-static approach for comparison.
Fred.Swartz@gmail.com - 22 May 2006 20:58 GMT To stay in the mainstream of GUI building, don't go down the static path. Use the common approach of subclassing JFrame, building the GUI in its constructor, and define main in the same class. Main should just create an object of that class, then setVisible(true) on it. Or do that after starting a separate thread if the GUI is complicated enough to require that.
There's no advantage to the static approach -- basically the same amount of memory has to be allocated anyway. Java revolves around objects, and the big disadvantage of the static approach is that not even one object is allocated for your class. Perhaps the static approach works for everything, but you'll discover that you have to do a number of things a little differently.
You want a JFrame subclass to get one object, not multiple objects. This will also keep you in the mainstream with more useful examples.
Ian Wilson - 25 May 2006 10:08 GMT > To stay in the mainstream of GUI building, don't go down the static > path. Use the common approach of subclassing JFrame, building the GUI [quoted text clipped - 12 lines] > You want a JFrame subclass to get one object, not multiple objects. > This will also keep you in the mainstream with more useful examples. I'm having a problem with this approach. When I construct a JOptionPane, I don't know how to specify the parent frame correctly. In the example below, on WinXP, if you open the MyApp5 Customer dialog, then open another app over the top, then click MyApp5 in the tray at the bottom to bring it to front, you don't see the modal dialog because I havent set its parent correctly. How do I specify the parent?
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;
import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem;
public class MyApp5 extends JFrame implements ActionListener { private static final long serialVersionUID = 3258412832977860659L;
public MyApp5() { JMenu editMenu = new JMenu("Edit"); editMenu.add(makeMenuItem("Suppliers")); editMenu.add(makeMenuItem("Customers")); JMenuBar menuBar = new JMenuBar(); menuBar.add(editMenu); setJMenuBar(menuBar); }
JMenuItem makeMenuItem(String itemName) { JMenuItem item = new JMenuItem(itemName); item.addActionListener(this); return item; }
public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if (command == "Customers") { MyApp5CustomerPane custPane = new MyApp5CustomerPane(); } if (command == "Suppliers") { // } // Lots more like this }
private static void createAndShowGUI() { JFrame frame = new MyApp5(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); int width = 600; int height = 400; Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); int x = (screen.width - width) / 2; int y = (screen.height - height) / 2; frame.setBounds(x, y, width, height); frame.setVisible(true); }
public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } // class MyApp5 /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable;
public class MyApp5CustomerPane extends JOptionPane { private static final long serialVersionUID = 3257571685141197368L;
private String[] columnNames = { "Name", "City" };
private Object[][] data = { { "British", "London" }, { "Continental", "Houston" }, { "SouthWest", "Dallas" }, { "United", "Chicago" }, { "Virgin", "London" } };
public MyApp5CustomerPane() {
JTable table = new JTable(data, columnNames); JScrollPane scroller = new JScrollPane(table); JPanel panel = new JPanel(); panel.add(scroller); setMessage(panel);
setMessageType(JOptionPane.PLAIN_MESSAGE); setOptionType(JOptionPane.OK_CANCEL_OPTION);
JDialog dialog = createDialog(new JFrame(), "Customers"); // ^^^^^^^^ problem! dialog.setResizable(true); dialog.setVisible(true); } } /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Ian Wilson - 26 May 2006 11:51 GMT >> To stay in the mainstream of GUI building, don't go down the static >> path. Use the common approach of subclassing JFrame, building the GUI >> in its constructor, and define main in the same class. Main should >> just create an object of that class, then setVisible(true) on it. Or >> do that after starting a separate thread if the GUI is complicated >> enough to require that. <snippage>
> I'm having a problem with this approach. When I construct a JOptionPane, > I don't know how to specify the parent frame correctly. In the example > below, on WinXP, if you open the MyApp5 Customer dialog, then open > another app over the top, then click MyApp5 in the tray at the bottom to > bring it to front, you don't see the modal dialog because I havent set > its parent correctly. How do I specify the parent? <snip: code listings>
I changed MyApp5CustomerPane custPane = new MyApp5CustomerPane(); MyApp5CustomerPane custPane = new MyApp5CustomerPane(this); ... public MyApp5CustomerPane() { public MyApp5CustomerPane(JFrame parent) { ... JDialog dialog = createDialog(new JFrame(), "Customers"); JDialog dialog = createDialog(parent, "Customers");
Then all was OK.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|