在这个例子中,我试图在我的GUI中添加一个表,然后动态地向其添加行(以显示进度)。我不明白的是为什么所有的行都会立刻出现。我的意思是,表格的变化,不是吗?有人可以给我一个解释吗?
import java.awt.Component;
public class Main {
public static void main(String[] args) {
// Show GUI
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
GUI gui = new GUI();
gui.setVisible(true);
DefaultTableModel model = new DefaultTableModel(
new String[] { "Column 1", "Column 2" }, 0);
JTable table = new JTable(model);
gui.add(table);
gui.validate();
for (int i = 0; i < 10; i++) {
System.out.println("Row " + i);
model
.addRow(new String[] { "Row", String.valueOf(i) });
// model.fireTableDataChanged();
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
}
class GUI extends JFrame {
private static final long serialVersionUID = 1L;
public GUI() {
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 350, 100);
setLocationRelativeTo(null);
JPanel cp = new JPanel();
cp.setBorder(new EmptyBorder(10, 10, 10, 10));
setContentPane(cp);
}
}
答案 0 :(得分:3)
重申Kleopatra:不要睡觉EDT
您可以使用this answer
中的javax.swing.Timer
修改强>
我也不想弄乱你的代码太多(只是因为它看起来很奇怪)但我改变了一点来添加Timer
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
public class Main {
static JTable table;
static GUI gui;
static Processor p = null;
public static void main(String[] args) {
// Show GUI
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
gui = new GUI();
p = new Processor() {
@Override
public void execute() {
final JTable table = new JTable(p.getTableModel());
final JScrollPane scrollPane = new JScrollPane(table);
gui.getContentPane().add(scrollPane, BorderLayout.CENTER);
gui.setLocationRelativeTo(null);
gui.setVisible(true);
Timer timer = new Timer(100, new ActionListener(){
public void actionPerformed(ActionEvent e) {
p.processRow();
table.scrollRectToVisible(table.getCellRect(table.getRowCount() - 1, 0, true));
}
});
timer.start();
}
};
p.execute();
}
});
}
}
class GUI extends JFrame {
private static final long serialVersionUID = 1L;
public GUI() {
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 350, 400);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(10, 10, 10, 10));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
}
}
interface Callback {
void execute();
}
abstract class Processor implements Callback {
private final String[] cols = {"COL", "COL", "COL", "COL", "COL"};
private DefaultTableModel tableModel;
int numRows;
int numCols;
int a, b, c, d, e;
Processor() {
a = 1; b = 2; c = 3; d = 4; e = 4;
numRows = 1000;
tableModel = new DefaultTableModel(cols, numCols);
}
public DefaultTableModel getTableModel() {
return tableModel;
}
public void processRow() {
tableModel.addRow(new Object[]{a, b, c, d, e});
a++; b++; c++; d++; e++;
}
}
答案 1 :(得分:1)
正如kleopatra和peeskillet指出的那样,我最初的例子遭遇了一个愚蠢的错误。值得注意的是,peeskillet和我正在采用不同的方法。在我的示例中,列旨在表示可能花费未知时间且实际上可能失败的连接尝试(或多或少)(在这种情况下,只有在这种情况下,下一列才会起作用等等) )。因此,对我来说,一次添加行是没有意义的(这可能是因为我的例子对peeskillet来说看起来很奇怪)。我已经使用SwingWorker解决了这个任务。正如kleopatra所指出的,还有另一个错误,现在已经修复了。这是我的代码:
package SwingWorkerExampleCopy;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import java.awt.BorderLayout;
public class SwingWorkerExampleCopy {
public static void main(String[] args) {
// Show GUI
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
GUI gui = new GUI();
DefaultTableModel tableModel = new DefaultTableModel();
// Use a SwingWorker
Worker worker = new Worker(tableModel);
worker.execute();
JTable table = new JTable(tableModel);
table.setEnabled(false);
// table.setTableHeader(null);
JScrollPane scrollPane = new JScrollPane(table);
gui.getContentPane()
.add(scrollPane, BorderLayout.CENTER);
}
});
}
}
class GUI extends JFrame {
private static final long serialVersionUID = 1L;
public GUI() {
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 350, 400);
setLocationRelativeTo(null);
setVisible(true);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(10, 10, 10, 10));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
}
}
class Worker extends SwingWorker<DefaultTableModel, Object[]> {
private final static int numRows = 10;
private final static int numCols = 10;
private DefaultTableModel model;
Worker(DefaultTableModel model) {
this.model = model;
model.setColumnCount(numCols);
}
@Override
protected DefaultTableModel doInBackground() throws Exception {
// Add row
for (int row = 0; row < numRows; row++) {
// Build columns
for (int col = 0; col < numCols; col++) {
if (col == 0) {
publish(new Object[] { new String("Row " + row), row,
col });
} else {
// Simulate a slow source
Thread
.sleep(new Random().nextInt((250 - 50) + 1) + 50);
Boolean isSuccessful = false;
// Simulate a return value
if (new Random().nextBoolean()) {
isSuccessful = true;
}
publish(new Object[] {
new String((isSuccessful == true ? "x" : "o")), row,
col });
if (isSuccessful == true) {
break;
}
}
}
}
return model;
}
@Override
protected void process(List<Object[]> chunks) {
for (Object[] chunk : chunks) {
// chunk[0]: cell value
// chunk[1]: number
// chunk[2]: column
if ((int) chunk[2] == 0) {
Object[] row = new Object[numCols];
row[0] = (Object) chunk[0];
model.addRow(row);
} else {
model.setValueAt((Object) chunk[0], (int) chunk[1],
(int) chunk[2]);
}
}
}
}
答案 2 :(得分:0)
因为在您的代码运行时,没有其他事件(例如重绘事件)可以执行 - 您将阻止事件线程,直到您完成。
您可以直接调用重绘,但在代码运行时,UI仍然无法响应输入。您最好在单独的工作线程中运行循环,并在需要时使用invokeLater或invokeAndWait来执行UI的更新。