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

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")));

Related

Java: when trying to pause the program, the entire program freezes

I have a program here with buttons. one is a pause button and the other is a resume button. when i click on the pause button the program stops, but when i attempt to click the resume button nothing happens, i can't even click the button or even X out the window. And the click effects on the buttons also dont work. So i'm assuming the program just froze for some reason
public void createButtons() {
fastForwardButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized(this) {
this.notify();
}
}
});
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized(this) {
try {
this.wait();
} catch (InterruptedException e3) {
e3.printStackTrace();
}
}
}
});
}
public static void main(String args[]) {
new Sim().start();
}
Any ideas would be much appreciated, thanks
Update:
The purpose of this program is to have a simulation of a game and i have these 2 buttons were u can pause the game and then resume the game. but all in all, i really just want to pause the whole program and resume it
Went for a small hack, i just placed a while loop in the place i wish to pause and added a isPaused state that will be true or false depending on the button pressed. The while loop will be an infinite loop till someone clicks resume, which will update the state to false and the thing will resume itself. Worked out fine in the end

How to deselect an item in a jList after a certain ammount of milliseconds on a mouseExit event

I have a jList called todoList
When the user click on an item in the list, it stays selected. But I would like the currently selected item in the list to deselect "by itself" after 400 milliseconds when the mouse exits the jList.
This must only run if there is something already selected in the list.
I am using Netbeans IDE and this is what is have tried so far:
private void todoListMouseExited(java.awt.event.MouseEvent evt) {
if (!todoList.isSelectionEmpty()) {
Thread thread = new Thread();
try {
thread.wait(400L);
todoList.clearSelection();
} catch (InterruptedException ex) {
System.out.println(ex);
}
}
}
and
private void todoListMouseExited(java.awt.event.MouseEvent evt) {
if (!todoList.isSelectionEmpty()) {
Thread thread= Thread.currentThread();
try {
thread.wait(400L);
todoList.clearSelection();
} catch (InterruptedException ex) {
System.out.println(ex);
}
}
}
These both just make everything stop working.
My though process was that i need to create a new Thread that will wait for 400 milliseconds and then run the clearSelection() method of the jList. This would happen every time the mouse exits the list and run only if there is something in the list that is already selected.
I hope I am explaining my problem thoroughly enough.
The problem is that you are blocking the AWT-Event-Thread.
The solution is to use a swing timer:
private void todoListMouseExited(java.awt.event.MouseEvent evt)
{
if (!todoList.isSelectionEmpty()) {
new Timer(400, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
todoList.clearSelection();
}
}).start();
}
}
The problem is that Object#wait is waiting(rather than sleeping) to be notified but this is not happening. Instead the timeout causing an InterruptedException bypassing the call to clearSelection.
Don't use raw Threads in Swing applications. Instead use a Swing Timer which was designed to interact with Swing components.
if (!todoList.isSelectionEmpty()) {
Timer timer = new Timer(400, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
todoList.clearSelection();
}
});
timer.setRepeats(false);
timer.start();
}

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

I have a issue with java threads and KeyEvents?

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

To set delay on a button click in java?

I have a save button in a JFrame ;on clicking save the 'save' text sets to 'saving....'; I need to set that text as 'saved' after a delay of 10 seconds.How is it possible in java?
Please help...
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
This is what i did...but this wont shows as 'saving' during that delayed time.
If you want to provide the user with visual feedback that something is going on (and maybe give some hint about the progress) then go for JProgressBar and SwingWorker (more details).
If on the other hand you want to have a situation, when user clicks the button and the task is supposed to run in the background (while the user does other things), then I would use the following approach:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false); // change text if you want
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the calculations
// Wait if you want
Thread.sleep(1000);
// Dont touch the UI
return null;
}
#Override
protected void done() {
try {
get();
} catch (Exception ignore) {
} finally {
button.setEnabled(true); // restore the text if needed
}
}
}.execute();
}
});
Finally, the initial solution that was using the Swing specific timer:
final JButton button = new JButton("Save");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Take somehow care of multiple clicks
button.setText("Saving...");
final Timer t = new Timer(10000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
button.setText("Saved");
}
});
t.setRepeats(false);
t.start();
}
});
This question & first 3 answers are heading down the wrong track.
Use a JProgressBar to show something is happening. Set it to indeterminate if the length of the task is not known, but presumably you know how much needs to be saved and how much is currently saved.
Don't block the EDT (Event Dispatch Thread) - the GUI will 'freeze' when that happens. Use a SwingWorker for long running tasks. See Concurrency in Swing for more details.
The best is to use a timer and its method execute with a delay : http://developer.apple.com/library/mac/documentation/java/reference/javase6_api/api/java/util/Timer.html#schedule(java.util.TimerTask, long). Use a timertask to wrap your runnable and that's it.

Categories

Resources