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.
Related
just a question about SwingUtilities.InvokeLater().
To my understanding, any time I update my Swing interface I need to call SwingUtilities.InvokeLater to get onto the EDT. Does this need to be done if I am attempting to update my GUI from a button listener, as they button events are already on the EDT?
i.e, would i have to..
public void mouseClicked(MouseEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//GUI updates
}
});
}
or would I simply be able to...
public void mouseClicked(MouseEvent e) {
//GUI updates
}
Furthermore, Does the same logic apply if I am calling a method on an object that will update the GUI?
any time I update my Swing interface I need to call SwingUtilities.InvokeLater to get onto the EDT
Correct. This includes any time you update the model of the component, since this will also result in the repainting of the component.
Does this need to be done if I am attempting to update my GUI from a button listener, as they button events are already on the EDT?
Again correct. Since the code is automatically invoked on the EDT you do not need to manually add it to the EDT using the invokeLater().
You typically use the SwingUtilities.invokeLater() if your code is executing on a separate Thread and part of that logic needs to update a GUI component.
Updating this message :
Swing event handling code runs on a special thread known as the event dispatch thread. So all of the component(button, checkbox, radio button etc.,) actions are handled on EDT. So no need to have SwingUtilities.invokeLater() inside your button action as it always runs on EDT.
Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive.
So if you are planning to perform a long running task that could affect a GUI inside an action then better go for Worker Threads or Background Threads.
SwingWorker has doInBackground(), done() and process() methods to handle the long running tasks well without impacting the GUI.
Go through below links to get more info
Why does SwingUtilities.invokeLater() cause JButton to freeze?
What does SwingUtilities.invokeLater do?
https://www.javacodegeeks.com/2012/12/multi-threading-in-java-swing-with-swingworker.html
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..)
When we implement Listener, Renderer or Editor, inside methods how Java its calling automatically?
Code:
Class A implements ActionListener{
A(){
//bla bla
//bla bla
this.addActionListener(btn);
}
public void actionPerformed(ActionEvent e){**// How actionPerformed method called //automatically if we register button**
}
}
How its calling actionPerformed method automatically after registering button object? We are just passing the btn object into addActionListener(btn). How inside its calling that method?
I checked through netbeans inside addActionListener method*. There is no calling method of actionPerformed method. Also if we register it keeps on working. Is it calling by thread anywhere inside? But i checked source code. nothing is there. How?
Events are dispatched from an EventListenerList, owned by the parent JComponent, using a convention outlined in the API and discussed here. Editors and Renderers are evoked by the owning view component.
Addendum: Can we create interface same as it is? How?
Yes, JFreeChart is a fairly accessible example. Although a chart is not itself a JComponent, it uses the same model for its own events.
In Java, anything which happens upon any windows component is dealt with by the Event Dispatcher Thread:
The event dispatching thread (EDT) is a background thread used in Java
to process events from the Abstract Window Toolkit (AWT) graphical
user interface event queue. These events are primarily update events
that cause user interface components to redraw themselves, or input
events from input devices such as the mouse or keyboard.
Whenever you click or do some event, it is the EDT which kick starts the action listener, which is why doing any Thread.sleep in your action listener will eventually freeze the UI for a period of time.
Since your class implements a given interface, your class will guarantee the EDT that it will have a series of methods which the EDT can use to do whatever it needs.
For more information on the EDT, please take a look at this Oracle document.
It's magic.
Event handling is taken care of for you by the AWT API. These events are then queue and dispatched to the various components (via a serious of steps). Each interested party then handles those requests that are of interest to them before passing them up the food chain till it reaches you.
The question is, should you care?
In some respects yes, but do you care how electricity works or just that you can turn on the light switch?
I'm sure there's better documentation, but you could take a look at http://docs.oracle.com/javase/1.3/docs/guide/awt/designspec/events.html for starters...
Swing calls your ActionListener automatically when the action occurs. The actual method call is located deep inside the source code of Swing.
I have a JWindow and a JFrame both I have made runnable and both implement a mouse listener.
I have alot of testing to do for a project of mine and to simplify it I wish to be able to automate most of it, so I have starting my own mouse recorder and replayer (uses Java Robot Class).
Kinda like a simplified AutoHotKey or AutoIt thing... but it'll run on my Ubuntu machine aswell as my Windows one!!!
The JWindow I have made is translucent and covers the entire screen, when you click on it it disappears and replays the click to the object behind and then reappears. This is the recording process. When the User right clicks the is set to not visible and the recorded actions are replayed.
During replay I want the option to be able to exit the entire application and so I though the best way to do this would be to make the JFrame and the JWindow Runnable.
The JFrame is simply their to offer a close option from the application.
So, in my Main class I have
public static void Main(String[] args){
recorder = new Recorder();
gui = new GUI();
Thread tr = new Thread(recorder);
Thread tg = new Thread(gui);
tr.setName("Recorder");
tg.setName("GUI");
tr.start();
tg.start();
}
My understanding is Recorder and GUI are runnable objects and they are made into threads via the new Thread command. When I use .start() I am beginning the execution of the thread and from here on the system decides which thread is running at any particular time.
Onto the Recorder and GUI classes.
public class Recorder
implements Runnable, MouseListener {
//Constructor and other code
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
//Record events
}else{
//Replay events
}
System.exit(0);
}
public void run() {
System.out.println("Recorder");
}
}
public class GUI
implements Runnable, MouseListener {
//Constructor, simply constructs JFrame and sets mouselistener to it
public void mouseClicked(MouseEvent e) {
System.exit(0);
}
public void run() {
System.out.println("GUI");
}
}
My application prints out Recorder and then GUI
Allows me to record my events
then right click on the JWindow to replay them...
but then when I click on the JFrame's close button or even in the frame because of the mouse listener it won't exit until all of the actions have been fully replayed?
One thing I did wonder is what ever I put in run is what is what keeps the thread running? So when System.out.println(""); is executed the thread dies? So I tried a while loop around them and my application successfully prints
GUI
GUI
GUI
RECORDER
RECORDER
GUI
RECORDER
etc
etc
So I can see that they threads are running concurrently... it's just that all of the other actions outside of the run don't seem to get executed... How can I include my mouse listener, etc within the threads execution?
You are confusing Threads with Objects. When you have an Object that is a Runnable that just gives a starting point for a Thread. However this doesn't mean that when another thread (in this case the Event thread that handles the MouseListener) calls a method in your Runnable that it executed by the thread that is executing the Runnable. When a method is called, it never switches to another thread. If you want this you need a mechanism. For instance a queue that the MouseListener can post tasks to, and in your Runnable.run() you then keep looking for a new task.
When swing initializes it starts it's own Event Dispatch thread. All your listener methods executes within this thread. It doesn't matter whether or not your listener object implements runnable.
See this tutorial to grasp the basics of multi-threading in context of Swing. http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html
The actual answer to your question is in this part of the tutorial:
http://java.sun.com/docs/books/tutorial/uiswing/concurrency/cancel.html
But I suggest that you go through the whole tutorial.
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.