3

Im making a backup program, and I want everything that i have the program backing up displayed on a JTextArea. well, it works, but only after the program is finished with the backup. How do i fix this? The code i have running this is here:

backup method

public void startBackup() throws Exception {
    // txtarea is the JTextArea
    Panel.txtArea.append("Starting Backup...\n");

    for (int i = 0; i < al.size(); i++) {
        //al is an ArrayList that holds all of the backup assignments selected
        // from the JFileChooser

        File file = new File((String) al.get(i));
        File directory = new File(dir);

        CopyFolder.copyFolder(file, directory);
            }
     }

Copy Folder class:

public class CopyFolder {
public static void copyFolder(File src, File dest) throws IOException {

    if (src.isDirectory()) {

        // if directory not exists, create it
        if (!dest.exists()) {
            dest.mkdir();
            Panel.txtArea.append("Folder " + src.getName()
                    + " was created\n");
        }

        // list all the directory contents
        String files[] = src.list();

        for (String file : files) {
            // construct the src and dest file structure
            File srcFile = new File(src, file);
            File destFile = new File(dest, file);
            // recursive copy
            copyFolder(srcFile, destFile);
        }

    } else {
        try {
            CopyFile.copyFile(src, dest);
        } catch (Exception e) {
        }
    }
}
    }

CopyFile class

public class CopyFile {

public static void copyFile(File src, File dest) throws Exception {
    // if file, then copy it
    // Use bytes stream to support all file types
    InputStream in = new FileInputStream(src);
    OutputStream out = new FileOutputStream(dest);

    byte[] buffer = new byte[1024];

    int length;
    // copy the file content in bytes
    while ((length = in.read(buffer)) > 0) {
        out.write(buffer, 0, length);
    }

    in.close();
    out.close();
    // System.out.println("File copied from " + src + " to " + dest);
    Panel.txtArea.append("File copied " + src.getName() + "\n");
}
    }

Thanks for the help in advance, and let me know of any assistance i can give. I did a google search on this, and it does seem to be a big problem, but i just cant think of how to fix it. Oh, and please dont downvote this just because it doesnt apply to you, its very aggravating. Thanks in advance again!

EDIT: This is what i got:

public class test extends SwingWorker<Void, String> {
String txt;
JTextArea txtArea = null;

public test(JTextArea txtArea, String str) {
    txt = str;
    this.txtArea = txtArea;
}

protected Void doInBackground() throws Exception {

    return null;
}

protected void process(String str) {
    txtArea.append(str);
}

protected void getString() {
    publish(txt);
}
    }
mKorbel
  • 109,525
  • 20
  • 134
  • 319
PulsePanda
  • 1,806
  • 10
  • 33
  • 56

1 Answers1

5

The main problem you're having is you're trying to perform blocking actions in the Event Dispatching Thread. This will prevent the UI from been updated as repaint requests are not reaching the repaint manager until AFTER you've finished.

To over come this, you're going to need to off load the blocking work (ie the back up process) to a separate thread.

For this I suggest you have a read through the Concurrency in Swing Trail which will provide you with some useful strategies to solve your particular problem. In particular, you'll probably benifit from using a SwingWorker

Take a close look at doInBackground and the process methods

UPDATED with Example

Okay, so this is a REALLY simple example. This basically walks you C:\ drive to 3 directories deep and dumps the content to the supplied JTextArea

public class BackgroundWorker extends SwingWorker<Object, File> {

    private JTextArea textArea;

    public BackgroundWorker(JTextArea textArea) {

        this.textArea = textArea;

    }

    @Override
    protected Object doInBackground() throws Exception {

        list(new File("C:\\"), 0);

        return null;

    }

    @Override
    protected void process(List<File> chunks) {

        for (File file : chunks) {

            textArea.append(file.getPath() + "\n");

        }

        textArea.setCaretPosition(textArea.getText().length() - 1);

    }

    protected void list(File path, int level) {

        if (level < 4) {

            System.out.println(level + " - Listing " + path);

            File[] files = path.listFiles(new FileFilter() {

                @Override
                public boolean accept(File pathname) {

                    return pathname.isFile();

                }
            });

            publish(path);
            for (File file : files) {

                System.out.println(file);
                publish(file);

            }

            files = path.listFiles(new FileFilter() {

                @Override
                public boolean accept(File pathname) {

                    return pathname.isDirectory() && !pathname.isHidden();

                }
            });

            for (File folder : files) {

                list(folder, level + 1);

            }

        }

    }

}

You would simply call new BackgroundWorker(textField).execute() and walk away :D

UPDATED with explicit example

public class BackgroundWorker extends SwingWorker<Object, String> {

    private JTextArea textArea;
    private File sourceDir;
    private File destDir;

    public BackgroundWorker(JTextArea textArea, File sourceDir, File destDir) {

        this.textArea = textArea;
        this.sourceDir = sourceDir;
        this.destDir = destDirl

    }

    @Override
    protected Object doInBackground() throws Exception {

        if (sourceDir.isDirectory()) {

            // if directory not exists, create it
            if (!destDir.exists()) {
                destDir.mkdir();
                publish("Folder " + sourceDir.getName() + " was created");
            }

            // list all the directory contents
            String files[] = sourceDir.list();

            for (String file : files) {
                // construct the src and dest file structure
                File srcFile = new File(sourceDir, file);
                File destFile = new File(destDir, file);
                // recursive copy
                copyFolder(srcFile, destFile);
            }

        } else {
            try {
                copyFile(sourceDir, destDir);
            } catch (Exception e) {
            }
        }

        return null;

    }

    public void copyFolder(File src, File dest) throws IOException {

        if (src.isDirectory()) {

            // if directory not exists, create it
            if (!dest.exists()) {

                publish("Folder " + src.getName() + " was created");
            }

            // list all the directory contents
            String files[] = src.list();

            for (String file : files) {
                // construct the src and dest file structure
                File srcFile = new File(src, file);
                File destFile = new File(dest, file);
                // recursive copy
                copyFolder(srcFile, destFile);
            }

        } else {
            try {
                copyFile(src, dest);
            } catch (Exception e) {
            }
        }
    }

    public void copyFile(File src, File dest) throws Exception {
        // if file, then copy it
        // Use bytes stream to support all file types
        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dest);

        byte[] buffer = new byte[1024];

        int length;
        // copy the file content in bytes
        while ((length = in.read(buffer)) > 0) {
            out.write(buffer, 0, length);
        }

        in.close();
        out.close();
        publish("File copied " + src.getName());

    }

    @Override
    protected void process(List<String> chunks) {

        for (String msg : chunks) {

            textArea.append(msg + "\n");

        }

        textArea.setCaretPosition(textArea.getText().length() - 1);

    }
}

Now to run...

new BackgroundWorker(textArea, sourceDir, destDir).execute();
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 2
    No, cause you're just making the `Event Dispatching Thread` go to sleep. You need to perform you backup work out side of the `EDT` and resync your update requests back into the `EDT` (`SwingUtilities.invokeLater` is useful for this, but to quite frank, your problem fits into the `SwingWorker` API) – MadProgrammer Aug 13 '12 at 01:29
  • So what's wrong with what's been suggested? Essentially, it does what you just asked – MadProgrammer Aug 13 '12 at 01:41
  • 1
    @MadProgrammer is correct; your edit is wrong. Follow the examples in the API or [here](http://stackoverflow.com/questions/tagged/java+swing+swingworker). – trashgod Aug 13 '12 at 01:41
  • well im trying to use the SwingWorker, but i cant get it to freakin work! check new edit to see how i have it made and initiallized – PulsePanda Aug 13 '12 at 02:10
  • 1
    @wbAnon Read my example. You **DON'T** need a `Thread`, `SwingWorker` will create it for you. **DO NOT** modify Swing components in **ANY** `Thread` other then the `EDT`. Do you work in the `doBackground` method and `publish` what you want to be updated on the screen. Use the `process` method to make the updates to the UI – MadProgrammer Aug 13 '12 at 02:28
  • could you possibly make show an example of an implementation of this with my code? because i've been working on this for a while, since you posted your update, and i just cant get it. i think this is one of those things that i dont get for a while, then later its like "DUH! Now i get it!" but ya if you could do that, that would be really great! thanks! PS: Check edit for the things that i got to... – PulsePanda Aug 13 '12 at 02:44
  • Wow. That explicit example is truly 'deluxe service'. :) – Andrew Thompson Aug 13 '12 at 03:02
  • The design of your code is a little awkward. I'd be making more use of the `Observer Pattern` (http://en.wikipedia.org/wiki/Observer_pattern) with the copy functionality, basically using it as a callback to notify me of events that are occurring. This would then be used to update the UI (or what ever else I needed) – MadProgrammer Aug 13 '12 at 03:03
  • Ok wow. i really need to figure out how all this works, but holy crap it worked! Thats really awesome! thanks MadProgrammer. +1 and thank you so much for your tips and custom code! – PulsePanda Aug 13 '12 at 13:17