Reputation: 1341
I've been following this thread to try to update a JProgressBar from a separate class in my program: java - Progress Bar - Is it possible to use setProgess() of Progress Bar outside the doInBackground() method?
Unfortunately my code isn't work properly. I probably missed something, but I can't seem to figure out what it was. This is the code I have written so far:
Here is the propertyChangeListener I use to update the progress bar:
PropertyChangeListener listener = new PropertyChangeListener(){
public void propertyChange(PropertyChangeEvent event){
if("progress".equals(event.getPropertyName())){
progressBar.setValue((int)currentPercent);
progressBar.setString(Integer.toString((int)currentPercent));
}
}
};
SwingWorker class:
class Task extends SwingWorker<Void, String>{
public Task(){
md = new ManipulateDirectories(this);
}
@Override
public Void doInBackground(){
for(int i = 0; i < directories.length; i++){
md.copyDirectory(directories[i], backupDir);
}
return null;
}
@Override
public void process(List<String> chunks){
}
@Override
public void done(){
closeWindow();
}
public void updateProgress(int tick){
setProgress(tick);
}
}
ManipulateDirectories class:
public class ManipulateDirectories{
Task task;
public ManipulateDirectories(Task task){
this.task = task;
}
//Recursive function to loop through and copy individual files
public void copyDirectory(File file, File dest){
if(file.isFile()){
try {
FileUtils.copyFileToDirectory(file, dest);
currentSize = currentSize + getDirSize(file);
if(currentSize >= ONE_PERCENT){
currentPercent = currentPercent + (currentSize / ONE_PERCENT);
task.updateProgress((int)currentPercent); //THIS LINE DOES NOT WORK
currentSize = currentSize % ONE_PERCENT;
}
} catch (IOException e) {
e.printStackTrace();
}
} else if (file.isDirectory()){
File newDir = new File(String.format("%s\\%s", dest.getAbsolutePath(), file.getName()));
if(!newDir.exists()){
newDir.mkdir();
for(File f : file.listFiles()){
copyDirectory(f, newDir);
}
}
}
}
public Long getDirSize(File file) {
long size = 0L;
if (file.isFile() && file != null){
size += file.isDirectory() ? getDirSize(file) : file.length();
} else if (file.isDirectory()){
for (File f : file.listFiles()) {
size += f.isDirectory() ? getDirSize(f) : file.length();
}
}
return size;
}
}
As you can see, the propertyChangeListener should be fired by the updateProgress(int) method within the swingworker class, and that method should be called by the line: task.updateProgress((int)currentPercent)
which is in the ManipulateDirectories class. However, that line does not seem to call updateProgress(). I am guessing it might be a problem with the particular instance of "Task"--perhaps I am creating a separate instance that does not have the correct context? (I know the terminology is probably a bit wrong, but hopefully you can understand what I'm trying to say). Can anyone spot my mistake/s? Any help would be very much appreciated, I've been stuck on this for quite a while now.
SSCCE:
import java.awt.BorderLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
public class MainClass extends JFrame {
private JProgressBar progressBar;
private DoSomething ds;
private int currentPercent = 0;
private Task task;
private static JPanel contentPane;
private JPanel bottomPane;
private JButton btnCancel;
public static void main(String[] args){
MainClass mc = new MainClass();
mc.createGUI();
}
public void createGUI(){
//Create frame
setTitle("Backup Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 350);
//Create content pane
contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
//Create panel for progress bar/cancel button
bottomPane = new JPanel();
bottomPane.setLayout(new BoxLayout(bottomPane, BoxLayout.Y_AXIS));
progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
progressBar.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
progressBar.setValue(0);
btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
closeWindow();
}
});
bottomPane.add(progressBar);
bottomPane.add(btnCancel);
contentPane.add(bottomPane, BorderLayout.SOUTH);
PropertyChangeListener listener = new PropertyChangeListener(){
public void propertyChange(PropertyChangeEvent event){
if("progress".equals(event.getPropertyName())){
progressBar.setValue((int)currentPercent);
progressBar.setString(Integer.toString((int)currentPercent));
}
}
};
setVisible(true);
task = new Task();
task.execute();
}
class Task extends SwingWorker<Void, String>{
public Task(){
ds = new DoSomething(this);
}
@Override
public Void doInBackground(){
for(int i = 0; i < 100; i++){
ds.incrementPercent();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public void done(){
closeWindow();
}
public void updateProgress(int tick){
setProgress(currentPercent + tick);
}
}
public class DoSomething{
Task task;
public DoSomething(Task task){
this.task = task;
}
public void incrementPercent(){
task.updateProgress(1);
}
}
public void closeWindow(){
WindowEvent close = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(close);
}
}
I realize that's a very long SSCCE, but hopefully it gives you all the information you need to know.
Upvotes: 2
Views: 1487
Reputation: 14413
You never add your listener to your SwingWorker
.
Change to:
task = new Task();
task.addPropertyChangeListener(listener);
The other error you have is that you never update your currentPercent
in updateProgress
.
public void updateProgress(int tick){
currentPercent+=tick;
setProgress(currentPercent);
}
EDIT
Well and actually your error is the same in your code (not sscce), you never update your currentPercent
value.
PropertyChangeListener listener = new PropertyChangeListener(){
public void propertyChange(PropertyChangeEvent event){
if("progress".equals(event.getPropertyName())){
currentPercent = (int)event.getNewValue();
progressBar.setValue(currentPercent);
progressBar.setString(Integer.toString(currentPercent));
}
}
};
Upvotes: 3