Java 用大量行填充JTable
我想在运行时用许多行(比如10000行)填充JTable。但我所有的尝试都很糟糕,效率也很低 起点是addData方法,它获取表示行的对象列表。我试图通过SwingWorker填写表格,但这对我来说只适用于小数据 另一个尝试是直接设置数据而不使用任何类型的线程,但是这也非常慢,至少UI没有像SwingWorker那样被阻塞 那么你是如何做到这一点的呢?表格应逐行或分块填写,但不能全部填写,同时垂直滚动条应可滚动 我的桌面模型:Java 用大量行填充JTable,java,swing,jtable,swingworker,Java,Swing,Jtable,Swingworker,我想在运行时用许多行(比如10000行)填充JTable。但我所有的尝试都很糟糕,效率也很低 起点是addData方法,它获取表示行的对象列表。我试图通过SwingWorker填写表格,但这对我来说只适用于小数据 另一个尝试是直接设置数据而不使用任何类型的线程,但是这也非常慢,至少UI没有像SwingWorker那样被阻塞 那么你是如何做到这一点的呢?表格应逐行或分块填写,但不能全部填写,同时垂直滚动条应可滚动 我的桌面模型: public class MyTableModel extends
public class MyTableModel extends AbstractTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
String[] columnNames;
public Map<Long, ErrorMessage> data = new LinkedHashMap<Long, ErrorMessage>();
public MyTableModel(String[] header) {
columnNames = header;
}
public String getColumnName(int col) {
return columnNames[col].toString();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public Object getValueAt(int row, int col) {
.
.
return value;
}
public void addRow(long id, MyDataObject o) {
data.put(id, m);
fireTableRowsInserted(0,nqm_messages.size()-1);
}
}
SwingWorker实现:
class TableSwingWorker extends SwingWorker<MyTableModel, MyDataObject> {
private final MyTableModel tableModel;
List<MyDataObject> messages;
public TableSwingWorker(MyTableModel tableModel, List<MyDataObject> dataList) {
this.tableModel = tableModel;
this.messages = new LinkedList<MyDataObject>(mm);
}
@Override
protected MyTableModel doInBackground() throws Exception {
for(MyDataObject s : messages) {
publish(s);
}
return tableModel;
}
@Override
protected void process(List<MyDataObject> chunks) {
for(MyDataObject row : chunks){
Long l = Long.parseLong(row.getId());
tableModel.addRow(l, row);
}
}
}
将对象添加到JTable:
public void addData(List<MyDataObject> o) {
MyTableModel m = (MyTableModel)table.getModel();
(new TableSwingWorker(m,o)).execute();
//for(int i=0; i < mm.size();i++) {
// long l = Long.parseLong(mm.get(i).getId());
// m.addRow(l, mm.get(i));
//}
}
因此,从评论中可以看出一些事情 您需要正确地触发row inserted方法,仅指示已添加的行和更新的行。这一点非常重要,因为工作台已针对速度进行了优化 您应该为您的表模型提供批处理添加方法,允许您在一个或尽可能少的步骤中更轻松地添加多行 您应该让SwingWorker定期睡眠或屈服,以便让它有时间发布结果。 在这个例子中,我添加了1000000行。在我的测试中,花了不到1秒的时间
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
public class TestTableLoad01 {
public static void main(String[] args) {
new TestTableLoad01();
}
public TestTableLoad01() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
MyTableModel model = new MyTableModel();
JTable table = new JTable(model);
table.setDefaultRenderer(Date.class, new TimeCellRenderer());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
TableSwingWorker worker = new TableSwingWorker(model);
worker.execute();
}
});
}
public class TimeCellRenderer extends DefaultTableCellRenderer {
private DateFormat df;
public TimeCellRenderer() {
df = new SimpleDateFormat("HH:mm:ss");
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof Date) {
value = df.format(value);
}
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return this;
}
}
public class MyTableModel extends AbstractTableModel {
private String[] columnNames = new String[]{"Date", "Row"};
private List<RowData> data;
public MyTableModel() {
data = new ArrayList<>(25);
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 0 ? Date.class : Integer.class;
}
@Override
public String getColumnName(int col) {
return columnNames[col];
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public Object getValueAt(int row, int col) {
RowData value = data.get(row);
return col == 0 ? value.getDate() : value.getRow();
}
public void addRow(RowData value) {
int rowCount = getRowCount();
data.add(value);
fireTableRowsInserted(rowCount, rowCount);
}
public void addRows(RowData... value) {
addRows(Arrays.asList(value));
}
private void addRows(List<RowData> rows) {
int rowCount = getRowCount();
data.addAll(rows);
fireTableRowsInserted(rowCount, getRowCount() - 1);
}
}
public class RowData {
private Date date;
private int row;
public RowData(int row) {
this.date = new Date();
this.row = row;
}
public Date getDate() {
return date;
}
public int getRow() {
return row;
}
}
public class TableSwingWorker extends SwingWorker<MyTableModel, RowData> {
private final MyTableModel tableModel;
public TableSwingWorker(MyTableModel tableModel) {
this.tableModel = tableModel;
}
@Override
protected MyTableModel doInBackground() throws Exception {
// This is a deliberate pause to allow the UI time to render
Thread.sleep(2000);
System.out.println("Start polulating");
for (int index = 0; index < 1000000; index++) {
RowData data = new RowData(index);
publish(data);
Thread.yield();
}
return tableModel;
}
@Override
protected void process(List<RowData> chunks) {
System.out.println("Adding " + chunks.size() + " rows");
tableModel.addRows(chunks);
}
}
}
因此,从评论中可以看出一些事情 您需要正确地触发row inserted方法,仅指示已添加的行和更新的行。这一点非常重要,因为工作台已针对速度进行了优化 您应该为您的表模型提供批处理添加方法,允许您在一个或尽可能少的步骤中更轻松地添加多行 您应该让SwingWorker定期睡眠或屈服,以便让它有时间发布结果。 在这个例子中,我添加了1000000行。在我的测试中,花了不到1秒的时间
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
public class TestTableLoad01 {
public static void main(String[] args) {
new TestTableLoad01();
}
public TestTableLoad01() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
MyTableModel model = new MyTableModel();
JTable table = new JTable(model);
table.setDefaultRenderer(Date.class, new TimeCellRenderer());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
TableSwingWorker worker = new TableSwingWorker(model);
worker.execute();
}
});
}
public class TimeCellRenderer extends DefaultTableCellRenderer {
private DateFormat df;
public TimeCellRenderer() {
df = new SimpleDateFormat("HH:mm:ss");
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof Date) {
value = df.format(value);
}
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return this;
}
}
public class MyTableModel extends AbstractTableModel {
private String[] columnNames = new String[]{"Date", "Row"};
private List<RowData> data;
public MyTableModel() {
data = new ArrayList<>(25);
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 0 ? Date.class : Integer.class;
}
@Override
public String getColumnName(int col) {
return columnNames[col];
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public Object getValueAt(int row, int col) {
RowData value = data.get(row);
return col == 0 ? value.getDate() : value.getRow();
}
public void addRow(RowData value) {
int rowCount = getRowCount();
data.add(value);
fireTableRowsInserted(rowCount, rowCount);
}
public void addRows(RowData... value) {
addRows(Arrays.asList(value));
}
private void addRows(List<RowData> rows) {
int rowCount = getRowCount();
data.addAll(rows);
fireTableRowsInserted(rowCount, getRowCount() - 1);
}
}
public class RowData {
private Date date;
private int row;
public RowData(int row) {
this.date = new Date();
this.row = row;
}
public Date getDate() {
return date;
}
public int getRow() {
return row;
}
}
public class TableSwingWorker extends SwingWorker<MyTableModel, RowData> {
private final MyTableModel tableModel;
public TableSwingWorker(MyTableModel tableModel) {
this.tableModel = tableModel;
}
@Override
protected MyTableModel doInBackground() throws Exception {
// This is a deliberate pause to allow the UI time to render
Thread.sleep(2000);
System.out.println("Start polulating");
for (int index = 0; index < 1000000; index++) {
RowData data = new RowData(index);
publish(data);
Thread.yield();
}
return tableModel;
}
@Override
protected void process(List<RowData> chunks) {
System.out.println("Adding " + chunks.size() + " rows");
tableModel.addRows(chunks);
}
}
}
最好的办法是不要这样做。没有人能用这么多行做任何事情。添加搜索表单。添加分页。你的SwingWorker的问题是它阻塞了。这意味着直到主循环结束或接近结束时,它才有时间发布结果。我们发现了两件事。1-在主循环中添加一个5-10毫秒的小延迟,这将允许SwingWorker和opportunity处理所有发布的结果2-添加一个batch Add to you table模型,这将允许您在单个方法调用中添加多行,为什么要触发一个事件,指示所有行都已插入addRow方法中最好的办法是,不要这样做。没有人能用这么多行做任何事情。添加搜索表单。添加分页。你的SwingWorker的问题是它阻塞了。这意味着直到主循环结束或接近结束时,它才有时间发布结果。我们发现了两件事。1-在主循环中添加一个5-10毫秒的小延迟,这将允许SwingWorker和opportunity处理所有发布的结果2-添加一个batch Add to you table模型,这将允许您在单个方法调用中添加多行,为什么要触发一个事件,指示所有行都已插入addRow方法?