I have a class MyModel with a property datalogEnabled (and other ones, but let's start there) that I would like to be able to implement properly for use with UI/view binding.
public class MyModel {
static final String KEY_DATALOG_ENABLED = "datalogEnabled";
final private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
final private Object syncLock = new Object();
final private Datalogger datalogger = new Datalogger();
public void addPropertyChangeListener(PropertyChangeListener pcl)
{
this.pcs.addPropertyChangeListener(pcl);
}
public void removePropertyChangeListener(PropertyChangeListener pcl)
{
this.pcs.removePropertyChangeListener(pcl);
}
public boolean isDatalogEnabled()
{
synchronized (this.syncLock)
{
return this.datalogEnabled;
}
}
public void setDatalogEnabled(final boolean enable) {
boolean old;
synchronized (this.syncLock) {
old = this.datalogEnabled;
this.datalogEnabled=enable;
}
/* begin snippet X: this is wrong for threading reasons */
this.pcs.firePropertyChange(KEY_DATALOG_ENABLED, old, enable);
setDatalogEnabledNow(enable);
/* end snippet X */
}
setDatalogEnabledNow(boolean b)
{
this.datalogger.setEnable(b);
}
/* other methods */
}
public class Datalogger() {
public void setEnable(boolean enable) { ... }
}
Except for snippet X, this seems right, but I'm not sure. What's getting me is that the various ways of accessing/setting/listening to the property may happen on different threads, and what I need to do is to act upon the datalogEnabled property somewhere (do some file I/O) within my Datalogger class, on another thread besides the Swing UI thread, because I don't want the UI thread to be unresponsive.
How can I properly rewrite snippet X?
In my overall program, I have an instance of ExecutorService. I could add an Executor (superclass of ExecutorService) as a constructor parameter in the MyModel class, and do this for snippet X:
this.pcs.firePropertyChange(KEY_DATALOG_ENABLED, old, enable);
this.executor.execute(new Runnable() {
#Override public void run() { setDatalogEnabledNow(enable); }
});
Should I put the firePropertyChange call into the deferred Runnable task as well? (is firePropertyChange supposed to be called immediately or after a property change really takes effect)
Or should the Datalogger class have an Executor as well so it can coordinate various tasks?
I'm confused on this one....
The listeners of a model can be uis components, or domains components. If a listener is a ui component, it must run on the edt, and not if the listener is domain.
The event come from a ui component, or from a domain component. If the event come from a ui component, the fire method is on the edt, and it is not if the event come from a domain.
So it's a little complicated... My opinion is than each listener should work for itself : a ui listener goes on the edt if it is not, and a domain goes not if it is. So the fire method stays on it's original thread.
2 cts.
Related
I have something I can't understand: my Swing GUI contains a 'play' and 'pause' button. I have also a static variable that defines 'ON' and 'OFF' states. (The main program generates the GUI).
By cliking on 'play' I change the state of my static variable to 'ON' and I launch a time-consuming process in a thread that also modifies the GUI. As long as the static variable is 'ON' loops in the same process. Clicking on 'pause' would change the static variable to OFF.
But by clicking on 'play' the GUI is freezing and consequently:
The GUI doesn't update
The process can't be 'paused' with my 'pause' button.
I have heard about EDT and SwingWorker but I you have a simple way to do it I take it.
Thank you for your help and forgive my bad english...
The problem is that you're doing the intensive, time-consuming work on the same thread responsible for updating the GUI. SwingWorker allows you to move time-consuming tasks to a separate thread of execution, thereby leaving the UI thread to do its thing uninhibited.
However, it does add a further complication: affinity. Calling methods on UI components generally requires that you do so from the UI thread. Therefore, you need to use special functionality to get back to the UI thread from the worker thread. SwingWorker also gives you this ability.
I suggest you read through this documentation.
You need to read Concurrency in Swing to understand how the EDT and SwingWorkers operate.
All GUI updates are executed on the EDT so when you click a GUI component any method that this calls will be executed on the EDT. If this is a time consuming process then this will block the EDT from executing any futher GUI updates. Hence your GUI is freezing and you can't click the pause button.
You need to use SwingWorker to execute the time consuming process on another thread. The link I provided above details how to do this.
You should not start long-running processes in Swing’s event handler because it will freeze your GUI, you know that now. :) Start it in a new thread. You only need to use a SwingWorker if you’re planning on manipulating the GUI from the worker thread (because Swing is not thread-safe).
This is a pretty straightforward reason: while Java is working on your time-consuming process, it isn't able to update the GUI. Solution: run the time-consuming process in a separate thread. There are a bunch of ways to program that, and it would probably depend somewhat on how your program is written.
The event dispatch thread (EDT) is the only thread in which it's safe to read or update the GUI.
The pause button should be setting the on/off variable in the event dispatch thread.
The time-consuming operation, and the loop, should not be in the EDT. (The loop should also not be running continuously doing nothing but check the variable, or it can easily eat all your CPU. If it has nothing else to do it should check, and then call Thread.sleep() for some length of time (say 100ms).)
If you can prove that the on/off variable is being set to OFF, but that nonetheless it's always read as ON, it may be that the variable's value is not being copied from the EDT to the worker thread. Make it volatile, or synchronize access to it, or use an AtomicReference, or read it in the EDT using SwingUtilities.invokeAndWait().
SwingWorker probably is the simplest way to go, here. Implement your time-consuming operation, and the on/off check, in the doInBackground() method, and your GUI update in the done() method.
public enum State {
RUNNING, STOPPED
}
public class ThreadSafeStateModel {
private State state = State.STOPPED;
public synchronized void stop() {
state = State.STOPPED;
}
public synchronized void start() {
state = State.RUNNING;
}
public boolean isRunning() {
return state == State.RUNNING;
}
}
public class ExpensiveProcessWorker extends SwingWorker<Void, Void> {
private final ThreadSafeStateModel model;
public ExpensiveProcessWorker(ThreadSafeStateModel model) {
this.model = model;
}
#Override // Runs in background
protected Void doInBackground() throws Exception {
while (model.isRunning()) {
// do one iteration of something expensive
}
return null;
}
#Override // Runs in event dispatch thread
protected void done() {
// Update the GUI
}
}
public class StopButton extends JButton {
public StopButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Stop") {
#Override
public void actionPerformed(ActionEvent e) {
model.stop();
}
});
}
}
public class StartButton extends JButton {
public StartButton(final ThreadSafeStateModel model) {
super(new AbstractAction("Start") {
#Override
public void actionPerformed(ActionEvent e) {
model.start();
new ExpensiveProcessWorker(model).execute();
}
});
}
}
(A lot could be done to clean this up depending on the real application, but you get the idea.)
#Override
public void actionPerformed(ActionEvent e) {
new Thread() {
public void run() {
//your code which runs on click event
}
}.start();
}
I would like to call different code (callbacks) from within a background thread loop and use that background thread to perform the work. It would be similar to delegates in C#.
public class test {
private boolean keepRunning;
private boolean messageReady;
private MyClass myClass;
void LongBackgroundWork(){
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (keepRunning) {
if (messageReady){
myClass.callback(); // call different methods here
// to be decided at runtime and run on this worker thread
}
}
}
});
thread.start();
}
}
I want to use the background thread not the UI thread. I want to set a callback from within myClass to choose what code is called. It's easy in C# how to do it Java.
I don't have much experience in Java and don't understand what mechanism to use. Should I be using a handler? Can a handler run code on a background thread?
I'd wager you want to have a pattern where an event or some occurence happens and you need to initiate a code block somewhere.
A pattern that could help you is perhaps an Observer Wiki and firing off to the event. You can also check out this SO question here if you'd like: Delegate vs Callback in Java
In your case, I think you'd want to have someone handle the responsibility of what you have to do when a message is ready. So what you're looking for is someone to perform the action, once the event is read (message ready).
Take for example Class Foo is your container of listeners, or also called an Observer that will be notified of any events. You can have a list of callbacks here to some object that is responsible for your logic to do what you need to do next.
Then you would have an Observable object or a class that would implement some logic when notified. You could then have various class objects perform the necessary logic by implementing the callback function required.
Example:
// Observer
public class Foo {
// List of objects that implement Callbacks interface
private List<Callbacks> mList;
public Foo() {
// Initialize here
}
public void addListener(Callbacks cb) {
mList.add(cb);
}
public void notifyListeners() {
for ( Callback cb : mList) {
cb.onCallback();
}
}
// Public interface to be implemented by users
public interface Callback {
void onCallback();
}
}
Then just have a class implement this object and you can pass it along if you'd like.
// Bar implements Foo.Callback interface
public class Bar implements Foo.Callback {
public class Bar() {}
#Override
public void onCallback() {
// Perform logic here
}
}
Finally in your code, you'd just create the Foo object, add a listener, and notify them when it's time to fire your event.
if i understood you properly,you cant do this on UI thread, basically when android see Thread like this it will expect that it's a long operation however you can call it by AsyncTask or Handler
you can make something like this
private class MyAsyncTask extends AsyncTask<Void,Void,Void>{
protected Void doInBackground() {
MyClass myClass=new MyClass();
myClass.LongBackgroundWork();
}
return totalSize;
}
}
this is how yo can call your thread otherwise you have to use Handler instead
Handler handler=new Handler();
handler.post(new Runnable(){
MyClass myClass=new MyClass();
myClass.LongBackgroundWork();
})
I am working on the design of a multi-threading app in Javafx and would like to have a TableView with columns for Name and Progress of each Thread. After doing much research I found a similar example of what I am trying to accomplish here:
JavaFX Update progressbar in tableview from Task
(Which points to this: 'https://community.oracle.com/message/10999916')
The problem I am running into, however, is illustrated well in this example; how can you call a 'Task' object multiple times to update a ProgressIndicator?
My understanding from Oracle's documentation is that a Task object "is a one-shot class and cannot be reused". It would seem then that one can only invoke the call() method of a Task object once. I need to update the Task multiple times as it progresses through a Thread class, not call it once and arbitrarily increment through a For loop.
I have read about binding to Listeners and creating Service classes, but I am unsure if those are actual resolutions to this problem. I would therefore like to ask if this is even possible in Javafx, or if perhaps I am overlooking something. In the event someone has accomplished this in the past, it would be tremendously helpful if you might be able to illustrate how through the example provided previously.
Any direction on this would be appreciated, thank you.
-Drew
EDIT 1: I edited my wording as it was inaccurate.
EDIT 2: Here is an example with some pseudo code. Say I had a class with the following code:
public static class TaskEx extends Task<Void>{
#Override
protected Void call(){
updateProgress(.5, 1);
return null
}
public static void callThread() {
TableView<TaskEx> table = new TableView<TaskEx>();
//Some code for data in table.
TableColumn progressColumn = new TableColumn ("Progress");
progressColumn.setCellValueFactory(new PropertyValueFactor("progress");
table.setItems(<data>);
table.getColumns();addAll(progressColumn);
ExecutorService executor = Executors.newFixedThreadPool(<SomeNumber>);
for(TaskEx task : table.getItems(){
Threading.ThreadClass newThread = new Threading.ThreadClass(task);
executor.submit(newThread, <uniqueID>);
}
}
Then say I had a second class for Threading with this logic:
static class ThreadClass extends Thread{
Task progressTask;
public ThreadClass(Task task, Integer id){
progressTask = task;
}
public void run(){
ExecutorService executor = Executors.newFixedThreadPool(<someNumber>);
//This invokes the Task call for the correct progressIndicator in the Tableview.
//It will correctly set the progressIndicator to 50% done.
executor.submit(progressTask);
/* Main logic of the Threading class that involves the 'id' passed in. */
//This will do nothing because you cannot invoke the Task call more than once.
executor.submit(progressTask);
}
}
That is the sort of workflow I need, but I'm unsure how to accomplish this.
It seems like you don't get what we were talking about. You are trying to do your logic in the Thread.run(), and then each thread is creating a Task just to do the update of progress.
What you need is really to shift your logic from Thread.run() to Task.call(). Your thread is really just a thread, and all it does is to run a Runnable object (which is the Task).
public class TaskEx extends Task<Void> {
#Override
protected Void call() {
// Do whatever you need this thread to do
updateProgress(0.5, 1);
// Do the rest
updateProgress(1, 1);
}
}
public static void callThread() {
TableView<TaskEx> table = new TableView<TaskEx>();
ObservableList<TaskEx> data = FXCollections.observableArrayList<>();
data.add(new TaskEx()); // Add the data you need
TableColumn progressColumn = new TableColumn("Progress");
progressColumn.setCellValueFactory(new PropertyValueFactory("progress"));
progressColumn.setCellFactory(column -> {
return new TableCell<TaskEx, Double> {
private final ProgressBar bp = new ProgressBar();
#Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
}
else {
bp.setProgress(item.doubleValue());
setGraphic(bp);
}
}
}
});
table.setItems(data);
table.getColumns().add(progressColumn);
ExecutorService executor = Executors.newFixedThreadPool(data.size());
for (TaskEx task : table.getItems()) {
executor.submit(task);
}
}
This implement removes ThreadClass because there should not be any logic that must be done at a thread sub-class. If you really need to access the thread object as part of your logic, call Thread.getCurrentThread() from your TaskEx.call().
This implement also opens multiple threads doing exactly the same thing (which is quite meaningless). If you need to do a set of different logics, you can either make a set of different Task subclasses, or add a constructor taking in Runnable objects in TaskEx.
E.g.
public class TaskEx extends Task<Void> {
private final Runnable[] logics;
public TaskEx(Runnable[] logics) {
this.logics = logics;
}
#Override
protected Void call() {
for (int i = 0; i < logics.length; i++) {
logics[i].run();
updateProgress(i, logics.length);
}
}
}
How to obtain separation of the View from model when using a SwingWorker with a long running process that should send updates back to the controller ?
I can use the SwingWorkers doInBackground() to keep the EDT responsive by calling e.g model.doLongProcess() from in there great!
The issue I have is trying to get data back before the process is finished, to update the view with the progress..
I know that I can get data back by using by using the SwingWorkers publish() method but this I think forces me to write the code for the doLongProcess() method within doInBackground().
For reference the MVC implementation I have a looks a little like this:
http://www.leepoint.net/notes-java/GUI/structure/40mvc.html
/ structure/calc-mvc/CalcMVC.java -- Calculator in MVC pattern.
// Fred Swartz -- December 2004
import javax.swing.*;
public class CalcMVC {
//... Create model, view, and controller. They are
// created once here and passed to the parts that
// need them so there is only one copy of each.
public static void main(String[] args) {
CalcModel model = new CalcModel();
CalcView view = new CalcView(model);
CalcController controller = new CalcController(model, view);
view.setVisible(true);
}
}
I have one Model Class which wraps a number of other classes together to a form simple interface for the controller.
I really don't want to have to move all/some/any of the code from these Classes into the controller - It doesn't belong there.
Update:
Here is the approach that I am taking - Its not the cleanest solution and It could be perceived as an abuse of PropertyChangeSupport.. on a semantic level.
Basically all the low-level classes that have long running methods will have a propertyChangeSupport field. The long running methods call the firePropertyChange() periodically to update on the status of the method and not necessarily to report the change of a property - that is what I mean by semantic abuse!.
Then the Model class which wraps the low level classes catches these events and issues its own highlevel firePropertyChange .. which the controller can listen for...
Edit:
To clarify, when I call firePropertyChange(propertyName, oldValue, newValue);
propertyName ---> I abuse the propertyName to represent a topicname
oldValue =null
newValue = the message that I want to broadcast
Then the PropertyChangeListener in the model or where ever can discern the message based on the topicname.
So Iv basically bent the system to use it like a publish-subscribe ....
I guess in place of the above method I could add a progress field to the lowlevel classes that gets updated, and then firePropertyChange based on that.. this would fall into line with how its supposed to be used.
I think of the publish/process pair as pushing data from the SwingWorker into the GUI. Another way to pass information is by having the GUI or control pull the information out of the SwingWorker by using PropertyChangeSupport and PropertyChangeListeners. Consider
giving your model a PropertyChangeSupport field,
Giving it add and remove PropertyChangeListener methods
Having it notify the support object of changes in state.
Having the SwingWorker add a PropertyChangeListener to the model.
Then having the SwingWorker notifying control or view of changes in the model's state.
The SwingWorker could even use publish/process with the changed information from the model.
Edit
Regarding your update:
Basically all the low-level classes that have long running methods will have a propertyChangeSupport field. The long running methods call the firePropertyChange() periodically to update on the status of the method and not necessarily to report the change of a property - that is what I mean by semantic abuse!.
I don't recommend that you do this. Understand that if the bound property being listened to does not change, none of the PropertyChangeListeners (PCLs) will be notified even if firePC() is called. If you need to poll a property, then I wouldn't use a PCL to do this. I would simply poll it, probably from outside of the class being polled.
Personally, in my SwingWorker I'd create a public publish method, and pass the instance of my SwingWorker to the long running Model method. That way the model pushes updates to the control (SwingWorker), which then pushes to the View.
Here's an example - I threw everything into one file (for simplicity of running), but I'd imagine normally you'd have separate files/packages for these things.
EDIT
To decouple the model from the control, you'd have to have an observer of the model. I would implement a ProgressListener inheriting ActionListener. The model just notifies all registered ProgressListener that progress has been made.
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class MVCSwingWorkerExample {
public static void main(String[] args) {
CalcModel model = new CalcModel();
CalcView view = new CalcView();
CalcController controller = new CalcController(model, view);
}
//Model class - contains long running methods ;)
public static class CalcModel{
//Contains registered progress listeners
ArrayList<ActionListener> progressListeners = new ArrayList<ActionListener>();
//Contains model's current progress
public int status;
//Takes in an instance of my control's Swing Worker
public boolean longRunningProcess(MVCSwingWorkerExample.CalcController.Worker w){
for(int i = 0; i < 60; i++){
try {
//Silly calculation to publish some values
reportProgress( i==0 ? 0 : i*100/60);
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Whowsa!");
e.printStackTrace();
}
}
return true;
}
//Notify all listeners that progress was made
private void reportProgress(int i){
status = i;
ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_FIRST, null);
for(ActionListener l : progressListeners){
l.actionPerformed(e);
}
}
//Standard registering of the listeners
public void addProgressListener(ActionListener l){
progressListeners.add(l);
}
//Standard de-registering of the listeners
public void removeProgressListener(ActionListener l){
progressListeners.remove(l);
}
}
//View Class - pretty bare bones (only contains view stuff)
public static class CalcView{
Box display;
JButton actionButton;
JLabel progress;
public void buildDisplay(){
display = Box.createVerticalBox();
actionButton = new JButton("Press me!");
display.add(actionButton);
progress = new JLabel("Progress:");
display.add(progress);
}
public void start(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(display);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
public static class CalcController{
CalcModel model;
CalcView view;
public CalcController(CalcModel model, CalcView view){
this.model = model;
this.view = view;
//Build the view
view.buildDisplay();
//Create an action to add to our view's button (running the swing worker)
ActionListener buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
Worker w = new Worker();
w.execute();
}
};
view.actionButton.addActionListener(buttonAction);
//Start up the view
view.start();
}
//Notified when the Model updates it's status
public class ProgressListener implements ActionListener{
Worker w;
public ProgressListener(Worker w){
this.w = w;
}
#Override
public void actionPerformed(ActionEvent e) {
CalcModel model = (CalcModel)e.getSource();
w.publishValue(model.status);
}
}
//The worker - usually part of the control
public class Worker extends SwingWorker<Boolean, Integer>{
public Worker(){
//Register a listener to pay attention to the model's status
CalcController.this.model.addProgressListener(new ProgressListener(this));
}
#Override
protected Boolean doInBackground() throws Exception {
//Call the model, and pass in this swing worker (so the model can publish updates)
return model.longRunningProcess(this);
}
//Expose a method to publish results
public void publishValue(int i){
publish(i);
}
#Override
protected void process(java.util.List<Integer> chunks){
view.progress.setText("Progress:" + chunks.get(chunks.size()-1) + "%");
}
#Override
protected void done() {
try {
view.progress.setText("Done");
} catch (Exception ignore) {
}
}
}
}
}
For a long running process under Swing you must create a new Thread for that purpose, so when this process is complete, then you must update you MVC inside the "Swing thread", remember there is only one for each application.
Try find a way to let know the user that you application is processing, and do not allow him to "multiply" again, until done.
public class CalcController {
////////////////////////////////////////// inner class MultiplyListener
/**
* When a mulitplication is requested. 1. Get the user input number from the
* View. 2. Call the model to mulitply by this number. 3. Get the result
* from the Model. 4. Tell the View to display the result. If there was an
* error, tell the View to display it.
*/
class MultiplyListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
final String userInput = m_view.getUserInput();
new Thread(new Runnable() {
#Override
public void run() {
try {
m_model.multiplyBy(userInput);
} catch (NumberFormatException nfex) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
m_view.showError("Bad input: '" + userInput + "'");
}
});
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
m_view.setTotal(m_model.getValue());
}
});
}
}).start();
}
}//end inner class MultiplyListener
}
I'm wondering if SwingWorker has to be a nested class within my main GUI. I'd rather make it an external class to keep the GUI clear from any of my programs logic.
I tried to make the SwingWorker class external, which works fine for the process, unfortunately I can't access any of my GUI fields from the SwingWorker class.
Whenever I try to access an attribute, such like a label or whatever from within SwingWorker's done() method I get a nullPointer exception.
Any advice would be much appreciated!
First of all thank you very much Jeff! Works fine so far, even though I could not follow you on the second option you presented.
One of my background tasks calculates a certain size (long value), so it would be nice to get that value from my GUI.
You suggested to work with getters and setters but unfortunately I've got no idea on how to implement them in the SwingWorker class.
I tried it like this:
public void setSize(long totalSize) {
this.totalSize = totalSize;
}
public long getTotalSize() {
return totalSize;
}
The setter is invoked at the end of the doInBackground() method. Unfortunately I can't use the get() method from my GUI.
final MySwingWorker w = new MySwingWorker();
Runnable r = new Runnable() {
public void run() {
// do something with w.get()
}
};
w.setRunnable(r);
w.execute();
The object creation of "w" does not work in my case as the constructor requires an object of Runnable.
Am I missing something?
Please go easy on me, it's the first time I work with SwingWorker. :)
Again, thank you very much for your help!
You can make the SwingWorker an external class. However, just like any other class, if it can't see the variables (e.g. the label you want to set), of course it won't be able to set it. One thing you could do is pass the worker a Runnable that it executes when it is complete.
public class MySwingWorker extends SwingWorker {
private final Runnable r;
public MySwingWorker(Runnable r) {
this.r = r;
}
public void doInBackground() {...}
public void done() { r.run(); }
}
Now from the GUI, you might do something like
Runnable updateLabel = new Runnable() {
public void run() {
label.setText("myValue");
}
};
SwingWorker w = new MySwingWorker(updateLabel);
w.execute();
This gets a bit trickier if you want to use the result of the SwingWorker, though it is possible. Rather than passing the Runnable to the swing worker's constructor, you would have a setter method and then it would be something like:
final MySwingWorker w = new MySwingWorker();
Runnable r = new Runnable() {
public void run() {
// do something with w.get()
}
};
w.setRunnable(r);
w.execute();
In either case, the Runnable is functioning similarly to a closure that is executed when the worker is finished.