Search code examples
javaswingjbuttonjtextfield

Make method that returns when JButton is pressed


I need to make a method that returns only when a JButton is pressed. I have a custom JButton class

public class MyButton extends JButton {


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

}

and I want to implement waitForPress. Basically, the method should only return when the user presses the button with their mouse. I have achieved similar behavior for JTextField (to return only when user presses 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);

    }

but I would like to do the same thing with JButton.

In advance: Please, if you wish to comment saying that this is not a good idea and that one should simply wait for actionPerformed event on a JButton and then do some action, please realize I already know that and have a good reason for doing what I'm asking here. Please try to only help with what I've asked. Thanks!!

In advance: Please, also realize that implementing actionPerformed also will not directly solve the problem. Because the code will progress even without the button being pressed. I need the program to stop, and only return when the button has been pressed. Here is a terrible solution if I were to use 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;
   }

}

Solution

  • As you asked for an implementation with a mutex, here's what it would be like. I'm using an ActionListener though, but there's no busy wait in it. If that isn't what you desire, you atleast saw what Burkhard meant ;)

    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();
        }
    }
    

    But I don't think this is a clean approach, but it doesn't consume CPU-time like a while(isStatementTrue)-implementation.
    An important thing here is: you're blocking the main thread with m.waitForPress() but as you wrote you're quite experienced and you know how to handle that.