In Java, what event is *continuously* fired on mouse button down? - java

I would like to know if there exists in Java an event that is continuously fired when a mouse button is being held down (pressed), even if the mouse is not moved. I could not find it in typical MouseListeners:
MouseDragged is fired only if the user move the mouse while holding the button down
MousePressed is fired only once when the button has been pressed
And that's about it.
Any idea how to make such an event?
Cheers
jy

There is an obvious reason why this event is not available in MouseListener: it's going to spam you with events such that everything is slowed down to a halt. Do you want to receive this event every second, every ms, or even more often? If you need that you'll have to do it yourself.
For stearing this process you of course need mousePressed and mouseReleased to determine whether a button is currently held down. Then you need to run some kind of loop that generates the corresponding events you'd like to have.
You might also want to work via polling, i.e. extend your MouseListener class such that it can tell you whether a button is still held down, and whereever you need those events you can actively poll for the button. It depends on how you want to use these events, which approach is more suitable.

If you need to do something whilst the mouse button is down, just start it when you detect a mousePressed event and then continuously do that until you detect a mouseReleased event. Then you don't need to have your event continuously firing. e.g.
public void mousePressed(MouseEvent e) {
someCondition = true;
while(someCondition) {
//do something
}
}
public void mouseReleased(MouseEvent e) {
someCondition = false;
}
EDIT:
As others have said, the code would need to be separated from the event thread otherwise the call to mouseReleased would get blocked preventing the loop from ending.

James Goodwin's code will not work. mousePressed and mouseReleased are both fired from the GUI thread, so blocking in mousePressed will prevent mouseReleased from ever being fired, meaning the loop will continue forever.
If you already have a seperate thread for processing then use mousePressed to indicate to that thread that the event should start, and mouseReleased to stop.
If you don't have a separate thread and don't want the hassle, a Timer is probably the easiest way. javadoc on Timer.
Specifically, you should create a TimerTask that does whatever it is you want to do multiple times and queue it using Timer.schedule:
Timer timer = new Timer();
TimerTask task = new MyTimerTask();
private class MyTimerTask extends TimerTask {
public void run() {
// your code here
}
}
public void mousePressed(MouseEvent e) {
timer.scheduleAtFixedRate(task, 0, 1000); // Time is in milliseconds
// The second parameter is delay before the first run
// The third is how often to run it
}
public void mouseReleased(MouseEvent e) {
task.cancel();
// Will not stop execution of task.run() if it is midway
// But will guarantee that after this call it runs no more than one more time
}
I'm pretty sure this is the simplest way, as it doesn't involve faffing around with inter-thread communication.
Oh, and as Peter said, you will have to add code to account for the user mousing down on your app and mousing up somewhere else.

There is no such event
You can create your own by starting a timer in the mousedown method and ending the same timer in the mousereleased
You will also need a few fail saves to make sure the timer stops when you do mousedown the movemove onto another component or even onto other frame or non java gui parts

I think you'll find the answer is no, there is no such event. Not just for Java, but for any GUI framework. It would serve no purpose other than to tie up the event queue.
You would need to create your own by trapping the mouse down event then having a timer fire events at regular intervals until the mouse up event.

Related

Value of JLabel is not being updated using setText() in Java

I know many people have asked this question before but I couldn't find any answer that solved my problem. My code is like this:
public void mouseClicked(MouseEvent arg0) {
TEXT.setText("ON");
myfunction(); //runs for a very long time
}
The original text of JLabel is "OFF". Now I want to change the text to "ON" when the mouse is clicked but the text doesn't set until myfunction() is complete (which may take several minutes).
I have tried the invalidate function, making a separate function for setting the text but nothing is working.
Please help me with this problem!
The problem is that mouseClicked(...) is executed on the UI Thread. That is the Thread that is responsible for handling all sorts of user actions (like a mouse click) and also the drawing of components (like updating the text of the label on screen). If you execute your long running method call on the UI thread, it will be blocked and can't draw anything until execution is complete. You'll have to use multi threading to get around this problem.
The following might not be the most elegant solution, but if you are new to multi threading it will get the job done:
public void mouseClicked(MouseEvent arg0) {
TEXT.setText("ON");
(new Thread() {
public void run() {
myfunction();
}
}).start();
}
It will spawn a new Thread that handles your method, which will let the UI Thread continue doing its thing. consider deactivating the button that has just been clicked, so the user can't start the execution while it is already in progress (which usually is what you want..)

JTextfield not updating till end of JButton action performed method? Tried using repaint,sleep still no use [duplicate]

I'm creating a board game using a GUI and JFrames/JPanels where you can play against the computer. I have a method called showPieces() which updates board GUI by changing the image icons on an array of buttons (which are laid out in a grid format). Once the icons have been updated the revalidate() and repaint() methods to update the GUI.
The showPieces() method has a parameter that needs to be passed to it every time it is called.
The main issue I'm having is I want the human to make a move, update the GUI, wait 1 second, the computer makes it's move and then loop until someone wins.
My basic code is the following:
do{
human.makeMove();
gui.showPieces(data);
try {
Thread.sleep(1000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
computer.makeMove()
gui.showPieces(data);
}while(playing);
This cause the issue where when the human player makes their move, the GUI will freeze for one second and then after the delay, both moves are made at the same time.
I hope it makes sense, but I'm a novice with Java and may have to look more into threading as I don't understand it well enough.
Thread.sleep() is done on the Event Dispatch Thread which will lock the GUI.
So If you need to wait for a specific amount of time, don't sleep in the event dispatch thread. Instead, use a timer.
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
}
};
new Timer(delay, taskPerformer).start();
As with most all similar Swing questions, you're putting your entire Swing GUI to sleep by calling Thread.sleep(...) on the GUI's event thread (the EDT or Event Dispatch Thread), and when during this period the GUI will not be able to update its images or interact with the user whatsoever. The solution here is not to use Thread.sleep(...) but rather to use a Swing Timer to cause your 1 second delay.
Swing Timer Tutorial.

Why does my timer event start triggering faster and faster every time I start it again?

I need a timer for a game I am building and what it basically does is fire up an event that moves and object a square every second when I hit play. Now either I let the game take its course(the game finishes or the object moves out of bounds) or press play once again, the timer seems to be triggering the object to move faster than previously and so on, going faster and faster every time I restart the time.
private void playButtonMouseClicked(java.awt.event.MouseEvent evt) {
/*code*/
timer = new Timer(timerSpeed, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
/*code that ends with something that calls timer.stop()*/
}
}
});
if(timer.isRunning()) //in case I don't let the game stop the timer
timer.stop();
timer.start();
}
I checked with timer.getDelay() and the delay doesn't change, it stays the same, but I can see the arrow moving faster and faster every time. I'm using jPanels and a label with and icon to display the grid and the moving object.
Any ideas?
but I can see the arrow moving faster and faster every time.
This tells me you have multiple Timers executing.
Your current code creates a new Timer every time the button is clicked.
The timer.isRunning() check will never be true because you just created a new Timer which will not be running since you haven't started it yet.
So your old Timer may still be running but because you no longer have a reference to it, you can't stop it.
The solution:
Don't create a new Timer object every time you click the button. The Timer object should be created in the constructor of your class. Then you just start/stop the Timer as required

stop mouseEntered execution when mouse exits the element JFrame

my app plays different sounds when entering the area of different buttons. when the mouse exits the area of a button, i want all sounds to stop. i start the sounds in the mouseEntered method, and stop them in the mouseExited method:
#Override
public void mouseEntered(MouseEvent mouse) {
allForms.playSounds(mouse);
}
#Override
public void mouseExited(MouseEvent mouse) {
allForms.stopSounds(mouse);
}
the problem is the mouseEntered method won't stop it's execution in the middle to start executing mouseExited.
is there a way to solve this problem?
You appear to be calling a long-running bit of code on the Swing event thread, tying up the thread. A solution is to call the playSounds in a background thread which should free up the Swing thread so that it responds to you and will hopefully allow you to call stopSounds. A SwingWorker can help you create a background thread and allow its code interact with swing in a thread-safe manner.
As an aside, another way to trigger your code would be to listen to your JButton's ButtonModel for roll over events.
Edit
You state in comment:
is it possible to use SwingWorker without having to extend the class? my class already extends JFrame.
Your SwingWorker could be in its own class, or could be an anonymous inner class if it's small enough. If separate, it would be part of your "control" code, assuming that you've factored your code into an M-V-C pattern (or Model-View-Control).
For what it's worth, I rarely if ever create GUI code that extends a top level window such as a JFrame, and avoiding this has saved me from problems and frustration.

Java - Waiting for some type of key press to continue

What is the best way to implement a "press x to continue" type of thing in Java?
Specifically, I have a custom class which extends JFrame and a custom class which extends JPanel. I have a Main.java (which has an instance of my JFrame class), and there is a point where I do not want to continue until the user has pressed the space bar:
Main.java:
...code...
frame.waitForSpace();
...more code which gets executed only after space is pressed...
So, in my frame class, how should I implement this:
MyFrame.java:
/* This method only finishes when the space bar is pressed */
public void waitForSpace() {
}
By the way, I have the KeyListener on my JFrame which works when the space button is pressed. But I'm not quite sure how to incorporate that into what I'm trying to do.
Example code would be awesome!
Put whatever you want to do when the user presses space into that handler. Most likely you don't want to do (whatever) every time the space bar is pressed, but only some of the time; therefore the event handler should be contingent on the value of some variable, and the code that runs before you want the user to press space should set that variable to the value that means "do it." The handler should set the variable back to the the default value after it runs.
Remember that Swing GUI's are event driven. So don't wait for anything. Instead give your class a state field of some sort, perhaps a boolean, change the state variable on key press, perhaps using key bindings, and then don't allow certain behaviors unless the state has been changed (via if statements).
Using a CountDownLatch when await() is invoked, the current main() thread will wait until the countDown() method is called from another thread.
The KeyEventDispatcher lets you add a keystroke listener globally. So whenever a key is pressed dispatchKeyEvent() gets called from the EDT (Event Dispatching Thread) and there you can check for 'space' being pressed and release the countdown latch that main() is waiting on.
However, if the thread that calls waitForSpace() is the EDT, then you will be forcing the EDT to wait for itself, causing deadlock. It is impossible to wait on the EDT and still receive key events as far as I know.
This will work so long as a JFrame has focus:
public void waitForSpace() {
final CountDownLatch latch = new CountDownLatch(1);
KeyEventDispatcher dispatcher = new KeyEventDispatcher() {
// Anonymous class invoked from EDT
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE)
latch.countDown();
return false;
}
};
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher);
latch.await(); // current thread waits here until countDown() is called
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(dispatcher);
}
Don't use a KeyLIstener.
Use Key Bindings. You've already been given a link to the key bindings tutorial.

Categories