【问题标题】:Java ActionListener Return Variable To Method That Contains ActionListenerJava ActionListener 将变量返回到包含 ActionListener 的方法
【发布时间】:2015-06-29 21:37:36
【问题描述】:

我有一个这样的方法,给定一个JButton 数组,并在按下它们时返回它们的文本:

public static String foo(JButton[] buttons) {
    for (JButton i : buttons) {
        i.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                return i.getText();
            }
        });
    }
}

但是,当然,这段代码不会编译,因为我将一个变量返回给一个 null 方法。那么,我如何让i.getText() 也通过foo() 方法返回其输出?


编辑,所有代码:

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class JCustomFrame {
    public static void showMessageFrame(String title, String message,
            String[] textOnButtons, ImageIcon icon) {
        final JFrame frame = new JFrame();
        JPanel panel = new JPanel();

        panel.setLayout(new GridBagLayout());
        panel.setBackground(Color.WHITE);

        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.EAST;
        c.fill = GridBagConstraints.RELATIVE;
        c.gridx = 0;
        c.gridy = 0;
        c.insets = new Insets(5, 5, 5, 5);

        JLabel messageLabel = new JLabel(message);
        messageLabel.setFont(messageLabel.getFont().deriveFont(16.0f));

        panel.add(messageLabel, c);

        c.gridy = 1;
        c.gridx = 0;
        for (int i = 0; i < textOnButtons.length; i++) {
            JButton button = new JButton(textOnButtons[i]);
            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    return ((JButton) arg0.getSource()).getText();
                    frame.dispose();
                }
            });
            button.setFont(button.getFont().deriveFont(16.0f));
            panel.add(button, c);
            c.gridx++;
        }

        if (icon == null) {
            frame.setIconImage(new BufferedImage(1, 1,
                    BufferedImage.TYPE_INT_ARGB_PRE));
        } else {
            frame.setIconImage(icon.getImage());
        }
        frame.add(panel);
        frame.setTitle(title);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.pack();
    }

    public static void main(String[] args) {
        JCustomFrame.showMessageFrame("Test Frame",
                "Do you really want to do this?", new String[] { "Hell No",
                        "Sure, Why Not" }, null);
    }
}

【问题讨论】:

  • 您以线性/程序化的方式思考,这不是 UI 的工作方式,UI 是事件驱动的,这意味着某事发生(在某个时间点)并且您对其做出响应。将值退回给 foo 方法是没有意义的,因为代码在通知 ActionListener 之前很久就已经完成执行。最好让侦听器自己执行所需的操作

标签: java swing return listener


【解决方案1】:

这个说法没有意义:

那么,我如何让 i.getText() 也通过 foo() 方法返回其输出?

根据事件驱动编程的规则,在将 ActionListener 添加到按钮后,方法 foo() 将不再运行,并且肯定会在用户按下按钮时结束。相反,尽管您可以让 ActionListeners 更改类的状态,但任何类都应该足够了。例如:

class FooClass {
    private String text;

    public void foo(JButton[] buttons) {
        for (JButton i : buttons) {
            i.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    text = e.getActionCommand(); 
                }
            });
        }
    }
}

如果您需要有关可行解决方案的更多详细信息,请告诉我们有关您的实际程序和具体问题的更多详细信息。

现在,如果您确实需要一种方法来返回所按下按钮的值,则需要通过通知机制和回调方法来完成此操作,但同样,解决方案的细节将取决于实际的细节问题和代码。


编辑

您正在尝试模拟 JOptionPane。您的解决方案是使用 JOptionPane,向其中添加 JPanel,或者使用模态 JDialog 创建自己的:

import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class JCustomFrame2 {

   public static String showMessageFrame(Window owner, String title,
         String message, String[] textOnButtons, ImageIcon icon) {
      final JDialog dialog = new JDialog(owner);
      StringBuilder sb = new StringBuilder();

      // make it application modal!
      dialog.setModalityType(ModalityType.APPLICATION_MODAL);
      JPanel panel = new JPanel();

      panel.setLayout(new GridBagLayout());
      panel.setBackground(Color.WHITE);

      GridBagConstraints c = new GridBagConstraints();
      c.anchor = GridBagConstraints.EAST;
      c.fill = GridBagConstraints.RELATIVE;
      c.gridx = 0;
      c.gridy = 0;
      c.insets = new Insets(5, 5, 5, 5);

      JLabel messageLabel = new JLabel(message);
      messageLabel.setFont(messageLabel.getFont().deriveFont(16.0f));

      panel.add(messageLabel, c);

      c.gridy = 1;
      c.gridx = 0;
      for (int i = 0; i < textOnButtons.length; i++) {
         JButton button = new JButton(textOnButtons[i]);
         button.addActionListener(new ButtonListener(sb));
         button.setFont(button.getFont().deriveFont(16.0f));
         panel.add(button, c);
         c.gridx++;
      }

      if (icon == null) {
         dialog.setIconImage(new BufferedImage(1, 1,
               BufferedImage.TYPE_INT_ARGB_PRE));
      } else {
         dialog.setIconImage(icon.getImage());
      }
      dialog.add(panel);
      dialog.setTitle(title);
      dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
      dialog.pack();
      dialog.setVisible(true);

      return sb.toString();
   }

   private static class ButtonListener implements ActionListener {
      private StringBuilder sb;

      public ButtonListener(StringBuilder sb) {
         this.sb = sb;
      }


      @Override
      public void actionPerformed(ActionEvent e) {
         sb.append(e.getActionCommand());
         Component component = (Component) e.getSource();
         Window win = SwingUtilities.getWindowAncestor(component);
         if (win != null) {
            win.dispose();
         }
      }
   }

   public static String showMessageFrame(String title,
         String message, String[] textOnButtons, ImageIcon icon) {
      return showMessageFrame(null, title, message, textOnButtons, icon);
   }


   public static void main(String[] args) {
      String result = JCustomFrame2.showMessageFrame("Test Frame",
            "Do you really want to do this?", new String[] { "Hell No",
                  "Sure, Why Not" }, null);

      System.out.println(result);
   }
}

【讨论】:

  • @LucasBaizer:应该与您的问题一起发布。我冒昧地为你做这件事。
【解决方案2】:

为什么这么复杂?无论foo 应该做什么,只要简单地从ActionListener 内部调用另一个方法,并将按钮的名称作为参数,就会容易得多。或者,如果你真的想实现这样的目标,让线程等待用户按下按钮。

public void doSomething(){
    JButton[] someButtons = ...;//whereever you create the buttons

    System.out.println(foo(someButtons));
}

public static String foo(JButton[] buttons){
    final String someString = "";

    final Object lock = new Object();

    for(JButton b : buttons){
        b.addActionListener(e -> {
             someString.concat(b.getName());

             synchronized(lock){
                 lock.notifyAll();
             }
        });
    }

    synchronized(lock){
        try{
            lock.wait();
        }catch(InterruptedException e){}
    }

    return someString;
}

【讨论】:

  • 抱歉,synchronized 是什么?
  • 用于锁定指定对象的代码块。这可以防止多个线程同时访问同一对象上的同一段代码。不过,这只是一个成熟的版本。在此处进行了更准确的描述:docs.oracle.com/javase/tutorial/essential/concurrency/…(用于同步方法)和此处:docs.oracle.com/javase/tutorial/essential/concurrency/…(用于同步语句)
  • 您是否在正在运行的程序中对此进行了测试?如果不是非常小心并且主要在后台线程中完成,看起来它可能会锁定整个 GUI。
  • @HovercraftFullOfEels 取决于调用 foo 的位置。不应从事件处理线程中调用它,但如果确保这一点,GUI 将正常工作。据我所知,OP 想在主线程中使用它,所以一切都很好
  • 如果从 EDT 调用 foo,这将阻塞 EDT,这意味着永远不会调用 ActionListenr,如果不从 EDT 调用,那么您将面临与 EDT 竞争条件的风险。 ..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
  • 2014-10-22
  • 2023-03-29
  • 2012-02-07
相关资源
最近更新 更多