-
SwingWorker
Hi,
I´m not sure, if I have chosen the right topic for my problem, nontheless I hope that I have.
I´d like to create a simple progressBar app, involving simple delayed counter and progressbar-dialog.
My vision is simple: with 500ms delay counting untill 10 is being displayed to the console.
Meanwhile, the indeterminete progressbar is being displayed.
After counting is done, I´d like to return the integer of value 987 (this is very important for me, in order to develop app later)
According to some tutorials I tried to code this app, but unfortunatelly unsuccessfully.
Here is my code:
Code:
public class Task{
public static void main(String[] args) {
final JProgressBar progressBar = new JProgressBar(0, 10);
final CounterTask task = new CounterTask();
JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("start");
task.execute();
Integer res=new Integer(5);
try{
System.out.println("try");
while(!task.isDone()){
System.out.println("while");
res=task.get(50, TimeUnit.MILLISECONDS);
System.out.println("res: "+res);
System.out.println("afterRes");
}
res=task.get(50, TimeUnit.MILLISECONDS);
System.out.println("res: "+res);
System.out.println("/while");
}
catch (Exception ex){}
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(startButton);
JPanel cp = new JPanel();
LayoutManager layout = new BoxLayout(cp, BoxLayout.Y_AXIS);
cp.setLayout(layout);
cp.add(buttonPanel);
cp.add(progressBar);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(cp);
frame.pack();
frame.setVisible(true);
}
}
class CounterTask extends SwingWorker<Integer, Integer> {
protected JDialog dialog;
@Override
protected Integer doInBackground() throws Exception {
int i = 0;
int count = 10;
dialog=new JDialog();
JProgressBar progressBar=new JProgressBar();
progressBar.setIndeterminate(true);
dialog.add(progressBar);
dialog.pack();
dialog.setVisible(true);
while (!isCancelled() && i < count) {
i++;
Thread.sleep(500);
System.out.println(i);
}
publish(new Integer(987));
return new Integer(987);
}
@Override
protected void done() {
dialog.setVisible(false);
System.out.println("Done !");
}
}
The counting is ok as same as progressbar, however the return value hasn´t been written.
Please, could anybody help me find out, where my problem is, or furthermore could anybody provide me with working solution?
Thank you very much
-
One problem with your code is this:
Code:
while (!task.isDone()) {
System.out.println("while");
res = task.get(50, TimeUnit.MILLISECONDS);
System.out.println("res: " + res);
System.out.println("afterRes");
}
As this could freeze the event dispatch thread, the main Swing thread, and nullify all the benefits of using a SwingWorker. But there is a better way since SwingWorkers have built in support for a PropertyChangeListener, and you might want to use that to your advantage. With this, you could even use a determinate progress bar rather than an indeterminate progress bar. For example,
Code:
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.*;
import javax.swing.SwingWorker.StateValue;
@SuppressWarnings("serial")
public class Task3 extends JPanel {
private static final int FINAL_VALUE = 987;
private JTextArea textArea = new JTextArea(10, 20);
private JButton startBtn = new JButton("Start");
public Task3() {
JPanel startBtnPanel = new JPanel();
startBtnPanel.add(startBtn);
startBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startBtnActionPerformed();
}
});
textArea.setEditable(false);
textArea.setFocusable(false);
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(new JScrollPane(textArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
add(startBtnPanel);
}
private void startBtnActionPerformed() {
startBtn.setEnabled(false);
Window win = SwingUtilities.getWindowAncestor(this);
final JDialog dialog = new JDialog(win, "Progress", ModalityType.APPLICATION_MODAL);
final JProgressBar progressBar = new JProgressBar();
JPanel progressPanel = new JPanel();
progressPanel.add(progressBar);
progressPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
dialog.getContentPane().add(progressPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
final CounterTask3 counterTask3 = new CounterTask3(this, FINAL_VALUE);
counterTask3.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state")) {
if (counterTask3.getState().equals(StateValue.DONE)) {
dialog.setVisible(false);
startBtn.setEnabled(true);
// could call counterTask3.get() here to get the final value
}
}
else if (evt.getPropertyName().equals("progress")) {
int progress = counterTask3.getProgress();
progressBar.setValue(progress);
}
}
});
counterTask3.execute();
dialog.setVisible(true);
}
public void appendToTextArea(String text) {
textArea.append(text);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGui();
}
});
}
private static void createGui() {
Task3 task3 = new Task3();
JFrame frame = new JFrame("App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(task3);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class CounterTask3 extends SwingWorker<Integer, Integer> {
private static final int MAX_COUNTER = 10;
private static final long SLEEP_TIME = 500;
private Task3 task3;
private int finalValue;
public CounterTask3(Task3 task3, int finalValue) {
this.task3 = task3;
this.finalValue = finalValue;
}
@Override
protected Integer doInBackground() throws Exception {
int counter = 0;
while (counter < MAX_COUNTER && !isCancelled()) {
counter++;
Thread.sleep(SLEEP_TIME);
publish(counter);
setProgress((counter * 100)/MAX_COUNTER); // if use determinate PB
}
return finalValue;
}
@Override
protected void process(List<Integer> chunks) {
for (Integer intChunk : chunks) {
task3.appendToTextArea("int value: " + intChunk + "\n");
}
}
@Override
protected void done() {
task3.appendToTextArea("Final value: " + finalValue + "\n");
}
}
There are several ways to skin this cat and my suggestion is not the only way, and may not even be the best way.
-
hi,
thank you very much for help.
The property-change listener works good, the determinate progressBar is not nessesary, anyway thanks a lot.
Nontheless, I probably have expresed in a strange way (sorry for my english) - I want to get the Integer (987) from worker into the rest of my other code, i.e. write returned int from propertyChangeListener insteand of from done() method.
I asked you to explain me the example with only integer, but in future I´m going to let it return more complicated classes, e.g. ResultSet etc.
Thank you very much for your helpful responses.
-
oh man,
I´m so sorry, I didn´t see your coment. It works fine. Thanks for help