【问题标题】:Java Swing Jbutton accessing a pressed button from another class?Java Swing Jbutton从另一个类访问按下的按钮?
【发布时间】:2015-03-16 04:27:47
【问题描述】:

您好,我在 java 中遇到了这个问题,尝试使用 swing 创建 UI。我遇到了一个我无法解决的问题,需要一些帮助。

我想要发生的是当单击按钮时,它将它传递给在方法 run() 中创建的对象 ui。

public class MainTest{
    public static void main(String[] args){
        MainTest test = new MainTest();
        test.run();
    }

    public void run(){
        UITest ui = UITest();
        ui.start();

        while (true){
            if (ui.getClicked()) break;
        }

        System.out.println("Working this far");
}


public class UITest{
    private JFrame frame;
    private boolean clicked = false;

    public void start(){
        EventQueue.invokeLater(new JframeCreator());
    }

    private class JframeCreator implements Runnable{
        public void run(){
            createUI();
            frame.setVisible(true);
        }
    }

    private void createUI(){
        frame = new JFrame();
        frame.setResizable(false);
        frame.setSize(353, 264);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);

        JButton btnNewButton = new JButton("test");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                clicked = true;
            }
        });
        btnNewButton.setBounds(118, 150, 89, 32);
        frame.getContentPane().add(btnNewButton);

    }

    public boolean getClicked(){
        return clicked;
    }
}       

对我来说,这看起来应该可以工作,但它并没有得到输出“工作这么远”的代码。我点击按钮,没有任何反应

不过,一旦我添加了一个输出值,它确实可以工作。现在,当我单击它运行的按钮时。

public void run(){
    //previous code
    while(true){
        if (ui.getClicked()) break;
        System.out.println("Not working"); //Added
    }

    System.out.println("working this far");
}

我似乎无法弄清楚为什么它会以这种方式工作以及我缺少什么。

希望我说得足够清楚。

【问题讨论】:

    标签: java swing jbutton


    【解决方案1】:

    按钮的单击发生在与运行循环的线程不同的线程中。私有变量的变化对循环线程是不可见的,因此它会继续循环。

    您应该将clicked 变量设为volatile。这将确保对它感兴趣的其他线程可以看到其中的更改。

    打印命令可能会导致内存模型允许新值对该线程可见,但当然,这不是正确的做法。

    当然,在布尔变量上等待一个紧密的循环也不是那么可取的。

    【讨论】:

    • 还没听说过 volatile 关键字。对 Java 和一般编程来说仍然是新手。这只是我正在修改以使用 UI 的旧任务。从现在开始在学习 Swing 的课堂上。谢谢
    • @kyle3794 好吧,Swing 点击在一个单独的线程中工作 - 事件调度线程 - 所以如果你想从一个单独的线程与你的 GUI 交互,你必须学习如何处理多线程。因此,要么留下它,要么在编辑您的问题时解释作业的所有细节,然后也许我们将能够帮助您更好地设计它。作为旁注,请始终检查您发布的代码是否可编译。
    【解决方案2】:

    一种方法是使用观察者设计模式并监听 GUI 中的状态变化。一种方法是通过调用firePropertyChange(...) 方法触发Swing 组件的固有PropertyChangeSupport 来通知侦听器。然后通过addPropertyChangeListener(...) 向该组件注册的所有侦听器都可以侦听此事件。例如:

    import java.awt.*;
    import java.awt.event.*;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    
    import javax.swing.*;
    
    public class MainTest{
       public static void main(String[] args){
          final MtNonGui nonGui = new MtNonGui();
    
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                MtGuiPanel guiPanel = new MtGuiPanel();
                JFrame testFrame = new JFrame("Test");
                testFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                testFrame.add(guiPanel);
                testFrame.pack();
                testFrame.setLocationByPlatform(true);
                testFrame.setVisible(true);
    
                guiPanel.addPropertyChangeListener(MtGuiPanel.PRESS_ME_ACTION, new PropertyChangeListener() {
    
                   @Override
                   public void propertyChange(PropertyChangeEvent evt) {
                      nonGui.buttonPressed();
                   }
                });
             }
          });
       }
    
    }
    
    class MtNonGui {
    
       public void buttonPressed() {
          System.out.println("Button Pressed");
       }
    
    }
    
    class MtGuiPanel extends JPanel {
       public static final String PRESS_ME_ACTION = "press me action";
       private JButton button = new JButton(new PressMeAction("Press Me"));
    
       public MtGuiPanel() {
          add(button);
       }
    
       private class PressMeAction extends AbstractAction {
          public PressMeAction(String name) {
             super(name);
             int mnemonic = (int) name.charAt(0);
             putValue(MNEMONIC_KEY, mnemonic);
          }
    
          @Override
          public void actionPerformed(ActionEvent e) {
             MtGuiPanel.this.firePropertyChange(PRESS_ME_ACTION, false, true);
          }
       }
    }
    

    缺点:

    1. 一个简单的通知有很多代码

    优点:

    1. 这一切都是解耦的——GUI 完全不知道谁在听它,非 GUI 对象也是如此。
    2. 无需无限循环来轮询 GUI 的状态。
    3. 它可以很好地扩展,因此当您的程序变得更大和更复杂时,这不会破坏任何东西。

    【讨论】:

    • 目前有点超出我的范围,但我很乐意对此进行大量试验,并希望尽快理解它,谢谢。
    • @kyle3794:如果您有任何具体问题,请随时提出来。
    【解决方案3】:

    使用某种模式对话框而不是JFrame,并在控件返回到您的代码时检查 UI 的状态。

    一个模态对话框会在它可见时被阻塞。

    public class MainTest{
        public static void main(String[] args){
            MainTest test = new MainTest();
            test.run();
        }
    
        public void run(){
            EventQueue.invokeLater(new Runnable(){
                public void run() {
                    UITest ui = UITest();
                    boolean wasClicked = ui.start();
    
                    System.out.println("Working this far");
                }
         }
    }
    
    
    public class UITest{
        private JDialog frame;
        private boolean clicked = false;
    
        public boolean start(){
            createUI();
            frame.setVisible(true);
            return clicked;
        }
    
        private void createUI(){
            frame = new JDialog();
            frame.setResizable(false);
            frame.setSize(353, 264);
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            // Really, really bad idea
            frame.getContentPane().setLayout(null);
    
            JButton btnNewButton = new JButton("test");
            btnNewButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    clicked = true;
                    dispose();
                }
            });
            btnNewButton.setBounds(118, 150, 89, 32);
            frame.getContentPane().add(btnNewButton);
    
        }
    
        public boolean getClicked(){
            return clicked;
        }
    }       
    

    详情请见How to use dialogs

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-26
      • 2014-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多