我正在处理执行某些功能的应用程序,这些功能会运行很长时间。为了让用户知道正在进行处理,我需要一个标签,该标签可以显示一些可以表示该情况的标签。因此,我为此类标签创建了一个小部件。
下面的程序运行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()方法,但是这次,标签直到长度过程完成。这是使用ProgressLabel
和actionPerformed()
的另一段代码: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可能是更好的方法