Cancel anonymous SwingWorker - java

I have run into a weird dependency when trying to cancel an anonymous SwingWorker.
My current code:
private static void init() {
if (connected) {
return;
}
//final SwingWorker<Void, Void> initWorker;
final Timer noConnectionTimer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//initWorker.cancel(true);
waitObject.setTimedOut(true);
connected = false;
waitObject.process();
}
});
new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
noConnectionTimer.setRepeats(false);
noConnectionTimer.start();
cachedInstance = new Network(Config.HOST_NAME, Config.HOST_PORT);
if (connected) {
noConnectionTimer.stop();
new Thread(cachedInstance).start();
waitObject.setTimedOut(false);
waitObject.process();
}
return null;
}
}.execute();
}
First assumption I want to be verified:
I can kill the new Network(Config.HOST_NAME, Config.HOST_PORT) code by killing (cancelling) the SwingWorker.
So assuming my assumption is correct, I want to cancel the anonymous SwingWorker, but when I try to give it a name initWorker, then it needs to be final such that the timer can reference it. However the SwingWorker itself needs to reference the timer aswell, so the timer also needs to be final.
So I think I managed to create a dependancy between two final variables that need eachother, how can I fix this?
Regards.

You don't have to add an ActionListener upon creation. You could just pass null to the Timer's constructor and add the ActionListener afterwards, using addActionListener.

Related

Manually invoke actionPerformed of a javax.swing.Timer

The following Timer works perfectly.
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// ...
}
});
What I want to do is call the actionPerformed() manually. How can I achieve this?
The question seems unclear to the readers, I'll try to explain more.
Timer does some process hourly. I want to do it whenever I want without interfering the timer's process.
Short answer...
A much simpler (and better designed) solution would be, instead of...
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("OK");
}
});
You should externalise the work the ActionListener does...
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
doReallyImportantWorkEveryHour();
}
});
then you remove the Timer from the equation and you can call doReallyImportantWorkEveryHour when you want and solve the fundamental problem
Long Answer
So, let's start with...
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("OK");
}
});
Creating a Timer this way, automatically registers a ActionListener with the Timer.
You then state:
What I want to do is call the actionPerformed() method inside the timer's ActionListener manually. How can I achieve this?
Which suggest you want try and do something like...
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TICK_HOUR.getActionListeners()[0].actionPerformed(null);
}
});
This could cause a NullPointerException, but more importantly, this will have an adverse affect on system performance, as there is no way that the ActionListener will know it shouldn't continuously all itself - basically and infinite loop.
IF however, you wanted to, prematurely, trigger the Timers ActionListeners (outside of any registered listeners)
Then yes, you could use...
ActionEvent evt = new ActionEvent(
TICK_HOUR,
0,
TICK_HOUR.getActionCommand(),
System.currentTimeMillis(),
0);
for (ActionListener listener : TICK_HOUR.getActionListeners()) {
listener.actionPerformed(evt);
}
but make sure you're calling them from within the context of the EDT, as that's one of the guarantees that the Timer makes.
A "simpler" solution might be just to use the functionality that is already provide by the Timer itself...
public class ManuallyTimer extends Timer {
public ManuallyTimer(int delay, ActionListener listener) {
super(delay, listener);
}
public void tigger() {
ActionEvent evt = new ActionEvent(TICK_HOUR, 0, TICK_HOUR.getActionCommand());
fireActionPerformed(new ActionEvent(this, 0, getActionCommand(),
System.currentTimeMillis(),
0));
}
}
Inside a static-initializer-block store ActionListener in a variable instead of passing it directly to the Timer:
private static final Timer TICK_HOUR;
static{
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// ...
}
};
TICK_HOUR = = new Timer(3600000, listener);
listener.actionPerformed(/* someEvent */);
}
You might aswell store the listener variable as a class level static variable and then call it elsewhere from your code:
private static final ActionListener LISTENER = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
// ...
}
};
private static final Timer TICK_HOUR = new Timer(3600000, LISTENER);
And then somewhere in your code
LISTENER.actionPerformed(/* someEvent */);
Use getActionListeners().
Returns an array of all the action listeners registered on this timer.
Returns:
all of the timer's ActionListeners or an empty array if no action listeners are currently registered.
~Java doc~
TICK_HOUR.getActionListeners()[0].actionPerformed(null);
This will throw a ArrayIndexOutOfBoundsException if there are no ActionListeners registered to the timer. So better check the length of the array before using.

Communication between Java Swing Application and Leap Motion Listener

I want to know how I can do a communication between the Java Swing Application and between my leap motion listener.
Because I want that in my application when I click on a button I can change a number with the number of finger see by the leap motion.
I have one Java Swing application :
public class KidCountingFrame extends JFrame
And one Leap Motion Runnable:
public class LeapMouse implements Runnable
{
#Override
public void run()
{
CustomListener l = new CustomListener();
Controller c = new Controller();
c.addListener(l);
}
}
Which is launching a Leap Motion Listener... :
public class CustomListener extends Listener
Maybe I have to use a design pattern ?
* UPDATE : *
I try to applied the ProgressBarDemo on my project and to follow explications.
But one error happens when I put the listener in the SwingWorker constructor :
Exception in thread "Thread-1443" java.lang.NullPointerException: null upcall object
Here my updated code :
public class PanelLeapFingers extends JPanel implements ActionListener,
PropertyChangeListener
{
private JButton digitDisplayButton;
private Task task;
class Task extends SwingWorker<Void, Void>
{
public Task()
{
try
{
NbFingersListener l = new NbFingersListener();
Controller c = new Controller();
c.addListener(l);
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
#Override
public Void doInBackground()
{
// In background :
// Find how digit fingers are shown by the user
int progress = 0;
//setProgress(????); //I don't really know how call the listener here
setProgress(5); //Here it's just to make a test
return null;
}
#Override
public void done()
{
Toolkit.getDefaultToolkit().beep();
digitDisplayButton.setEnabled(true);
setCursor(null); // turn off the wait cursor
}
}
public PanelLeapFingers()
{
super(new BorderLayout());
digitDisplayButton = new JButton("?");
digitDisplayButton.setFont(new Font("Arial", Font.PLAIN, 40));
digitDisplayButton.setActionCommand("start");
digitDisplayButton.addActionListener(this);
JPanel panel = new JPanel();
panel.add(digitDisplayButton);
add(panel, BorderLayout.PAGE_START);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
public void actionPerformed(ActionEvent evt)
{
digitDisplayButton.setEnabled(false);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
task = new Task();
task.addPropertyChangeListener(this);
task.execute();
}
public void propertyChange(PropertyChangeEvent evt) {
if ("progress" == evt.getPropertyName()) {
int progress = (Integer) evt.getNewValue();
digitDisplayButton.setText(progress+"");
}
}
}
I'm not sure to be on the good way and I don't understand how I can receive information from my listener in my setProgress( ) function.
EDIT :
Solution : Finally I have decide to use a Singleton Model to communicate between the listener and the Java Swing APP. I save all informations when the Listener is working in the Singleton Model and I recover the information that I need in the Java Swing APP.
As discussed here, the Listener will be called asynchronously, typically from another thread. To avoid blocking the event dispatch thread, create your Listener in the constructor of a SwingWorker and arrange for your doInBackground() implementation to publish() frames of interest; process() can then handle these frames on the event dispatch thread.
Alternatively, poll the Controller at a suitable rate in the ActionListener of javax.swing.Timer.

How to know when two threads are finished in Swing

I have to perform two tasks. I like two threads perform each task simultaneously. The tasks don't share data.
Before the tasks start, is shown a dialog with a info "Wait, processing...".
Here the codes:
final JDialog dialog = new JDialog(this, true);
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
#Override
protected void done() {
// Must close dialog? The other finished?
}
};
SwingWorker<Void, Void> worker2 = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
#Override
protected void done() {
// Must close dialog? The other finished?
}
};
worker.execute();
worker2.execute();
dialog.setVisible(true);
// Must close dialog?
I would like to close the dialog only when the two threads ended. How to know when they ended? Who and when should close the dialog?
Update: the threads must run simultaneously, not in sequential mode.
Create a CountDownLatch, set to 2
Create your two SwingWorkers, passing each a reference to the CountDownLatch. In there done methods, call countDown on the latch. Do this in the done method, as it will be called regardless of how the doInBackground method exited (ie in case it throws an Exception)
Create a third SwingWorker, passing it a reference to the CountDownLatch, in this worker wait for the latch in the doInBackground method. Once this SwingWorker's done method is called, you should now be able to dispose of the dialog safely
You should call get() on both workers
For now I have made a sample code which will help you to understand the logic behind this.
import java.awt.BorderLayout;
import javax.swing.*;
public class DemoTest {
JFrame frame = new JFrame();
JLabel lbl1 = new JLabel();
JLabel lbl2 = new JLabel();
SwingWorker<Void,Void> worker1 = new SwingWorker<Void,Void>()
{
#Override
protected Void doInBackground() throws Exception {
for(int i = 0;i<=100;i++)
{
lbl1.setText("Counter1 Value:"+Integer.toString(i));
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}
return null;
}
#Override
protected void done()
{
lbl1.setText("Thread 1 completed its job");
worker2.execute();
}
};
SwingWorker<Void,Void> worker2 = new SwingWorker<Void,Void>()
{
#Override
protected Void doInBackground() throws Exception {
for(int i = 0;i<=100;i++)
{
lbl2.setText("Counter1 Value:"+Integer.toString(i));
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}
return null;
}
#Override
protected void done()
{
lbl2.setText("Thread 2 completed its job");
}
};
public DemoTest()
{
frame.setSize(400,400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(lbl1,BorderLayout.NORTH);
frame.add(lbl2,BorderLayout.SOUTH);
frame.setVisible(true);
try
{
worker1.execute();
}
catch(Exception e)
{
e.printStackTrace();
}
//close dialog box
}
public static void main(String []args)
{
DemoTest d = new DemoTest();
}
}
I would use something like a counting lock for this. It is definitely using the least possible resources. The class below is a counting lock. Basically you initialise it with the constructor and specify the number of threads you need to wait for.
In the main thread (or UI thread) you call "waitForAll()" once you are done with setup. You can see that waitForAll is basically waiting for a notify from any other thread. If a notify is received it checks whether or not the number of active workers has reached zero. If the number of active workers is still greater 0 it waits again.
The workers however call unlock() on the lock. Notify decreases the counter by one and calls notify() which makes the main thread wake up and perform the above mentioned procedure.
public class CountingLock {
private int counter;
/**
* Number of workers
*
* #param n
*/
public CountingLock(int n) {
this.counter = n;
}
/**
* Wait until counter == 0
* #throws InterruptedException
*/
public synchronized void waitForAll() throws InterruptedException {
while(counter > 0) {
this.wait();
}
}
/**
* Deduce counter and notify
*/
public synchronized void unlock() {
this.counter--;
this.notify();
}
}
In the dialog prior launching the threads do the following:
CountingLock lock = new CountingLock(2);
/** put your thread setup code from your example here */
lock.waitForAll();
dialog.setVisible(false);
Make sure to pass a reference of lock to your threads and at the end of each thread call the following:
lock.unlock();
As per the comment to this answer, Java as of Java 1.5 (verified) provides a class java.concurrent.CountDownLatch with the exactly same behaviour. The use is well documented in the API.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html
example with CoundDownLatch
CountDownLatch lock = new CountDownLatch(2);
/** put your thread setup code from your example here */
lock.await();
dialog.setVisible(false);
In the threads do the following:
lock.countDown();
full example
final CountingLock lock = new CountingLock(2);
final JDialog dialog = new JDialog(this, true);
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
#Override
protected void done() {
// Must close dialog? The other finished?
lock.unlock();
}
};
SwingWorker<Void, Void> worker2 = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
#Override
protected void done() {
// Must close dialog? The other finished?
lock.unlock();
}
};
worker.execute();
worker2.execute();
dialog.setVisible(true);
lock.waitForAll();
dialog.setVisible(false);
Actually you should also consider to move the waitForAll or await call and setting dialog.setVisible(false) in another background thread since you most likely will not want the UI to stall.

Disable parent frame without stopping thread?

I'm developing a Swing app, and I need to run an infinite loop in the background (which runs until: 1) the cancel button of my JDialog is selected or 2) the input data it is searching for is found) while a modal dialog shows an indeterminate progress bar.
Something I've noticed is that if the JDialog is modal, then the SwingWorker will not execute its tasks until the JDialog is closed (and releases its deathgrip on the EDT, I guess...?). If the JDialog is not modal, then SwingWorker's tasks will execute happily in the background.
I've been doing some research, but I'm no thread/EDT expert and am having a hard time figuring the reason/solution.
Any input on this situation/threads/EDT/SwingWorker, or a suggested solution, would be greatly appreciated.
(Question pulled directly from: http://www.coderanch.com/t/346275/GUI/java/SwingWorker-Modal-JDialogs)
I tried the solution regarding the setVisible call of the JDialog like this user found to be the solution, but I still can't execute both threads simultaneously. Any help would be appreciated.
Relevant:
public Dialog(JFrame parentFrame, String equipmentName) {
super(parentFrame, "Progress");
this.hasRequestedCancel = false;
this.equipmentName = equipmentName;
add(createMainPanel());
setIconImage(Toolkit.getDefaultToolkit().getImage(SomeClass.class.getResource(ICON_PATH)));
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
setModalityType(ModalityType.DOCUMENT_MODAL);
pack();
setSize(550, 100);
setResizable(false);
setLocationRelativeTo(parentFrame);
setVisible(true);
}
And
SwingWorker<File, Void> worker = createSwingWorker(params, ...);
worker.execute();
And
private SwingWorker<File, Void> createSwingWorker(final File someFile, final SomeClass asdf, final String param3) throws IOException {
SwingWorker<File, Void> swingWorker = new SwingWorker<File, Void>() {
#Override
protected File doInBackground() throws IOException {
Dialog progressBar = new Dialog(SomeClass.this, SomeClass.this.equipManufacturerDevice);
try {
while(!someFile.exists() && !progressBar.hasRequestedCancel()) {
Thread.sleep(SomeClass.SLEEP_DURATION);
System.out.println("yo");
}
} catch (InterruptedException e) {
}
...
}
#Override
protected void done() {
...
}
};
return swingWorker;
}
The problem is that you are calling setVisible(true) inside the Dialog’s constructor which is a discouraged practice anyway (you just found one reason, why).
Separate the creation and opening of the dialog and you don’t have that problem anymore. The following sample code demonstrates how this can be achieved:
final Dialog d=new Dialog((Window)null);
d.setSize(300, 300);
d.setModal(true);
new SwingWorker<Object,Object>() {
#Override
protected Object doInBackground() throws Exception {
System.out.println("long running stuff");
TimeUnit.SECONDS.sleep(10);
System.out.println("end of long running stuff");
return null;
}
#Override
protected void done() {
d.dispose();
}
}.execute();
System.out.println("before setVisible(true)");
d.setVisible(true);// will block
System.out.println("after setVisible(true)");
What if you moved the data input logic from the main frame and kept it running on a separate, dedicated, background thread whose sole job is to listen for connections and handle them. This would leave your parent JFrame to handle UI interactions thereby giving you the freedom to freeze it when one of your JDialog has focus.

Synchronizing on a passed object, JFrame is freezing

I created JFrame which contains and InternalFrame which draws figures which are moving(each figure is another Thread) I wanted to pauseButtonmake it pause, so I wanted to synchronize them on the passed object.
But when I hit the pause button the whole window is freezing and I cannot hit the play button
Another thing is that only one is running at the time, I want them all running then all pause.
class A extends JFrame{
....
Object o = new Object();
JButtton pauseButton = new JButton("pause");
JButtton playButton = new JButton("play");
B b = new B(o);
pauseButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
synchronized (synchronizator) {
try {
synchronizator.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
playButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
synchronized (synchronizator) {
synchronizator.notifyAll();
}
}
...
}
class B extends JInternalFrame{
Object o;
B(Object o){this.o = o}
./...
many... C thread = new C(o);
....
}
class C extends Thread{
Object o;
booolean running;
public void run(){
while(running){
synchronized(o){
}
}
}
}
Noooo!! ;)
All Swing activity should be done on the AWT Event Dispatch Thread (EDT). Use normal thread-agnostic objects and perhaps javax.swing.Timer (not java.util!) for timing.
You may want to do other things not involving Swing on different threads, but I suggest keeping a really clean separation. That is to say very few objects should be dealing with thread issues.
If you are using the bare low-level Java synchronisation facilities, set a condition prior to notify/notifyAll and put your waits within while loops.

Categories

Resources