【问题标题】:Java loading gif freeze while processing data?Java在处理数据时加载gif冻结?
【发布时间】:2018-08-29 14:26:48
【问题描述】:

我调用了一个列出目录中所有文件的方法,并将它们添加到 JTable:

    addFilesWithSubsButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            reverseLoadingVisibility(loaderLabel); //set Visible
            addFilesWithSubs2(chooser, loaderLabel);
        }
    });

public void addFilesWithSubs2(JFileChooser chooser, JLabel loaderLabel) {
    //loading all files ....

    //when every file is listed:
    //Set invisible
    reverseLoadingVisibility(loaderLabel);
}

另一种方法是改变加载 .gif 所在的 JLabel 的可见性。

public void reverseLoadingVisibility(JLabel loaderLabel) {
    loaderLabel.setVisible(!loaderLabel.isVisible());
}

问题是:gif 不播放,冻结,而文件被添加到 JTable。

更新:加载 gif 冻结仍有问题

addFilesButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                reverseLoadingVisibility(loaderLabel);
                try {
                    new AddFiles().doInBackground(
                            chooser, CHOOSERTITLE, 
                            lastDictionary,
                            sdf,
                            filesTable,
                            model,
                            columnNames,
                            loaderLabel);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

公共类 AddFiles 扩展 SwingWorker{

@Override
protected Void doInBackground() throws Exception {
    return null;
}

protected void doInBackground(JFileChooser chooser, String CHOOSERTITLE, 
        String lastDictionary,
        SimpleDateFormat sdf,
        JTable filesTable,
        DefaultTableModel model,
        String[] columnNames,
        JLabel loaderLabel) throws Exception {
    //Set visible
    reverseLoadingVisibility(loaderLabel);


    chooser.setDialogTitle(CHOOSERTITLE);
    chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
    //
    chooser.setAcceptAllFileFilterUsed(true);
    //TODO: this changed to chooser    
    if (chooser.showOpenDialog(chooser) == JFileChooser.APPROVE_OPTION) { 

      // create a file that is really a directory
      File aDirectory = new File(chooser.getSelectedFile().toString());
      lastDictionary = chooser.getSelectedFile().toString();

      // get a listing of all files in the directory
      String[] filesInDir = aDirectory.list();
      // TODO
      System.out.println("Number of files: " + filesInDir.length);

      // have everything i need, just print it now


      for ( int i=0; i<filesInDir.length; i++ )
          {
            File currentFile = new File(aDirectory + "\\" + filesInDir[i]);

            System.out.println(filesInDir[i] );
            System.out.println(aDirectory );
            System.out.println(currentFile.length()/1024 + " KB");



            System.out.println(sdf.format((currentFile).lastModified()));

            // Avoid duplicates
            int row = 0;
            boolean duplicate = false;
            for (; row < filesTable.getRowCount(); row++) {
                if (model.getValueAt(row, 1).equals(filesInDir[i]) &&
                    model.getValueAt(row, 3).equals(aDirectory)
                ) {
                    duplicate = true;
                    break;
                }
                System.out.println("model.getValueAt(row, 1) " + model.getValueAt(row, 1));
                System.out.println(filesInDir[i]);
                System.out.println("model.getValueAt(row, 3) " + model.getValueAt(row, 3));
                System.out.println(aDirectory);
            }

            if (!duplicate && currentFile.isFile()) {
                model.addRow(new Object[]{
                        filesTable.getRowCount()+1, 
                        filesInDir[i],
                        null,
                        aDirectory,
                        currentFile.length()/1024 + " KB",
                        sdf.format((currentFile).lastModified())
                });


            }


          }
      }
    else {
      System.out.println("No Selection ");
    }

    // Readjust columns
    adjustTableColumns(filesTable, columnNames);

    //Set unvisible
    reverseLoadingVisibility(loaderLabel);
}

...

【问题讨论】:

    标签: java swing


    【解决方案1】:

    这就是为什么因为所有文件都在 EDT(事件调度线程)中加载(希望您使用 SwingUtilities.invokerLater() 方法启动您的应用程序),这会导致所有摆动组件冻结。有关详细信息,请阅读 oracle 的此 java 文档:Initial Threads.

    为了解决您的问题,您必须使用SwingWorker。负责 Swing 应用程序中繁重的后台任务的类。通过简单的谷歌搜索,你可以从这里得到一个想法:How do I use SwingWorker in Java?

    UPDATE 以回答 OP 的评论。

    事实是你的代码有点大,最重要的是,它不是SSCCE.

    为了帮助您找到您正在寻找的解决方案,我创建了一个 SSCCE,使用 SwingWorker 做一些“重”的事情。在我们的例子中,繁重的事情是在 .txt 文件中写入 1000 行,但每一行、线程(我们的工作人员)将休眠 10 毫秒。

    看看,如果你想运行它(我推荐它)。代码中有一些额外的cmets,不要忘记检查它们。

    package test;
    
    import java.awt.BorderLayout;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileWriter;
    import java.util.List;
    
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    
    public class SwingWorkerExample extends JFrame {
        /*
         * Worker has Void doInBackground a.k.a, doInBackground method needs to return nothing.
         * Worker needs to process-publish Integers.
         */
        private SwingWorker<Void, Integer> writeToFileWorker = null;
        private JLabel gifLabel;
        private JButton doSomethingHeavy;
    
        public SwingWorkerExample() {
            super("Just a test.");
            createWorker();
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            getContentPane().setLayout(new BorderLayout());
            gifLabel = new JLabel();
            ImageIcon gif = new ImageIcon("C:/Users/George/Desktop/giphy.gif");
            gifLabel.setIcon(gif);
            gifLabel.setVisible(false); //Initialy non visible
            gifLabel.setHorizontalTextPosition(JLabel.CENTER);
            gifLabel.setVerticalTextPosition(JLabel.BOTTOM);
            gifLabel.setHorizontalAlignment(JLabel.CENTER);
            getContentPane().add(gifLabel, BorderLayout.CENTER);
    
            doSomethingHeavy = new JButton("Do something heavy in another thread and start dancing...");
            doSomethingHeavy.addActionListener(e -> {
                //Before start the worker, show gif and disable the button
                doSomethingHeavy.setEnabled(false);
                gifLabel.setVisible(true);
                writeToFileWorker.execute();
            });
            getContentPane().add(doSomethingHeavy, BorderLayout.PAGE_END);
            setSize(500, 300);
            setLocationRelativeTo(null);
        }
    
        private void createWorker() {
            writeToFileWorker = new SwingWorker<Void, Integer>() {
                @Override
                protected Void doInBackground() throws Exception {
                    File fileToWrite = new File(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "hello_worlds.txt");
                    try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileToWrite));) {
                        for (int line = 0; line < 1000; line++) {
                            writer.append("Hello World! My name is Swing Worker.");
                            writer.append(System.lineSeparator());
                            Thread.sleep(10);
                            publish(line);
                        }
                    }
                    return null;
                }
    
                /*
                 * Runs in Event Dispatch Thread (EDT)
                 */
                @Override
                protected void process(List<Integer> chunks) {
                    int line = chunks.get(0);//First parameter is the line
                    gifLabel.setText("Written " + line + " lines in the txt.");
                    super.process(chunks);
                }
    
                /*
                 * Runs in Event Dispatch Thread (EDT)
                 */
                @Override
                protected void done() {
                    //When swing worker is finished, a.k.a the heavy work, stop the gif and enable the button
                    gifLabel.setVisible(false);
                    doSomethingHeavy.setEnabled(true);
                    super.done();
                }
            };
    
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                SwingWorkerExample swe = new SwingWorkerExample();
                swe.setVisible(true);
            });
        }
    }
    

    小预览:

    【讨论】:

    • @lipilocid 我更新了我的帖子。花点时间检查一下。
    【解决方案2】:

    我的猜测是您的 addFilesWithSubs2-Method 阻塞了 UI 线程。如果您有长时间运行的任务,则必须在单独的线程中执行它们,例如SwingWorker

    【讨论】:

    • 有很多问题,但我会给你一些提示。您的 AddFiles 类正在覆盖 SwingWorker 的 doInBackground 方法(因为您正在扩展 SwingWoker 类)。您必须将长时间运行的任务代码放入该方法中,而不是创建具有相同名称和一些参数的方法。最后,当您创建 AddFiles 类的实例时,您必须调用 execute 方法来启动后台任务(因此 doInBackground 方法会被执行)。
    猜你喜欢
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-02
    相关资源
    最近更新 更多