java - 在 SwingWorker 中实现 JScrollPane/JTextArea

标签 java implementation jtextarea swingworker jscrollbar

使用 SwingWorker 时,我的 JScrollPane/JTextArea 遇到一些问题。这是我目前拥有的:

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

这不是确切的代码,但它应该可以让您了解其要点。不管怎样,问题是 JScrollPane 根本没有出现,尽管 doInBackground() 方法中的代码确实运行了。我希望它与后台任务中的更新(txtDirs.append(file.getAbsolutePath()))有关。但是,我不太确定在这种情况下如何使其发挥作用。该框架按预期显示,但完全是空白的。 Task 类中应该有一个“process”方法吗?那是“txtDirs.append(file.getAbsolutePath())”应该放置的地方吗?恐怕我对 SwingWorkers 的使用相当陌生,所以任何帮助将不胜感激。

编辑:

经过一番困惑后,我决定简单地发布我的完整代码。我知道它有问题,而且我可能误解了评论中提到的一些内容,所以我希望发布此内容能让有人指出我所犯的任何明显错误。

完整代码:

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

编辑#2:

我对 createGUI() 方法进行了一些更改,以避免 contentPane 具有空布局:

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 ,而是使用 JTextArea(rows, cols)
  • 请勿从 EDT 外部修改任何 UI 组件,而是使用 publish并覆盖processprocess在 EDT 的内容中调用

看看Concurrency in Swing了解更多详情

导致您的问题的可能原因包括...

  • 在使用 BorderLayout 时向框架添加其他组件,不指定位置约束(BorderLayout.CENTER 除外)
  • 在添加组件之前调用visible

已更新

主要问题是 contentPane正在使用 null布局和滚动 Pane 的默认边界是 0x0位置 0x0宽度和高度。

最好的选择是不使用WinodwBuilder并学习如何使用layout managers

用示例更新

这是一个使用两个布局管理器的示例,BorderLayout作为基本布局和 GridBagLayout为额外的组件提供一些额外的支持。

基本经验法则。如果它是 UI 组件,特别是如果它在屏幕上(或者您不知道它是否在屏幕上),则必须仅从 EDT 的上下文中更新它。

这意味着调用progressBar.setValue来自doInBackground内违反了Swing的单线程规则。 SwingWorker通过其 PropertyChange 提供进度更新支持

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

关于java - 在 SwingWorker 中实现 JScrollPane/JTextArea,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20778551/

相关文章:

java - 如何独立设计一个java矩阵类实现

java - Mule:不同组件的接口(interface)绑定(bind),如何避免重复?

java - 如何从 Apache 的 UploadedFile 类中获取 java.io.File?

java - spring 使用哪个模型类来响应请求映射方法的错误?

java - 如何实现ListIterator?

error-handling - try/catch block 如何实现?

java - 如何向 JTextArea 添加水平和垂直滚动条(java)

java - 如何在 JTextArea 中为文本生成 html?

java - 检查两个字符串是否相同以停止输入

java - 我需要在同一页上打印 JTextArea 和 JTable。