我用更新进度监控长时间运行的任务。 在长时间运行的任务是对的SwingWorker线程执行过程中。
我用编程这样的事情:
public class MySwingWorkerClass extends SwingWorker<Void, Void> {
private JProgressBar progressBar;
public MySwingWorker(JProgressBar aProgressBar) {
this.progressBar = aProgressBar;
progressBar.setVisible(true);
progressBar.setStringPainted(true);
progressBar.setValue(0);
}
@Override
public Void doInBackground() {
//long running task
loop {
calculation();
progressBar.setValue(value);
}
return null;
}
@Override
public void done() {
progressBar.setValue(100);
progressBar.setStringPainted(false);
progressBar.setVisible(false);
}
}
但最近我发现,我可以通过使用“setProgress”和定义属性的变化做,做这样的事情
public class MySwingWorkerClass extends SwingWorker<Void, Void> {
private JProgressBar progressBar;
public MySwingWorker(JProgressBar aProgressBar) {
addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer) evt.getNewValue());
}
}
});
progressBar.setVisible(true);
progressBar.setStringPainted(true);
progressBar.setValue(0);
setProgress(0);
}
@Override
public Void doInBackground() {
//long running task
loop {
calculation();
setProgress(value);
}
return null;
}
@Override
public void done() {
setProgress(100);
progressBar.setValue(100);
progressBar.setStringPainted(false);
progressBar.setVisible(false);
}
}
我的问题是:是我的第一个代码可以接受或我将使用setProgress为anyreason? 我觉得第二个代码更为复杂,在我的情况,不知道是否有任何优势或理由使用第二个。
任何建议?
编辑感谢您的回答。 作为一个总结。 第一个解决方案是因为,美国东部时间在外面进行更新进度条的“错误”。 第二种解决方案是“正确的”,因为进度条更新的EDT内进行
现在,根据@mKorbel在我的情况下,“有趣”的答案我计算给在HTML文本结果我“插入”(见这个链接 )。 我当前的代码如下。
我出版(串)和我的过程代码看起来像
@Override
protected void process(List<String> strings) {
for (String s : strings) {
try {
htmlDoc.insertBeforeEnd(htmlDoc.getElement(htmlDoc.getDefaultRootElement(), StyleConstants.NameAttribute, HTML.Tag.TABLE), s);
} catch (BadLocationException ex) {
} catch (IOException ex) {
}
}
}
如何重新@mKobel做同样的在我的案件。 我的意思是,他用它来覆盖表呈现在我的情况,我将覆盖哪些渲染器(JTextPane的?)怎么样?
在第一个代码,您呼叫在非EDT(事件调度线程)线程以下行。 所以它不是线程安全的:
progressBar.setValue(value);
这可能会导致意外的行为,Swing不是设计成线程安全的库。
有不同的方法在Swing的方式执行此。 这方面的一个正确的方法是你在第二个职位做了什么。 另一个办法是使用publish()/process()
方法和第三种方法是,写你自己的线程,而不是SwingWorker
和使用SwingUtilities.invokeLater()
我用更新进度监控长时间运行的任务。 在长时间运行的任务是对的SwingWorker线程执行过程中。
右边可以使用SwingWorker
在所有情况下重定向任何重型和长时间运行的任务的Background
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableCellProgressBar {
private String[] columnNames = {"String", "ProgressBar"};
private Object[][] data = {{"dummy", 100}};
private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
@Override
public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
@Override
public boolean isCellEditable(int row, int col) {
return false;
}
};
private JTable table = new JTable(model);
public JComponent makeUI() {
TableColumn column = table.getColumnModel().getColumn(1);
column.setCellRenderer(new ProgressRenderer());
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
startTask("test");
startTask("error test");
startTask("test");
}
});
JPanel p = new JPanel(new BorderLayout());
p.add(new JScrollPane(table));
return p;
}
//http://java-swing-tips.blogspot.com/2008/03/jprogressbar-in-jtable-cell.html
private void startTask(String str) {
final int key = model.getRowCount();
SwingWorker<Integer, Integer> worker = new SwingWorker<Integer, Integer>() {
private int sleepDummy = new Random().nextInt(100) + 1;
private int lengthOfTask = 120;
@Override
protected Integer doInBackground() {
int current = 0;
while (current < lengthOfTask && !isCancelled()) {
if (!table.isDisplayable()) {
break;
}
if (key == 2 && current > 60) { //Error Test
cancel(true);
publish(-1);
return -1;
}
current++;
try {
Thread.sleep(sleepDummy);
} catch (InterruptedException ie) {
break;
}
publish(100 * current / lengthOfTask);
}
return sleepDummy * lengthOfTask;
}
@Override
protected void process(java.util.List<Integer> c) {
model.setValueAt(c.get(c.size() - 1), key, 1);
}
@Override
protected void done() {
String text;
int i = -1;
if (isCancelled()) {
text = "Cancelled";
} else {
try {
i = get();
text = (i >= 0) ? "Done" : "Disposed";
} catch (Exception ignore) {
ignore.printStackTrace();
text = ignore.getMessage();
}
}
System.out.println(key + ":" + text + "(" + i + "ms)");
}
};
model.addRow(new Object[]{str, 0});
worker.execute();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new TableCellProgressBar().makeUI());
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class ProgressRenderer extends DefaultTableCellRenderer {
private final JProgressBar b = new JProgressBar(0, 100);
public ProgressRenderer() {
super();
setOpaque(true);
b.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Integer i = (Integer) value;
String text = "Completed";
if (i < 0) {
text = "Error";
} else if (i < 100) {
b.setValue(i);
return b;
}
super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
return this;
}
}
但为什么用Wwing GUI复杂SwingWorker
(大约需要最深的知识Java Essential Classes
和Generics
太)
对于基本的实现Runnable#Thread
仅需要invokeLater
用于输出到摆动GUI,并在的情况下从EDT(从摇摆/ AWT监听器)开始,并且没有任何代码行包含Thread.sleep(int)
然后是invokeLater
仅谏/生产所需的代码
import java.awt.Component;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
public class TableWithProgressBars {
public static class ProgressRenderer extends JProgressBar implements TableCellRenderer {
private static final long serialVersionUID = 1L;
public ProgressRenderer(int min, int max) {
super(min, max);
this.setStringPainted(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
this.setValue((Integer) value);
return this;
}
}
private static final int maximum = 100;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TableWithProgressBars().createGUI();
}
});
}
public void createGUI() {
final JFrame frame = new JFrame("Progressing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Integer[] oneRow = {0, 0, 0, 0};
String[] headers = {"One", "Two", "Three", "Four"};
Integer[][] data = {oneRow, oneRow, oneRow, oneRow, oneRow,};
final DefaultTableModel model = new DefaultTableModel(data, headers);
final JTable table = new JTable(model);
table.setDefaultRenderer(Object.class, new ProgressRenderer(0, maximum));
table.setPreferredScrollableViewportSize(table.getPreferredSize());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
new Thread(new Runnable() {
@Override
public void run() {
Object waiter = new Object();
synchronized (waiter) {
int rows = model.getRowCount();
int columns = model.getColumnCount();
Random random = new Random(System.currentTimeMillis());
boolean done = false;
while (!done) {
int row = random.nextInt(rows);
int column = random.nextInt(columns);
Integer value = (Integer) model.getValueAt(row, column);
value++;
if (value <= maximum) {
model.setValueAt(value, row, column);
try {
waiter.wait(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
done = true;
for (row = 0; row < rows; row++) {
for (column = 0; column < columns; column++) {
if (!model.getValueAt(row, column).equals(maximum)) {
done = false;
break;
}
}
if (!done) {
break;
}
}
}
frame.setTitle("All work done");
}
}
}).start();
}
}
我对你看看真正的沉重和长时间运行的任务结束Runnable#Thread
(简单,易行,non_buggy和清晰的方式),只有当你对知识Java
和Swing
得非常好,那么你可以考虑SwingWorker
你的第二个方法是正确的,甚至在的类Javadoc文档SwingWorker
类。 “进度”事件在美国东部时间发射,所以你的听众更新在美国东部时间进度条。 这是不是在你的第一种方法的情况。
(使用的另一种方法的一个例子publish/process
由大臣表示)中可以找到我的答案在以前SO问题
如该所示例子 ,你的工人使用setProgress()
在你的第二个例子是正确的:任何PropertyChangeListener
将异步事件调度线程上通知。