java swingworker thread to update main Gui
There is an excellent example from the JavaDocs
class PrimeNumbersTask extends
SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//initialize
}
@Override
public List<Integer> doInBackground() {
List<Integer> numbers = new ArrayList<Integer>(25);
while (!enough && !isCancelled()) {
number = nextPrimeNumber();
numbers.add(number);
publish(number);
setProgress(100 * numbers.size() / numbersToFind);
}
return numbers;
}
@Override
protected void process(List<Integer> chunks) {
for (int number : chunks) {
textArea.append(number + "\n");
}
}
}
JTextArea textArea = new JTextArea();
final JProgressBar progressBar = new JProgressBar(0, 100);
PrimeNumbersTask task = new PrimeNumbersTask(textArea, N);
task.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer)evt.getNewValue());
}
}
});
task.execute();
System.out.println(task.get()); //prints all prime numbers we have got
Take a look at publish and process
The underlying intention is that you need to update the UI from only within the Event Dispatching Thread, by passing the data you want to updated to the UI via the publish
method, SwingWorker
will call process
for you within the context of the EDT
How to use SwingWorker to update the GUI in real-time?
your background threads should call method
String message="hi im processx";
SwingWorker.publish(message);
and you have to ovveride method
SwingWokrer.process().
this method is called on EDT when it is free with the message which was passed before to publish (might be one or more) in the argument.
You should display your progress there
Yo can read more about those methods in SwingWorker documentation
Swing Worker and GUI update
The call to execute() method for SwingWorker is the last instruction of WaitingFrame constructor: is there a better place for it?
There is nothing wrong with how you are calling it.
The dispose() method for WaitingFrame is called from SwingWorker's done() method, is it correct? If a count process is very fast, could the dispose method be called before the waiting frame is actually visible? As a result, i would have two open frames...
It is correct and the situation you describe cannot happen. SwingWorker.done()
is called on EDT via a delayed SwingUtilities.invokeLater
call and you already called JFrame.setVisible(true)
before constructing the SwingWorker
(on EDT).
Instead of multiple frames, consider using a dialog, perhaps a modal one if you are attempting to block user input (like here).
Is there a better method to interrupt the process and to manage the message dialogs shown to users? I used two boolean variables, valid and interrupted, to achieve my purpose...
There certainly is a better way of doing this, considering that your current code is dangerously close to not being thread safe. Consider using an AtomicBoolean
instead of boolean
if both EDT and swing worker need to access those two members.
You should also check the interrupted
flag somewhere and exit your file listing loop upon it changing.
You can also wrap any swing code into a SwingUtilities.invokeLater
call anywhere inside SwingWorker.doInBackground()
for fine grained GUI updates. Doing this essentially has the same effect as if done()
had been invoked but you control when and how many times it is called. Check here for a code example. Your own code does this to pass execution from the main thread to EDT inside your main()
method (the reason for this code pattern is that all swing code must execute on EDT).
how to update GUI from swingworker which returns two different values
The second type parameter V in SwingWorker<T,V>
is used for carrying out intermediate results by this SwingWorker's publish and process methods. This could be your custom class. Here is an example based on posted SSCCE (shortened for clarity):
class Progress {
private int task;
private int element;
public Progress(int task, int element) {
super();
this.task = task;
this.element = element;
}
...
}
public class Model extends SwingWorker<Integer, Progress> {
...
@Override
protected Integer doInBackground() throws Exception {
...
publish(new Progress(i, ii));
}
}
EDIT: example of process method implementation
@Override
protected void process(List<Progress> progressList) {
for (Progress p : progressList){
System.out.println(p.getTask() + " : " + p.getElement());
}
}
EDIT: example of UI update
Here is a slightly modified version of the worker implementation, similar to a sample demonstrated in SwingWorker manual. The only changes are introduction of textArea
member and updated setProgress()
call in doInBackground()
. progress
property is used to update the progress bar, process()
is used to update text area.
public static class Model extends SwingWorker<Integer, Progress> {
private HashMap<String, Number> GUIparams;
private int session;
private int ticks;
private JTextArea textArea;
Model(HashMap<String, Number> KSMParams, JTextArea textArea) {
GUIparams = KSMParams;
session = (Integer)GUIparams.get("experimentsInSession");
ticks = (Integer)GUIparams.get("howManyTicks");
this.textArea = textArea;
}
@Override
protected void process(List<Progress> progressList) {
for (Progress p : progressList){
textArea.append(p.getTask() + " : " + p.getElement() + "\n");
System.out.println(p.getTask() + " : " + p.getElement());
}
}
/**
* Actual simulation
*/
@Override
protected Integer doInBackground() throws Exception {
int i=0;
while(!isCancelled() && i<session){
i++;
int ii=0;
while(!isCancelled() && ii<ticks){
// this is n, the task length and I'd like to update the GUI with this value
ii++;
}
//System.out.println(i);
// this is m, how many time the task has been repeated, and now it is updated in the GUI
publish(new Progress(i, ii));
//setProgress(i);
setProgress(100 * i / session);
Thread.sleep(1000);
}
return i;
}
/**
* Invoked when simulation exits
*/
@Override
protected void done() {
if (isCancelled()) {
Logger.getLogger(Model.class.getName()).log(Level.WARNING, "Experiment session cancelled by user. Closing Session...");
} else {
// do stuff
Logger.getLogger(Model.class.getName()).log(Level.WARNING, "Experiment session ended.");
}
}
}
Here is a demo initialization:
final JProgressBar progressBar = new JProgressBar(0, 100);
final JTextArea textArea = new JTextArea();
final JButton button = new JButton("Start");
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
HashMap<String, Number> map = Maps.newHashMap();
map.put("experimentsInSession", 10);
map.put("howManyTicks", 5);
Model task = new Model(map, textArea);
task.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer)evt.getNewValue());
}
}
});
task.execute();
}
});
Java Swingworker one after another and update GUI
1) How to run all the workers in a perfect sequencial order. i.e when worker1 is done then start worker 2, when worker2 is done then start worker 3 and so on.
A little trick to remember, you can put a SwingWorker
into a ExecutorService
So, using something like...
public static class Worker extends SwingWorker {
private int sequence;
public Worker(int sequence) {
this.sequence = sequence;
}
@Override
protected Object doInBackground() throws Exception {
System.out.println(sequence + "...");
Thread.sleep(500);
return null;
}
}
As a test, you could use something like...
ExecutorService es = Executors.newFixedThreadPool(1);
for (int index = 0; index < 10; index++) {
es.submit(new Worker(index));
}
es.shutdown();
(You don't need to call shutdown
, but otherwise my tested never allowed the JVM to terminate ;))
Which will run the workers in the order they are submitted.
Now, if you want to feed the values from one SwingWorker
to another, you could do something like...
public abstract class ChainedWorker<T, V> extends SwingWorker<T, V> {
private ChainedWorker<T, ?> next;
private T previousValue;
public ChainedWorker(ChainedWorker<T, ?> next) {
this.next = next;
}
public void setPreviousValue(T previousValue) {
this.previousValue = previousValue;
}
@Override
protected void done() {
try {
T previous = get();
if (next != null) {
next.setPreviousValue(previous);
next.execute();
}
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
}
}
Which is simply a SwingWorker
which allows you to provide a link in the chain (the next worker to call), which passes the value that this SwingWorker
generated...or some such similar
Now, if you're really nuts and want to role your own, maybe something like...
public class ChainedWorkerBuilder {
private List<SwingWorker> workers;
private SwingWorker current;
public ChainedWorkerBuilder() {
workers = new ArrayList<>(25);
}
public ChainedWorkerBuilder add(SwingWorker worker) {
workers.add(worker);
return this;
}
public void execute() {
if (!workers.isEmpty()) {
SwingWorker worker = workers.remove(0);
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())) {
SwingWorker source = (SwingWorker)evt.getSource();
switch (source.getState()) {
case DONE:
source.removePropertyChangeListener(this);
execute();
break;
}
}
}
});
}
}
}
2) How to update a textfield in my Welcome class, with the values from the Samp class.
I don't think I'm following your code directly, but, if you did something like...
SwingWorker<Boolean, Void>worker = new SwingWorker<Boolean, String>() {
protected Boolean doInBackground() throws Exception {
publish(fileName);
ZipUtility zu = new ZipUtility(fileName));
return zu.extract(fileName);
}
Then in the SwingWorker
s process
method you would be able to update the UI safely...
@Override
protected void process(List<String> chunks) {
// Grab the last element...
textfield.setText(chunks.get(chunks.size() - 1));
}
}
Related Topics
Java:Read Last N Lines of a Huge File
How to Use Session in Jsp Pages to Get Information
Printing Message on Console Without Using Main() Method
Create File with Given Size in Java
How to Read Excel Cell Having Date with Apache Poi
What Do Curly Braces in Java Mean by Themselves
How to Use Argumentcaptor for Stubbing
Exception Noclassdeffounderror for Cacheprovider
Find Out What Jvm Eclipse Is Running On
Java Swing Jtextfield Set Placeholder
Jbutton() Only Working When Mouse Hovers
Jaxb :Need Namespace Prefix to All the Elements
Jaxb Mapping Cyclic References to Xml
Get Key Press Without Pressing Enter in Console
How to Set Color to a Certain Row If Certain Conditions Are Met Using Java