Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid nested ActionListeners?

In my program, I want the user to:

  1. pick/open a database (like Access) on their own
  2. pick a table from the database
  3. select column(s) from the table

In my code, I have a class that does something like this:

mntmOpenDatabase.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        //open the database
        //display tables as buttons
        tableButton.addActionListener(new ActionListener() { // select a table
            public void actionPerformed(ActionEvent e) {
                //display the columns of the table selected as buttons
                    colButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e) {// add to the list of columns to be exported }

And this results to a very big block of code. Is there a cleaner, simpler way to do this?

like image 776
Wabbage Avatar asked Oct 30 '15 21:10

Wabbage


2 Answers

The solution is to refactor:

  • Create a separate and separately testable class for the code to open the database.
  • And a separate and separately testable class for the display of this data.
  • In the ActionListener, either create instances of these classes, or interact with them, if they already exist.
  • Learn the basic principles of the M-V-C (Model-View-Control) design pattern, and use them. You don't have to be slavish to them, and lord-knows there are many variants, but their overall guiding principles should be at least respected.
  • Strive to make your GUI or view as dumb as possible. It knows how to display its data, it has facilities to allow the control to update its display, and it knows how to notify the control when the user interacts with it, and that's about it.
  • Side recommendation 1: be sure that all database interaction is done in a background thread.
  • Side recommendation 2: be sure that almost all Swing interaction is done in on the Swing EDT (the event-dispatch thread).

Please look at this similar but more complete question and answer: How can one best avoid writing bloated GUI code?. The answers are as good as it gets, and I wish that I could up-vote them a gazillion times.

For example, your code above could be as simple as:

mntmOpenDatabase.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        control.openDatabase();
    }
}
like image 125
Hovercraft Full Of Eels Avatar answered Oct 22 '22 22:10

Hovercraft Full Of Eels


In your example you will instantiate and add new listener on each ActionEvent. Really you should configure it once. Something like this:

public class OpenDataBaseListener implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e){
               //your event handling here
        }
}

public class TableButtonListener implements  ActionListener{
        @Override
        public void actionPerformed(ActionEvent e){
            //your logic   
        }
}

etc...

And when you create your listeners you should register them once:

mntmOpenDatabase.addActionListener(new OpenDataBaseListener());
tableButton.addActionListener(new TableButtonListener());
colButton.addActionListener(new ColButtonListener());
like image 30
D. Rakov Avatar answered Oct 22 '22 23:10

D. Rakov