我正在处理执行某些功能的应用程序,这些功能会运行很长时间。为了让用户知道正在进行处理,我需要一个标签,该标签可以显示一些可以表示该情况的标签。因此,我为此类标签创建了一个小部件。

下面的程序运行find,并根据需要获取输出。

import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


/**
 * This is an extension to a JLabel that can be used to display an ongoing progress.
 * @author Ankit Gupta
 */
public class ProgressLabel extends JLabel {

    /**
     * The prefix label to which periods are added.
     */
    private String startLabel;
    /**
     * The label to display end of an operation.
     */
    private String endLabel;

    /**
     * Flag to indicate whether the animation is running or not.
     */
    private boolean running = false;
    //list to hold intermediate labels
    List<String> intermediateLabels;

    public ProgressLabel(String slbl, String elbl) {
        this.startLabel = slbl;
        this.endLabel = elbl;
        //initialize all the labels to be used once as creating them again and again is expensive
        intermediateLabels = new ArrayList<String>();
        intermediateLabels.add(startLabel+".");
        intermediateLabels.add(startLabel+"..");
        intermediateLabels.add(startLabel+"...");
        intermediateLabels.add(startLabel+"....");
    }

    public void done(){
        running = false;
    }

    public void start(){
        running = true;
        new LabelUpdateThread().start();
    }

    private class LabelUpdateThread extends Thread{
        int i;

        public LabelUpdateThread(){
            i=0;
        }

        @Override
        public void run(){
            while(running){
                SwingUtilities.invokeLater(new Runnable(){
                    @Override
                    public void run() {
                        setText(intermediateLabels.get((i++)%3));
                    }
                });

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {}
            }
            setText(endLabel);
        }
    }

    public static void main(String []args) throws InterruptedException{
        final JFrame frame = new JFrame("Testing ProgressLabel");
        JPanel panel = new JPanel();
        ProgressLabel progressLabel = new CZProgressLabel("Searching", "Done");
        panel.add(progressLabel);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(500,500));
        frame.pack();
        progressLabel.start();
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                frame.setVisible(true);
            }
        });
        Thread.sleep(5000);
        progressLabel.done();
    }
}


但是,当我尝试将其包含在应用程序中时,它没有按预期工作。我创建了一个带有按钮的小面板,并在按钮的actionPerfomed()代码中像以前一样使用ProgressLabel的start()和done()方法,但是这次,标签直到长度过程完成。这是使用ProgressLabelactionPerformed()的另一段代码:

public class SearchPanel extends JPanel {

    private JTextArea queryBox;
    private JButton searchBtn;
    private ProgressLabel progressLabel;
    private JSeparator queryAreaSeparator;

    public SearchPanel() {
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();

        //First Row
        gbc.gridy = 0;
        gbc.gridwidth = 2;
        gbc.gridx = 0;
        queryBox = new JTextArea();
        queryBox.setRows(25);
        queryBox.setColumns(25);
        this.add(queryBox, gbc);


        //Second Row
        gbc.gridy = 1;

        gbc.gridwidth = 1;
        progressLabel = new ProgressLabel("Searching", "Done");
        this.add(progressLabel, gbc);

        gbc.gridx = 1;
        searchBtn = new JButton("Search");
        this.add(searchBtn, gbc);
        searchBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                progressLabel.start();
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException ex) {
                    Exceptions.printStackTrace(ex);
                }
                //the above sleep() call will be replace by some time-consuming process. It is there just for testing now

                progressLabel.done();
            }
        });


        gbc.gridx = 0;
    }

    /**
     * function to test CZSemanticSearchLabel
     */
    public static void main(String[] args) throws InterruptedException {
        final JFrame frame = new JFrame();
        CZSemanticSearchPanel panel = new CZSemanticSearchPanel();
        frame.add(panel);
        frame.setPreferredSize(new Dimension(500, 500));
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        Thread.sleep(10000);
        frame.dispose();


        final JFrame frame1 = new JFrame("Testing ProgressLabel");
        JPanel panel1 = new JPanel();
        CZProgressLabel progressLabel = new CZProgressLabel("Searching", "Done");
        panel1.add(progressLabel);
        frame1.add(panel1);
        frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame1.setPreferredSize(new Dimension(500, 500));
        frame1.pack();
        progressLabel.start();
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                frame1.setVisible(true);
            }
        });
        Thread.sleep(5000);
        progressLabel.done();
    }
}


我相信我已经在Swing的事件分发模型中搞砸了。但是,我不知道是什么?有人可以告诉我这段代码有什么问题,我该如何纠正?

最佳答案

我不知道您的实际代码,但是您的示例代码有缺陷...

在您的ActionListener中,您正在执行此操作...

progressLabel.start();
try {
    Thread.sleep(10000);
} catch (InterruptedException ex) {
    Exceptions.printStackTrace(ex);
}
//the above sleep() call will be replace by some time-consuming process. It is there just for testing now

progressLabel.done();


这将停止Event Dispatching Thread,在10秒钟内阻止来自已处理的任何重新绘制请求(即,没有屏幕更新)...这还将使您的应用程序看起来像是“挂起”。

我将ActionListener更新为这样(请注意,我添加了isRunning方法,该方法从标签返回running成员)

if (progressLabel.isRunning()) {
    progressLabel.done();
} else {
    progressLabel.start();
}


而且效果很好。

您可能想通读Currency in Swing以获得更多想法。

另外,正如已经建议的那样,SwingWorker可能是更好的方法

07-24 09:21