user17236093
user17236093

Reputation:

swing add more then one action listener to the same button

I am working on a project where there is a front and back course for a golf app that tracks the scores and stuff, and I am using the same frames for the front and the back, the front and the back write and read to different files and need to use different methods etc.

I am setting up my action listeners like this

   BUTTON_NAME.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
              // does stuff
                    }
                });

The problem that I am having with this if you use one of the action listeners from the front course frame they wont change when I want them to

Here is now I'm trying to change the action listeners

   BUTTON_NAME.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {

          BUTTON_NAME.addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
             // does stuff
                   }
                   });

                }
            });

So how would I correctly accomplish this? Thank you in advance.

Upvotes: 0

Views: 174

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347204

The core issue is not with the button or ActionListener, but with how you want to change the functionality when the ActionListener is triggered.

This is a core design principle which is demonstrated through the use of things like "dependency injection", "delegation", "observers", "models" and/or "data sources". Many of these are the same concept, performing slightly different roles, depending on your needs

See...

for more details.

For simplicity, a "delegate" can often be thought of as an "observer", for example, the ActionListener provides delegation of workflow when a button is clicked.

Delegation

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();

                JPanel panel = new JPanel(new GridLayout(1, 2));
                panel.add(new CommonPane(new CommonDelegate() {
                    @Override
                    public void didClickMe(CommonPane source) {
                        JOptionPane.showMessageDialog(source, "Left was clicked");
                    }
                }));
                panel.add(new CommonPane(new CommonDelegate() {
                    @Override
                    public void didClickMe(CommonPane source) {
                        JOptionPane.showMessageDialog(source, "Right was clicked");
                    }
                }));

                frame.add(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface CommonDelegate {
        public void didClickMe(CommonPane source);
    }

    public class CommonPane extends JPanel {

        public CommonPane(CommonDelegate delegate) {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(32, 32, 32, 32));

            JButton btn = new JButton("Click me");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    delegate.didClickMe(CommonPane.this);
                }
            });
            add(btn);
        }

    }
}

Data source

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();

                JPanel panel = new JPanel(new GridLayout(1, 2));
                panel.add(new CommonPane(new CommonDataSource() {
                    @Override
                    public String getClickMeTitle() {
                        return "On the left";
                    }

                    @Override
                    public String getClickMeMessage() {
                        return "Left was clicked";
                    }
                }));
                panel.add(new CommonPane(new CommonDataSource() {
                    @Override
                    public String getClickMeTitle() {
                        return "On the right";
                    }

                    @Override
                    public String getClickMeMessage() {
                        return "Right was clicked";
                    }
                }));

                frame.add(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface CommonDataSource {
        public String getClickMeTitle();
        public String getClickMeMessage();
    }

    public class CommonPane extends JPanel {

        public CommonPane(CommonDataSource dataSource) {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(32, 32, 32, 32));

            JButton btn = new JButton(dataSource.getClickMeTitle());
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showMessageDialog(CommonPane.this, dataSource.getClickMeMessage());
                }
            });
            add(btn);
        }

    }
}

Important

You could combine the roles of the "delegate" and the "data source" (aka "model") or you could seperate them and use both, so your UI would require both a "model" and a "delegate", depending on your needs.

One thing I would not recommend, is exposing the JButton to other calls, instead, if absolutely required, I'd expose a setXxxActionListener if you want to provide a more "direct" delegation of an individual action, but this would raise some alarm bells for me and I'd be questioning the need to design the code this way, but that's me.

Upvotes: 1

Related Questions