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.
Related
I'm writing a Java program that acts as both a server and a client. Leaving out the irrelevant bits it has three classes: Main, Server and Client. Main just sets up a menu and contains the main method. Server and Client hold the algorithms for the server and the client respectively.
What I'm trying to do is to call the algorithm from the server and client classes and their GUIs depending on the button pressed. The code to call the server currently looks like this:
serverButton = new JButton();
serverButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
server.showGUI();
server.run();
}
});
The problem is that server.run() runs continuously for quite a long while and is a lot of heavy lifting. This bugs out the GUI, which from my understanding is because I'm calling the method from the EDT.
How can I call this method from the main thread? Do I need to create a SwingWorker and leave it there until the end of server.run()?
How can I call this method from the main thread?
This is how it is usually done in Swing.
public class WhatEverServer {
private UserInterface userInterface;
[...]
private static void createAndShowGUI() {
if( GraphicsEnvironment.isHeadless() )
logger.log( Level.FATAL, "This system seems to be 'headless'. Aborting now." );
else {
userInterface = UserInterface.getInstance();
userInterface.createAndShowUI();
}
}
public static void main( String[] args ) {
// schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater( new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
public class UserInterface {
...
public void createAndShowUI() {
// make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
// create and set up the window.
JFrame frame = new JFrame( "Whatever Server" );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set UI components, i.e
// set main menu bar
frame.setJMenuBar( this.mainMenuBar );
// set layout
frame.getContentPane().setLayout( new BorderLayout() );
// add UI components
// display the window.
frame.pack();
frame.setVisible(true);
}
}
This bugs out the GUI, which from my understanding is because I'm
calling the method from the EDT.
Yes, since the action is triggered by an event, the actionPerformed() is invoked by (or on) the EDT. I don't know what you are doing in server.run(), but I suppose this should not end up on the EDT.
Do I need to create a SwingWorker and leave it there until the end of
server.run()?
I would use SwingWorker or SwingUtilities in that case. You can write an ActionHandler in this way, using two threads, one for doing some of the 'heavy lifting', one for setting up the UI :
public void actionPerformed(ActionEvent e) {
new Thread(new Runnable {
public void run() {
...
// do some 'heavy lifting' here ...
SwingUtilities.invokeLater(new Runnable() {
public void run() {
server.setupUI();
}
)
...
// or do some 'heavy lifting' here
});
}
}
Make sure the server object reference is final and then invoke the method in a new thread in your actionPerformed method.
Runnable task = () -> {server.run();};
Thread thread = new Thread(task);
thread.start();
It depends on your requirement, if you want the user do not want anything to do until server returns, it is best to do it in a Busyindicator like :
public void actionPerformed( ActionEvent e )
{
BusyIndicator.showWhile(Display.getCurrent(), new Runnable()
{
#Override
public void run()
{
server.run();
}
});
}
This will show user a hour glass while the server run is going on and user is blocked from using UI.
Or
if you want the UI to be responsive, you need to call server.run() in a separate thread.
MyThread t = new MyThread()
{
public void run()
{
server.run();
}
}
t.start();
and it is good practice to add a listener to thread to notify completion of server response so UI can do its things.
t.addListener( new MyThreadListener()
{
public void serverDone()
{
Display.getDefault().asyncExec( new Runnable()
{
public void run()
{
}
});
}
});
Please note this is not complete code for thread listener, just for idea sake.
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.
I've hit the infinite loop problem in Swing. Done some research and come across SwingWorker threads but not really sure how to implement them. I've knocked together a simple program that shows the problem. One button starts the infinite loop and I want the other button to stop it but of course due to the Swing single thread problem the other button has frozen. Code below and help appreciated:-
public class Model
{
private int counter;
private boolean go = true;
public void go()
{
counter = 0;
while(go)
{
counter++;
System.out.println(counter);
}
}
public int getCounter()
{
return counter;
}
public void setGo(boolean value)
{
this.go = value;
}
}
public class View extends JFrame
{
private JPanel topPanel, bottomPanel;
private JTextArea messageArea;
private JButton startButton, cancelButton;
private JLabel messageLabel;
private JScrollPane scrollPane;
public View()
{
setSize(250, 220);
setTitle("View");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
topPanel = new JPanel();
bottomPanel = new JPanel();
messageArea = new JTextArea(8, 20);
messageArea.setEditable(false);
scrollPane = new JScrollPane(messageArea);
messageLabel = new JLabel("Message Area");
topPanel.setLayout(new BorderLayout());
topPanel.add(messageLabel, "North");
topPanel.add(scrollPane, "South");
startButton = new JButton("START");
cancelButton = new JButton("CANCEL");
bottomPanel.setLayout(new GridLayout(1, 2));
bottomPanel.add(startButton);
bottomPanel.add(cancelButton);
Container cp = getContentPane();
cp.add(topPanel, BorderLayout.NORTH);
cp.add(bottomPanel, BorderLayout.SOUTH);
}
public JButton getStartButton()
{
return startButton;
}
public JButton getCancelButton()
{
return cancelButton;
}
public void setMessageArea(String message)
{
messageArea.append(message + "\n");
}
}
public class Controller implements ActionListener
{
private Model theModel;
private View theView;
public Controller(Model model, View view)
{
this.theModel = model;
this.theView = view;
view.getStartButton().addActionListener(this);
view.getCancelButton().addActionListener(this);
}
public void actionPerformed(ActionEvent ae)
{
Object buttonClicked = ae.getSource();
if(buttonClicked.equals(theView.getStartButton()))
{
theModel.go();
}
else if(buttonClicked.equals(theView.getCancelButton()))
{
theModel.setGo(false);
}
}
}
public class Main
{
public static void main(String[] args)
{
Model model = new Model();
View view = new View();
Controller controller = new Controller(model, view);
view.setVisible(true);
}
}
You can do it easily without implementing any timer, you just need to add two lines to your actionPerformed method:
public void actionPerformed(ActionEvent ae)
{
Object buttonClicked = ae.getSource();
if(buttonClicked.equals(theView.getStartButton()))
{
theModel.setGo(true); //make it continue if it's just stopped
Thread t = new Thread(new Runnable() { public void run() {theModel.go();}}); //This separate thread will start the new go...
t.start(); //...when you start the thread! go!
}
else if(buttonClicked.equals(theView.getCancelButton()))
{
theModel.setGo(false);
}
}
As your Model.go() is running in a separate thread, the Event Dispatch Thread is free to do its stuff, like drawing the button released again, instead of hanging with the button down.
There's a catch! however, because the thread running Model.go() will run wildly!, it's virtually called as many times per second as your system can.
If you plan to implement some animation or the like, then you will need to:
use a Timer,
or
add some sleep time to the new thread.
Example if you go with threads:
public void go()
{
counter = 0;
while(go)
{
counter++;
System.out.println(counter);
try {
Thread.sleep(1500); //Sleep for 1.5 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
As you can see I added Thread.sleep(1500) being 1500 the time in milliseconds (1.5 seconds). Thread.sleep can be interrupted for some reasons, so you must catch the InterruptedException.
It's not necessary to go deeper on handling correctly the InterruptedException in this particular case, but if you feel curious about it you can read this nice article.
You are blocking the Event Dispatch Thread (EDT). The thread is responsible to process painting and other UI related requests. Once EDT is blocked the UI will become frozen since it cannot process any events. For more details see The Event Dispatch Thread tutorial.
Consider using timers (How to Use Swing Timers), SwingWorker or an auxiliary background thread. Background thread can communicate with EDT using SwingUtilities.invokeLater(). This mechanism is already implemented in SwingWorker, so it may be easier to go with it. It depends on functionality that is required.
Use a javax.swing.Timer to do the go() work once, (with some optional delay), using start() and stop() in the event handling.
I decided to use a SwingWorker thread and below is the updated Controller class. It does what I need it to do but my question is, is it the correct way and is it clean code? Also, I've tried getting the output of the model.go() method into the view's textarea as per the commented out lines but not been succesful, anyone know how?
public class Controller implements ActionListener
{
private Model theModel;
private View theView;
private SwingWorker<Void, Void> worker;
public Controller(Model model, View view)
{
this.theModel = model;
this.theView = view;
view.getStartButton().addActionListener(this);
view.getCancelButton().addActionListener(this);
}
public void actionPerformed(ActionEvent ae)
{
Object buttonClicked = ae.getSource();
if(buttonClicked.equals(theView.getStartButton()))
{
theModel.setGo(true);
worker = new SwingWorker<Void, Void>()
{
#Override
protected Void doInBackground()
{
// theView.setMessageArea(theModel.getCounterToString());
return theModel.go();
}
#Override
protected void done()
{
// theView.setMessageArea(theModel.getCounterToString());
}
};
worker.execute();
}
else if(buttonClicked.equals(theView.getCancelButton()))
{
theModel.setGo(false);
}
}
}
public class Model
{
public Void go()
{
counter = 0;
while(go)
{
counter++;
System.out.println(counter);
}
return null;
}
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.
When the program starts, a new JFrame is created. Once the user clicks the start button a thread is created and started. Part of this threads execution is to validate the data on the form and then execute with that data. Once the data has been validated the thread calls dispose() on the original frame and then creates a new JFrame that acts as a control panel.
There is also an automatic mode of the program that doesn't display any GUI at all, this mode reads data from a configuration file and then starts the execution thread and runs everything but without the control panel.
I want the program to end once the thread completes, but in GUI mode, only if the user has closed the control panel as well.
Is it possible to make the thread wait for the frame to close. I assuming that the frame is run from it's own Thread? or is that not the case.
Thanks.
The answer you chose is a little awkward. Using Thread.sleep(1000) will check for window state every second. It is not a performance issue, but just bad coding style. And you may have a one second response time.
This code is a little bit better.
private static Object lock = new Object();
private static JFrame frame = new JFrame();
/**
* #param args
*/
public static void main(String[] args) {
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
Thread t = new Thread() {
public void run() {
synchronized(lock) {
while (frame.isVisible())
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Working now");
}
}
};
t.start();
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent arg0) {
synchronized (lock) {
frame.setVisible(false);
lock.notify();
}
}
});
t.join();
}
You can make reference from your thread to the JFrame. Then set the default close operation of JFrame to HIDE_ON_CLOSE. If the JFrame is closed, you can stop the thread.
Example code:
import java.awt.Dimension;
import javax.swing.JFrame;
public class FrameExample extends JFrame {
public FrameExample() {
setSize(new Dimension(100, 100));
setDefaultCloseOperation(HIDE_ON_CLOSE);
setVisible(true);
}
private static class T implements Runnable {
private FrameExample e;
public T(FrameExample e) {
this.e = e;
}
#Override
public void run() {
while (true) {
if (e.isVisible()) {
// do the validation
System.out.println("validation");
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
break;
}
}
}
}
}
public static void main(String[] args) {
FrameExample frameExample = new FrameExample();
new Thread(new T(frameExample)).start();
}
}
All Swing components, including JFrame, are managed by a single thread, called the Event Dispatch Thread, or EDT. (It's possible to call methods on Swing objects from other threads, but this is usually unsafe, except in a few cases not relevant here.)
You'll probably accomplish what you want here by putting the data validation and execution code in its own object which is otherwise completely unaware of the outside world. Then, call it from one of two other objects: one that manages a GUI, and another that runs in "automatic mode".