【问题标题】:Make method that returns when JButton is pressed按下 JButton 时返回的方法
【发布时间】:2013-01-06 21:58:18
【问题描述】:

我需要创建一个仅在按下JButton 时才返回的方法。我有一个自定义的JButton

public class MyButton extends JButton {


   public void waitForPress() {
       //returns only when user presses this button
   }

}

我想实现waitForPress。基本上,该方法应该只在用户用鼠标按下按钮时返回。我为JTextField 实现了类似的行为(仅在用户按下Space 时返回):

public void waitForTriggerKey() {
        final CountDownLatch latch = new CountDownLatch(1);
            KeyEventDispatcher dispatcher = new KeyEventDispatcher() {
                public boolean dispatchKeyEvent(KeyEvent e) {
                    if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_SPACE) {
                        System.out.println("presed!");
                        latch.countDown();
                    }
                    return false;
                }
            };
            KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher);
            try {
                //current thread waits here until countDown() is called (see a few lines above)
                latch.await();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }  
            KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(dispatcher);

    }

但我想对 JButton 做同样的事情。

提前:如果您想发表评论说这不是一个好主意,应该等待actionPerformed@987654330 上的事件@ 然后做一些动作,请意识到我已经知道了,并且有充分的理由去做我在这里要求的事情。请尽量只帮助我提出的问题。谢谢!!

提前:请注意,实施 actionPerformed 也不能直接解决问题。因为即使没有按下按钮,代码也会继续进行。我需要程序停止,并且只有在按下按钮时才返回。如果我要使用 actionPerformed,这是一个糟糕的解决方案:

public class MyButton extends JButton implements ActionPerformed {
   private boolean keepGoing = true;

   public MyButton(String s) {
       super(s);
       addActionListener(this);
   }

   public void waitForPress() {
       while(keepGoing);
       return;
   }

   public void actionPerformed(ActionEvent e) {
       keepGoing = false;
   }

}

【问题讨论】:

  • 我的第一直觉告诉我你应该实现一个ActionListener...
  • 您始终可以使用模态JDialog,这是一个阻塞调用。
  • @CodeGuy:使用模态 JDialog 似乎是您想要的。然而,我强烈认为这是一个不恰当的设计,并且您当前的代码存在问题。
  • @CodeGuy 我完全意识到这里的潜在问题,并且确切地知道我在做什么 我一直在使用 UI,尤其是 Swing UI,我已经使用了一段时间,我必须说我对后一种说法表示怀疑(没有冒犯)。我看不出你怎么不能把你的代码分成两种方法,并在按下按钮时调用第二种方法。无论如何(对此感到抱歉),但如果你觉得你仍然应该追求那个想法/设计,很遗憾我帮不了你。
  • @CodeGuy 我也不想参加体验战(是的,我读了你的 Jtextfield 示例)。所以这里可能会发生两件事:1)与 EDT 不同的 Thread 正在调用 waitForProcess() 然后,您所需要的只是调用 wait() 并拥有一个调用 notify()ActionListener(这只是基本的Java 线程同步)。 2)你从EDT调用waitForProcess()(然后我参考我之前的声明:将你的代码分成2个方法并在actionPerformed()中调用第二个)

标签: java swing jbutton jtextfield


【解决方案1】:

对于它的价值,这里是你如何使用wait()notify() 来做到这一点,但我觉得这里有一个更深层次的问题。我不认为这是一个令人满意的解决方案:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TestBlockingButton {

    boolean clicked = false;
    private Object toNotify;

    private void initUI() {
        JFrame frame = new JFrame(TestBlockingButton.class.getSimpleName());
        JButton button = new JButton("Click me");
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                clicked = true;
                if (toNotify != null) {
                    synchronized (TestBlockingButton.this) {
                        toNotify.notify();
                    }
                }
            }
        });
        frame.add(button);
        frame.setSize(400, 400);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void waitForProcess() {
        toNotify = this;
        while (!clicked) {
            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        System.out.println("continuing work");
    }

    public static void main(String[] args) {
        final TestBlockingButton test = new TestBlockingButton();
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                test.initUI();
            }
        });
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
        pool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("I was doing something and now I will wait for button click");
                test.waitForProcess();
                System.out.println("User has now cliked the button and I can continue my work");
            }
        });

    }
}

【讨论】:

  • 谢谢。很好的学习榜样。但是,我不得不在上面给出答案,因为它工作正常。
【解决方案2】:

当您要求使用互斥锁实现时,这就是它的样子。 虽然我正在使用ActionListener,但它并没有忙于等待。如果那不是您想要的,那么您至少看到了 Burkhard 的意思;)

public class MyButton extends JButton implements ActionListener
{
    private Semaphore sem = new Semaphore(1);

    public MyButton(String text) throws InterruptedException
    {
        super(text);
        addActionListener(this);
        sem.acquire();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        sem.release();
    }

    public void waitForPress() throws InterruptedException {
        sem.acquire();
        //do your stuff
        sem.acquire();
        //or just
        //waitForPress()
            //if you dont want it to end.
    }

    public static void main(String[] args) throws InterruptedException {
        JFrame frame = new JFrame();
        MyButton m = new MyButton("test");
        frame.add(m);
        frame.pack();
        frame.setVisible(true);
        m.waitForPress();
        //another time, if you only want it to block twice
        m.waitForPress();
    }
}

但我不认为这是一种干净的方法,但它不会像 while(isStatementTrue) 实现那样消耗 CPU 时间。
这里有一件重要的事情:您正在使用 m.waitForPress() 阻塞主线程,但正如您所写的那样,您很有经验并且知道如何处理它。

【讨论】:

  • 感谢您的回答。我还没有尝试过,因为我不确定“//做你的东西”部分是什么?我只希望函数在按下按钮时返回。这就是函数的全部作用。
  • 请删除setPreferredSize(new Dimension(10,10)); 电话。这只是一个非常糟糕的坏习惯。
  • 好吧,这只是一个最小的工作示例。我通常不这样做。但我想我会更好地删除它。
  • @CodeGuy //做你的东西是当块结束时将被执行的代码。如果你不想要那个,就离开它。 sem.aquire() 将在按下按钮时阻塞并返回。
  • @Zhedar 完美!!!你已经解决了答案。非常感谢。另外,Guillaume Polet,也感谢您的考虑和帮助。
猜你喜欢
  • 1970-01-01
  • 2013-11-03
  • 1970-01-01
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-11
  • 1970-01-01
相关资源
最近更新 更多