简体   繁体   中英

How do I add an ActionListener to an instance of my class that extends JButton?

I instantiated a button of my class like so:

linkBtn = new LinkButton(
                        new URI("http://www.example.com"),
                        "Click me");

Nothing happens when I click it, so I want to add an action listener something like this:

linkBtn.addActionListener(SOMETHING);

I tried things like this:

linkBtn.addActionListener(new LinkButton.OpenUrlAction());

That gives the following error:

an enclosing instance that contains LinkButton.OpenUrlAction is required

I haven't found the right syntax yet.

Here's my class that extends JButton:

import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URI;
import javax.swing.JButton;

public class LinkButton extends JButton
    implements ActionListener {
    /** The target or href of this link. */
    private URI target;
    final static private String defaultText = "<HTML>Click the <FONT color=\"#000099\"><U>link</U></FONT>"
        + " to go to the website.</HTML>";

    public LinkButton(URI target, String text) {
        super(text);
        this.target = target;
        //this.setText(text);
        this.setToolTipText(target.toString());
    }
    public LinkButton(URI target) {
        this( target, target.toString() );
    }    
    public void actionPerformed(ActionEvent e) {
        open(target);
    }
    class OpenUrlAction implements ActionListener {
      @Override public void actionPerformed(ActionEvent e) {
        open(target);
      }
    }
    private static void open(URI uri) {
    if (Desktop.isDesktopSupported()) {
      try {
        Desktop.getDesktop().browse(uri);
      } catch (IOException e) { /* TODO: error handling */ }
    } else { /* TODO: error handling */ }
  }
}

I don't understand why you extends a JButton but you can add by default this listener in constructor.

 public LinkButton(URI target, String text) {
        super(text);
        this.target = target;
        //this.setText(text);
        this.setToolTipText(target.toString());
        this.addActionListener(this);
        //this.addActionListener(new OpenUrlAction());
    }

Or you can do this.

linkBtn.addActionListener(linkBtn.new OpenUrlAction()); outerObject.new InnerClass()

Or you can modify your inner class with a constructor injection

class OpenUrlAction implements ActionListener{
  private URI target;

  OpenUrlAction(URI target){
   this.target=target;
  }

  @Override
  public void actionPerformed(ActionEvent evt){
     open(this.target);
  }
}

In client code:

`linkBtn.addActionListener(linkBtn.new OpenUrlAction(lninkBtn.getTarget)); // or the target that you want`

You could do this:

linkBtn.addActionListener(linkBtn.new OpenUrlAction());

But your program structure makes me wince. Myself I'd try to get Actions separate from views. I also much prefer extension by composition rather than inheritance.

I'm open to suggestions. I don't like my program structure either...

The answer's provided so far are all excellent.

Hovercraft has suggest the use of Action s, which would simply the structure of your code.

For example...

import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class LinkButtonExample {

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

    public LinkButtonExample() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new GridBagLayout());
                    frame.add(new JButton(new OpenURLAction(new URL("http://stackoverflow.com/"))));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (MalformedURLException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public class OpenURLAction extends AbstractAction {

        private URL url;

        public OpenURLAction(URL url) {

            this("<HTML>Click the <FONT color=\\\"#000099\\\"><U>link</U></FONT> to go to the website.</HTML>", url);

        }

        public OpenURLAction(String text, URL url) {

            putValue(NAME, text);
            setURL(url);

        }

        public void setURL(URL url) {
            this.url = url;
            setEnabled(
                            url != null
                            && Desktop.isDesktopSupported()
                            && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE));
            putValue(SHORT_DESCRIPTION, url == null ? null : url.toString());
        }

        public URL getURL() {
            return url;
        }

        @Override
        public void actionPerformed(ActionEvent e) {

            if (isEnabled()) {

                URL url = getURL();
                if (url != null && Desktop.isDesktopSupported()
                                && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
                    try {
                        Desktop.getDesktop().browse(url.toURI());
                    } catch (    IOException | URISyntaxException ex) {
                        ex.printStackTrace();
                    }
                }

            }

        }
    }
}

Check out How to use Actions for more details

Here what I came up with so far. I added this method to my LinkButton class:

public void init() {
    this.addActionListener(this);
}

Then I added this code to add the action listener:

linkBtnDonate.init();

It's working. I'm open to other suggestions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM