I am having some trouble with my JScrollPane/JTextArea when using a SwingWorker. Here is what I currently have:
JTextArea txtDirs;
Task task;
//EDT
public void createGUI(){
txtDirs = new JTextArea();
txtDirs.setBounds(10, 56, 414, 125);
txtDirs.setEditable(false);
contentPane.add(new JScrollPane(txtDirs));
task = new Task();
task.execute();
}
class Task extends SwingWorker<Void, Void>{
@Override
public void doInBackground(){
for(file : files){
txtDirs.append(file.getAbsolutePath);
}
}
@Override
public void done(){
closeWindow();
}
}
This isn't the exact code, but it should give you the gist of it. Anyway, the problem is that the JScrollPane doesn't appear at all, though the code in the doInBackground() method does run. I expect it has something to do with it being updated (txtDirs.append(file.getAbsolutePath())
) in the background task. However, I'm not quite sure how to make it work in this case. The frame appears as expected, but it is entirely blank. Should there be a "process" method in the Task
class? And is that where the "txtDirs.append(file.getAbsolutePath())
" should be placed? I'm afraid I'm rather new to the use of SwingWorkers, so any help would be appreciated.
EDIT:
After a little confusion I decided I'd simply post my full code. I know there are things wrong with it, and I probably misunderstood some of what was mentioned in the comments, so I'm hoping posting this will allow someone to point out any obvious mistakes I've made.
Full code:
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JProgressBar;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
import org.apache.commons.io.FileUtils;
@SuppressWarnings("serial")
public class BasicCopy extends JFrame {
private JPanel contentPane;
private JTextArea txtCopiedDirs;
private JButton btnCancel;
private JProgressBar progressBar;
private JLabel lblCopying;
private String mainDrive;
private String backupDrive;
private String username;
private String backupDir;
long totalSize = 0L; //total size of directories/files
long currentSize = 0L; //current size of files counting up to ONE_PERCENT
long currentPercent = 0L; //current progress in %
long ONE_PERCENT; //totalSize / 100
Task task;
public BasicCopy() {
}
public BasicCopy(String inDrive, String outDrive, String username, long space){
mainDrive = inDrive;
backupDrive = outDrive;
this.username = username;
totalSize = space*1048576;
ONE_PERCENT = totalSize/100;
createGUI();
}
public void createGUI(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Backup Progress");
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
txtCopiedDirs = new JTextArea(10, 50);
txtCopiedDirs.setEditable(false);
contentPane.add(new JScrollPane(txtCopiedDirs));
btnCancel = new JButton("Cancel");
btnCancel.setBounds(169, 227, 89, 23);
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
closeWindow();
}
});
contentPane.add(btnCancel);
progressBar = new JProgressBar(0, 100);
progressBar.setBounds(10, 192, 414, 24);
progressBar.setValue(0);
contentPane.add(progressBar);
lblCopying = new JLabel("Now backing up your files....");
lblCopying.setBounds(10, 11, 157, 34);
contentPane.add(lblCopying);
setVisible(true);
task = new Task();
task.execute();
}
/**
* Swing Worker class
*/
class Task extends SwingWorker<Void, String>{
@Override
public Void doInBackground(){
setProgress(0);
//Create Backup Directory
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy_HMMSS");
String timestamp = sdf.format(date);
backupDir = backupDrive + ":\\" + "Backup_" + timestamp;
File backupDirectory = new File(backupDir);
backupDirectory.mkdir();
//Copy Files
//Main directories
String pics = mainDrive + ":\\Users\\" + username + "\\Pictures\\";
String docs = mainDrive + ":\\Users\\" + username + "\\Documents\\";
String vids = mainDrive + ":\\Users\\" + username + "\\Videos\\";
String musc = mainDrive + ":\\Users\\" + username + "\\Music\\";
//Backup directories
String bkPics = backupDir + "\\Pictures\\";
String bkDocs = backupDir + "\\Documents\\";
String bkVids = backupDir + "\\Documents\\";
String bkMusc = backupDir + "\\Pictures\\";
String[] directories = {pics, docs, vids, musc};
String[] bkDirectories = {bkPics, bkDocs, bkVids, bkMusc};
//Loop through directories and copy files
for (int i = 0; i < directories.length; i++){
File dir = new File(directories[i]);
File dest = new File(bkDirectories[i]);
for(File file: dir.listFiles()){
try{
if(file.isFile()){
FileUtils.copyFileToDirectory(file, dest);
publish(file.getAbsolutePath() + "\n");
} else if (file.isDirectory()){
FileUtils.copyDirectoryToDirectory(file, dest);
publish(file.getAbsolutePath() + "\n");
}
if(getDirSize(file) >= ONE_PERCENT){
currentPercent = getDirSize(file)/ONE_PERCENT;
progressBar.setValue((int)currentPercent);
currentSize = 0;
} else {
currentSize = currentSize + getDirSize(file);
if(currentSize >= ONE_PERCENT){
currentPercent = currentSize/ONE_PERCENT;
currentPercent++;
progressBar.setValue((int)currentPercent);
currentSize = 0;
}
}
} catch (IOException e){
e.printStackTrace();
}
}
}
return null;
}
@Override
public void process(List<String> chunks){
for(String path : chunks){
txtCopiedDirs.append(path);
}
}
@Override
public void done(){
closeWindow();
}
}
public static 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;
}
/* Close current window */
public void closeWindow() {
WindowEvent close = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(close);
System.exit(0);
}
}
EDIT #2:
I have made some changes to the createGUI() method to avoid contentPane from having a null layout:
public void createGUI(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Backup Progress");
setBounds(100, 100, 450, 300);
contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
txtCopiedDirs = new JTextArea(10, 50);
txtCopiedDirs.setEditable(false);
scrollPane = new JScrollPane(txtCopiedDirs);
contentPane.add(scrollPane, BorderLayout.CENTER);
btnCancel = new JButton("Cancel");
btnCancel.setBounds(169, 227, 89, 23);
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
closeWindow();
}
});
contentPane.add(btnCancel);
progressBar = new JProgressBar(0, 100);
progressBar.setBounds(10, 192, 414, 24);
progressBar.setValue(0);
contentPane.add(progressBar);
lblCopying = new JLabel("Now backing up your files....");
lblCopying.setBounds(10, 11, 157, 34);
contentPane.add(lblCopying);
setVisible(true);
task = new Task();
task.execute();
}
setBounds
, instead use JTextArea(rows, cols)
publish
and override process
. process
is called within the content of the EDTTake a look at Concurrency in Swing for more details
Possible causes of your problem include...
BorderLayout
, without specifying a position constraint (other than BorderLayout.CENTER
)Updated
The main problem is, the contentPane
is using a null
layout and the scroll panes default bounds are 0x0
position by 0x0
width and height.
Best choice is to not use WinodwBuilder and learn how to use layout managers
Update with example
This is an example using two layout managers, BorderLayout
as the base layout and GridBagLayout
to provide some additional support for the extra components.
Basic rule of thumb. If it's a UI component, ESPECIALLY if it's on the screen (or you don't know it's on the screen or not), you must only ever update it from the context of the EDT.
This means calling progressBar.setValue
from within the doInBackground
is a violation of the single thread rule of Swing. SwingWorker
provides progress updates via it's PropertyChange
support
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
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 java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
public class BasicCopy extends JFrame {
private JPanel contentPane;
private JTextArea txtCopiedDirs;
private JButton btnCancel;
private JProgressBar progressBar;
private JLabel lblCopying;
private String mainDrive;
private String backupDrive;
private String username;
private String backupDir;
long totalSize = 0L; //total size of directories/files
long currentSize = 0L; //current size of files counting up to ONE_PERCENT
long currentPercent = 0L; //current progress in %
long ONE_PERCENT; //totalSize / 100
Task task;
public BasicCopy() {
}
public BasicCopy(String inDrive, String outDrive, String username, long space) {
mainDrive = inDrive;
backupDrive = outDrive;
this.username = username;
totalSize = space * 1048576;
ONE_PERCENT = totalSize / 100;
createGUI();
}
public void createGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Backup Progress");
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout());
txtCopiedDirs = new JTextArea(10, 50);
txtCopiedDirs.setEditable(false);
contentPane.add(new JScrollPane(txtCopiedDirs));
JPanel controls = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(4, 4, 4, 4);
lblCopying = new JLabel("Now backing up your files....");
contentPane.add(lblCopying, gbc);
gbc.gridy++;
progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
contentPane.add(progressBar, gbc);
gbc.gridy++;
btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
closeWindow();
}
});
controls.add(btnCancel, gbc);
contentPane.add(controls, BorderLayout.SOUTH);
setLocationRelativeTo(null);
pack();
setVisible(true);
task = new Task();
task.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
progressBar.setValue((int) evt.getNewValue());
}
}
});
task.execute();
}
/**
* Swing Worker class
*/
class Task extends SwingWorker<Void, String> {
@Override
public Void doInBackground() throws Exception {
setProgress(0);
//Create Backup Directory
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy_HMMSS");
String timestamp = sdf.format(date);
backupDir = backupDrive + ":\\" + "Backup_" + timestamp;
File backupDirectory = new File(backupDir);
backupDirectory.mkdir();
//Copy Files
//Main directories
String pics = mainDrive + ":\\Users\\" + username + "\\Pictures\\";
String docs = mainDrive + ":\\Users\\" + username + "\\Documents\\";
String vids = mainDrive + ":\\Users\\" + username + "\\Videos\\";
String musc = mainDrive + ":\\Users\\" + username + "\\Music\\";
//Backup directories
String bkPics = backupDir + "\\Pictures\\";
String bkDocs = backupDir + "\\Documents\\";
String bkVids = backupDir + "\\Documents\\";
String bkMusc = backupDir + "\\Pictures\\";
String[] directories = {pics, docs, vids, musc};
String[] bkDirectories = {bkPics, bkDocs, bkVids, bkMusc};
//Loop through directories and copy files
for (int i = 0; i < directories.length; i++) {
File dir = new File(directories[i]);
File dest = new File(bkDirectories[i]);
for (File file : dir.listFiles()) {
try{
if (file.isFile()) {
FileUtils.copyFileToDirectory(file, dest);
publish(file.getAbsolutePath() + "\n");
} else if (file.isDirectory()) {
FileUtils.copyDirectoryToDirectory(file, dest);
Thread.sleep(1000);
publish(file.getAbsolutePath() + "\n");
}
if (getDirSize(file) >= ONE_PERCENT) {
currentPercent = getDirSize(file) / ONE_PERCENT;
setProgress((int) currentPercent);
currentSize = 0;
} else {
currentSize = currentSize + getDirSize(file);
if (currentSize >= ONE_PERCENT) {
currentPercent = currentSize / ONE_PERCENT;
currentPercent++;
setProgress((int) currentPercent);
currentSize = 0;
}
}
} catch (IOException e){
e.printStackTrace();
}
}
}
return null;
}
@Override
public void process(List<String> chunks) {
for (String path : chunks) {
txtCopiedDirs.append(path);
}
}
@Override
public void done() {
closeWindow();
}
}
public static 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;
}
/* Close current window */
public void closeWindow() {
WindowEvent close = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(close);
System.exit(0);
}
}