JTextArea追加问题

3
我正在制作一个备份程序,并希望将需要备份的所有内容显示在JTextArea上。代码可以运行,但只能在程序完成备份后才显示。我该怎么解决?下面是运行此操作的代码:

备份方法

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);
            }
     }

复制文件夹类:
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类
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");
}
    }

提前感谢您的帮助,并让我知道我可以提供任何帮助。我在谷歌上搜索了一下,似乎这是一个大问题,但我就是想不出如何解决它。哦,请不要因为它与您无关而对此进行负评,这非常令人恼火。再次提前感谢您!编辑:这就是我得到的内容。
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);
}
    }

你正在尝试在SwingWorker的doInBackground()方法中进行Swing调用,这正好与你想要做的相反。请阅读教程以了解如何使用此工具。 - Hovercraft Full Of Eels
哦,抱歉我在重新编辑时忘记删除了那个。对不起。 - PulsePanda
可能一晚上好的睡眠会有所帮助。我现在要去睡觉了,如果我没有回复,请见谅。 - PulsePanda
1个回答

5
你遇到的主要问题是试图在 事件分发线程 中执行阻塞操作。这将导致UI无法更新,因为重绘请求在完成之前不会传达给重绘管理器。
为了解决这个问题,你需要将阻塞工作(即备份进程)转移到单独的线程中。
我建议你阅读Swing并发教程,它将为你提供一些有用的策略来解决你特定的问题。特别是,你可能会受益于使用SwingWorker
请仔细查看doInBackgroundprocess方法。

使用示例进行了更新

好的,这是一个非常简单的示例。它基本上遍历 C:\ 目录下三级目录,并将内容转储到提供的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);

            }

        }

    }

}

你只需要调用new BackgroundWorker(textField).execute()就可以了,然后离开:D

更新了具体的示例

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);

    }
}

现在运行...
new BackgroundWorker(textArea, sourceDir, destDir).execute();

2
不行,因为你只是让“事件分派线程”休眠。你需要在“EDT”之外执行备份工作,并将更新请求重新同步到“EDT”中(SwingUtilities.invokeLater 对此很有用,但坦白地说,你的问题适合使用 SwingWorker API)。 - MadProgrammer
那么,建议中有什么问题吗?基本上,它做了你刚才要求的事情。 - MadProgrammer
1
@MadProgrammer是正确的;你的编辑是错误的。请遵循API中的示例或此处 - trashgod
我正在尝试使用SwingWorker,但是我无法让它正常工作!请检查新的编辑以查看我如何制作和初始化它。 - PulsePanda
1
@wbAnon 请看我的例子。你不需要一个ThreadSwingWorker会为你创建它。不要任何除了EDT之外的Thread中修改Swing组件。在doBackground方法中工作,并且publish你想要在屏幕上更新的内容。使用process方法来更新UI。 - MadProgrammer
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接