I have a issue with java threads and KeyEvents? - java

I need a bit of help with my program here. I have a blocking function waiting in my main thread for the user to click "Enter". Then, when the user hits enter, the keypressed event should fire, which will unblock the blocking function. However, when the program hits the blocking function, it simply freezes up and doesn't register the key pressed event.
So, my question is, is a event a runnable, which is added to a thread whenever the user clicks enter? If so, my code should have worked, right? If this is not the case, and each event is not a separate thread, could anyone enlighten me on how I should fix my problem here?
my blocking function:
public String getInput() {
synchronized(waitObject) {
try {
System.out.println("waiting");
waitObject.wait(); // throws exception, cba to add it here
} catch (Exception ex) {
ex.printStackTrace();
}
}
return(myString);
}
my keylistener code:
public void keyPressed(KeyEvent e) {
System.out.println("key pressed");
char c = e.getKeyChar();
if (c == e.VK_ENTER) {
System.out.println("Enter pressed");
synchronized(waitObject) {
waitObject.notifyAll();
}
}
}
and the function getting the input:
private String getCommand() {
System.out.println("getting command");
CommandField command = new CommandField((JFrame)(this));
command.setPreferredSize(new Dimension(getWidth(), 30));
m_panel.add(command, BorderLayout.NORTH);
validate();
command.requestFocus();
System.out.println(command.getInput());
return null;
}
And this function is called from another keylistener:
public class Listener implements KeyListener {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_F2) {
System.out.println(getCommand());
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}

OK, getCommand() is called on the event thread which then calls getInput() on the same thread, which then calls Object#wait() on the event thread, so yes you are tying up the event thread and effectively freezing your program.
None of this is needed, and a much easier fix is possible if you code using the concepts of event-driven programming. You don't want to call wait() in a Swing GUI and in your situation don't need to call it, but rather you want to change how your program responds to input based on its state. If you tell us more on the exact behavior you're trying to elicit, we can probably help you find a much better solution.
Edit
Consider using a JOptionPane or a modal JDialog for displaying a "blocking" window that stops the main program until the dialog has been dealt with.

Starting with ImageApp, I added the following key binding in the constructor. It will show() the popup menu when pressing the Enter key. You can change the arbitrary location to suit your usage.
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "showPopup");
this.getActionMap().put("showPopup", new AbstractAction("showPopup") {
#Override
public void actionPerformed(ActionEvent e) {
popup.show(ImageApp.this, 42, 42);
}
});
Addendum: To bring up a modal input dialog, so something like this:
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "dialog");
this.getActionMap().put("dialog", new AbstractAction("dialog") {
#Override
public void actionPerformed(ActionEvent e) {
String value = JOptionPane.showInputDialog("What?");
System.out.println(value);
}
});

Related

Starting "asyncExec" in Mouse Down Event results in blocking behavior

Having a "next" Button, when I press keyboard enter key with the button selected, the widgetSelected event of the button is being repeatedly called once and once and doing a super fast next. It's exactly the behaviour I want, but only happens with keyboard enter key.
I want to have that behaviour with mouse click when holding the click. When trying to do the same with the mouse click, the behaviour is not the same, it only makes one event call, and when the click is end (UP). How to simulate the same behaviour with the mouse click?
I tried it doing this, but it blocks the UI (can't understand why) and mouseUp is never being called, it blocks forever in the while:
button.addMouseListener(new MouseAdapter() {
boolean mouseDown;
#Override
public void mouseDown(MouseEvent e) {
System.out.println("mouseDown");
mouseDown = true;
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
while (mouseDown) {
System.out.println("Doing next in mouseDown");
next(composite, label_1);
synchronized(this){
try {
wait(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
}
#Override
public void mouseUp(MouseEvent e) {
System.out.println("mouseUp");
mouseDown = false;
}
});
The Runnable you give to asyncExec runs in the UI thread. You must never do any sort of wait in the UI thread as that will block the UI until it completes.
So you cannot run a loop like this as it just blocks the UI. Since the loop never returns to the main SWT readAndDispatch loop no UI actions are done.
Instead use the timerExec method of Display to schedule a Runnable to run after a given interval. This runnable should do one step of the action and use timerExec to schedule the next step later.
I remember there was another question a few days ago regarding a long mouse click behaviour but I can't find it anymore. I put this code based on greg-449 solution to use timerExec method, after my failed attempts to use asyncExec in the UI thread. :)
button.addMouseListener(new MouseAdapter() {
boolean mouseDown;
#Override
public void mouseDown(MouseEvent e) {
mouseDown = true;
Display.getCurrent().timerExec(1000, () -> {
if (mouseDown) {
button.notifyListeners(SWT.Selection, new Event());
button.notifyListeners(SWT.MouseDown, new Event());
}
});
}
#Override
public void mouseUp(MouseEvent e) {
mouseDown = false;
}
});
button.addSelectionListener(SelectionListener.widgetSelectedAdapter(
e -> System.out.println("Do next")));

Is there any efficient way to keep a thread, which has ActionListener in it's run method, alive until a click event has occured?

boolean flag = true;
public void run(){
// some code
loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
flag = false;
// Some code
}
});
while(flag){}
}
I am using while loop till the actionListener is invoked which I think is silly perhaps. Please let me know if this can be done in more efficient way.
You dont need a Thread for the Listener itself, the Java UI Thread calls your Listener for you.
However if you want your response to the event non-blocking do the following:
// no need for a second thread here
loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// If you dont want to block the UI Thread make a new Thread here
new Thread(YOUR_RUNNABLE).start();
}
}
Related Question

Send Action to button who is listening for it

I have a JButton that has action listener.
btn_.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// DO STUFF
}
}
And I have a JSpinner that listens for key events.
spn_.addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_ENTER)
{
System.out.println("Someone pressed enter key");
}
}
});
What I would like to do, is whenever user presses enter key while the spinner is selected, I would like it to execute whatever command the button does.
Yes I understand that I can simply have a function for the actions button does, and then execute the same function when user presses enter key. I am asking this because I am curious if it is possible for components in Swing to send actions to each other and how to do it rather than what is the correct way to program.
Yes I understand that I can simply have a function for the actions button does, and then execute the same function when user presses enter key. I am asking this because I am curious if it is possible for components in Swing to send actions to each other and how to do it rather than what is the correct way to program.
If you are implying that executing a function is the correct way, I would suggest that is not the best way to solve the problem.
The correct way is to share the Action, not the method that you invoke.
You should NOT be using a KeyListener at all in this solution. The general solution is to use Key Bindings. Read the Swing tutorial on How to Use Key Bindings for more information.
However, in your case it is even a little easier because you can just share the ActionListener:
ActionListener al = new ActionListner() {...}
JTextField editor = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
editor.addActionListener(al);
button.addActionListener(al);
Use doClick() method of JButton:
btn_.doClick()
Within keyPressed as following:
spn_.addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_ENTER)
{
btn_.doClick()
}
}
});
The doClick() method as specified in oracle doc:
Programmatically perform a "click". This does the same thing as if the
user had pressed and released the button.
spn_.addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_ENTER)
{
btn_.doClick(); // fires the actionPerfomed on the button
}
}
});

How can I repeatedly call a method while button is pressed down (Java with Swing)?

I am trying to call a method repeatedly for as long as a button is pressed. But I get an infinite loop. Could anyone help me?
private void jButton6MousePressed(java.awt.event.MouseEvent evt) {
pressed = true;
while(pressed) {
car.accelerator();
}
}
private void jButton6MouseReleased(java.awt.event.MouseEvent evt) {
pressed = false;
}
Thanks.
You get an infinite loop because you have written an infinite loop, you need
JButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
car.accelerator();
}
});
If you want it to repeat the action while it's held own this is more difficult, here is an example of how you do that. In short you need to use threads.
I am pretty sure that once pressed is set to true, you never exit the while loop, so the fact that the button isn't being pressed never registers, the program is stuck. The only thing I can think of is using a timer to check periodically the state of the JButton. Alternatively, you can use multi-threading. That is, have PRESSED be a field in thread 1 that is set by the JButton (as you've done), and have the loop in a thread 2, checking on the status of PRESSED in thread 1.
Edit: Whoops, I see that bmorris591 has already suggested multithreading.
Swing thread enters an infinite loop.
You should run your loop in another thread:
private class BooleanHolder{
bool pressed;
};
final BooleanHolder pressed = new BooleanHolder();
private void jButton6MousePressed(java.awt.event.MouseEvent evt) {
presed.pressed=true;
Thread t = new Thread( new Runnable(){
public void run(){
while(pressed.pressed)
{
car.accelerator();
}
}
}
t.start();
}
private void jButton6MouseReleased(java.awt.event.MouseEvent evt) {
pressed.pressed=false;
}
Without knowing what car.accelerator(); does, it's impossible to make a accurate suggestion.
If car.accelerator() is interacting with the UI in any way, you need to be careful, you should never update the UI from any Thread other then the EDT.
Instead, you could use a rapid firing javax.swing.Timer
private Timer accelerateTimer;
//** ... **//
accelerateTimer = new Timer(15, new ActionListener() {
public void actionPerformed() {
car.accelerator();
}
});
accelerateTimer.setRepeats(true);
//** ... **//
public void mousePressed(MouseEvent me) {
accelerateTimer.restart();
}
public void mouseReleased(MouseEvent me) {
accelerateTimer.stop()
}

How to Interrupt in Java

In Java, let's say I have a GUI with 2 buttons, Go and Pause.
When I press Go, "Hello" gets printed out over and over again. When I press Pause, "Hello" no longer gets printed to the screen.
Example: User presses Go button. "Hello" gets printed out for 1 minute until the user presses "Pause."
What is the proper way to express this approach in Java? Is it equivalent to my commented pseudocode within the goButton source?
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
// while user has not pressed the pause button
printHello();
}
else if(e.getSource() == pauseButton)
{
pause();
}
}
Thanks
In order to get this to work, in reasonable fashion, you will need a Thread. This is executed in the background until such time as you decide to cancel/pause it.
This is an EXTREMELY basic example. Normally I'd wrap the task and the GUI up in appropriate classes rather then accessing static references, but it gives a basic idea
public class TestHello {
private static HelloTask task;
public static void main(String[] args) {
Thread thread = new Thread((task = new HelloTask()));
thread.setDaemon(true);
thread.start();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
JButton goButton = new JButton("Go");
JButton stopButton = new JButton("Stop");
goButton.setActionCommand("Go");
stopButton.setActionCommand("Stop");
ActionHandler handler = new ActionHandler();
goButton.addActionListener(handler);
stopButton.addActionListener(handler);
frame.add(goButton);
frame.add(stopButton);
frame.setVisible(true);
}
public static class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Go")) {
task.start();
} else if (e.getActionCommand().equals("Stop")) {
task.pause();
}
}
}
public static class HelloTask implements Runnable {
private static final Object WAIT_LOCK = new Object();
private boolean dump = false;
public void start() {
synchronized (WAIT_LOCK) {
dump = true;
WAIT_LOCK.notify();
}
}
public void pause() {
synchronized (WAIT_LOCK) {
dump = false;
WAIT_LOCK.notify();
}
}
#Override
public void run() {
while (true) {
while (dump) {
System.out.println("Hello");
}
try {
synchronized (WAIT_LOCK) {
WAIT_LOCK.wait();
}
} catch (Exception e) {
}
}
}
}
}
Some further read:
Java Concurrency
Concurrency in Swing
Caveats
NEVER try and modify the GUI from any thread other then the Event Dispatching Thread.
To have responsive UI you would usually have to run printHello() in separate thread. Then as you do processing in this thread, for example, after every print statement, you check some flag boolean isPaused; and stop execution if it is true. When pause button is clicked you set the value of this flag to true.
You need to implement your loop in a separate thread. Otherwise the GUI will become irresponsive and the user might not be able to click the Pause button at all.
With this threaded approach, you also need a flag which indicates whether or not to print out the message. The printing loop can simply stop executing the thread when the flag is set to no longer print.
what about htis:
boolean flag=true;
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
while(true)
{
printHello();
}
}
else if(e.getSource() == pauseButton)
{
pause();
}
}
You can do this in a few ways the simplest being:
You have a boolean flag, keepPrinting and you set it to true when you push the Go button, false when you push the Pause. Next you have a thread somewhere executing a while loop which will print nothing when keepPrinting is false.
The threading here is really important, without it you're going to have your GUI freeze once the user pushes a button as the program prints hello and happily ignores anything else.
Pseudo Code
//GUI
public ThreadedPrinter greeter;
void ButtonGoPushed(args){
greeter.keepPrinting = true;
}
void ButtonPausePushed(args){
greeter.keepPrinting = false;
}
//ThreadedPrinter
boolean keepPrinting
void run(){
while(true){
if(keepPrinting){
print("Hello");
}
sleep(5); //Make sure that this thread yields if the system doesn't do it automatically
}
The good news about java concurrency versus say C++ is that this will just work, you don't have to worry about the boolean being crazy and inconsistent because in java variable sets are atomic. If you want to do more than just set the variable, make a synchronized method that sets the variable and does anything else you want.
Basically to keep UI responsive such task need to be performed in other thread.
There can be various ways in which you can implement this mechanism in java.
I have used simple mechanism of Runnalbe and volatile flag which ensure that thread exists when you call cancelPrint() method
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
//start the thread here
}
else if(e.getSource() == pauseButton)
{
//call cancel here
}
}
public class HelloPrinter implements Runnable {
volatile boolean cancel = false;
#Override
public void run() {
while (!cancel) {
printHello();
}
}
public void cancelPrint() {
cancel = true;
}
}
I assume you want to do more than just printouts. Take a look at Swing Worker.
It allows you to pretty easily write your GUI-related code that gets executed in the AWT Event Thread and your long-executing code in other thread(s) and pass values back and forth. This will help prevent any GUI lockup issues you might experience.

Categories

Resources