【问题标题】:JFrame in separate class, what about the ActionListener?JFrame 在单独的类中,ActionListener 呢?
【发布时间】:2014-04-29 07:17:23
【问题描述】:

我正在尝试将我的 Swing GUI 与我的实际代码分开。简而言之,我希望用户启动一个进程(基于用户的选择);在这种情况下,将不再需要 JFrame。

我想不通的是如何将用户从 GUI.class 中的选择与 Main.class 共享。

你对我有什么建议吗?

这是我的代码:

public class Main {
  public static void main(String[] args) {
    // Show GUI
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        GUI gui = new GUI(templates);
        gui.setVisible(true);
      }
    });

    // Kick off a process based on the user's selection
  }
}

public class GUI extends JFrame {
  private static final long serialVersionUID = 1L;

  public GUI(Object[] objects) {
    setTitle("GUI");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 350, 100);
    setLocationRelativeTo(null);

    JPanel cp = new JPanel();
    cp.setBorder(new EmptyBorder(10, 10, 10, 10));
    setContentPane(cp);

    JLabel lbl = new JLabel("Selection:");
    cp.add(lbl);

    final JComboBox<String> comboBox = new JComboBox<String>(new String[] { "One", "Two", "Three" });
    comboBox.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        setVisible(false);
        dispose();
        // Share the selected item with Main.class
      }
    });
    cp.add(comboBox);
  }
}

【问题讨论】:

标签: java swing actionlistener


【解决方案1】:

这样做的一个好方法是使用 Callback 机制

要遵循的步骤:

  • 创建回调接口

    interface Callback {
        void execute(Object result);
    }
    
  • GUI 类将实现Callback 接口,但不提供任何实现

  • 制作GUIabstract

    abstract class GUI extends JFrame implements Callback
    
  • 现在创建一个GUI 类的对象,提供Callback 接口的实际实现

  • 这里可以使用匿名类

    GUI gui = new GUI() {
    
        @Override
        public void execute(Object result) {
            System.out.println("You have selected " + result);
        }
    
    };
    
  • 你可以在Callbackexecute()方法中传递任何东西。

    comboBox.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            setVisible(false);
            dispose();
            // Share the selected item with Main.class
            // Callback
            execute(comboBox.getSelectedItem());
        }
    });
    

这里Main 类负责捕获CallbackGUI 类指示的响应。


代码如下:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Main {
    public static void main(String[] args) {
        // Show GUI
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                GUI gui = new GUI() {

                    @Override
                    public void execute(Object result) {
                        System.out.println("You have selected " + result);
                    }

                };
                gui.setVisible(true);
            }
        });

        // Kick off a process based on the user's selection
    }
}

interface Callback {
    void execute(Object result);
}

abstract class GUI extends JFrame implements Callback {
    private static final long serialVersionUID = 1L;

    public GUI() {
        setTitle("GUI");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 350, 100);
        setLocationRelativeTo(null);

        JPanel cp = new JPanel();
        cp.setBorder(new EmptyBorder(10, 10, 10, 10));
        setContentPane(cp);

        JLabel lbl = new JLabel("Selection:");
        cp.add(lbl);

        final JComboBox comboBox = new JComboBox(new String[] { "One", "Two", "Three" });
        comboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setVisible(false);
                dispose();
                // Share the selected item with Main.class
                execute(comboBox.getSelectedItem());
            }
        });
        cp.add(comboBox);
    }

}

【讨论】:

  • 非常感谢您的精彩解释!这确实为我提供了一个新的视角。
  • 我可以扩展我的问题吗?再次来自设计模式观点:如果我想根据用户的选择进行一些计算并动态更新 GUI - 我的第一个想法是简单地嵌套另一个 Calculations 对象并使 GUI 对象静态(以便 Calculations 对象可以访问GUI 对象)。你对我有什么建议吗?
  • 我不能说,除非我完全理解你的代码。尽量少改动代码以避免回归。
  • 显然,您指的是我评论的早期版本。我要避免的(尽管回归可能是错误的术语)是这样的: public void run() { gui = new GUI() { (a)Override public void execute(Object result) { Calculations calc = new Calculations(result) { (a)Override public void execute(Object result) { gui.update(result) } } }
  • 是的,有很多方法可以做到这一点。如果整个应用程序中有一个 GUI 实例,那么您可以将其设为静态。我认为Calculations 也可以视为实用程序类,因此您可以在其中定义静态方法。为什么要为Calculations 实现Callback 接口?当源将被通知目标更改时使用Callback
【解决方案2】:

您可以创建一个对象来存储选择结果并将其传递给 GUI 类的构造函数。在关闭 UI 之前在该对象中设置选择结果,然后您的 Main 类可以访问该值:

public class SelectionResult {
    private String selectionResult;

    public void setSelectionResult(final String selectionResult) {
        this.selectionResult = selectionResult;
    }

    public String getSelectionResult() {
        return this.selectionResult;
    }
}

然后,您可以像这样修改 GUI 构造函数:

private final SelectionResult selectionResult;

public GUI(Object[] objects, SelectionResult selectionResult) {
    this.selectionResult = selectionResult;
    ...

在 Main 类中创建一个 SelectionResult 对象,并将其传递给 GUI 类的构造函数。在您的 GUI 类 ActionListener 中,您可以使用选定的值调用 setSelectionResult() 方法,并且该值将从 Main 类中可用。

您需要添加代码以使您的 main 方法在等待在 UI 中设置值时等待,然后根据选择继续执行您的逻辑。

【讨论】:

  • Djomrton,非常感谢!事实上,我没有考虑过传递一个对象!但是让主要方法等待的好方法是什么?有什么比 while (true) { if (gui == null) { break; } }?
  • 您可以使用信号量,并将其作为构造函数参数传递:Semaphore semaphore = new Semaphore(0);设置好选择结果后在GUI类中调用.release()方法,在需要等待的main方法中调用.aquire()方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多