使用大量行填充JTable [英] Populate JTable with large number of rows

查看:107
本文介绍了使用大量行填充JTable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在运行时期间用很多行填充JTable(比方说10000)。但我所有的尝试都非常糟糕且效率低下。

I would like to populate a JTable during runtime with many rows (lets say 10000). But all my attempts are very poor and inefficient.

起点是 addData 方法,该方法获取表示行的对象列表。我试图通过SwingWorker填充表格,但这仅适用于我的小数据。

Starting point is the addData method which gets a List of Objects representing a row. I tried to fill the table via a SwingWorker but this only works for small data for me.

另一种尝试是直接设置数据而不使用任何类型的线程,但这也非常慢,至少UI没有被阻止,就像它的情况一样SwingWorker。

Another attempt was setting the data directly without using any kind of thread, but this is also very slow, at least the UI isn't blocked like its the case with the SwingWorker.

那么你如何做到这一点呢?该表应该逐行或逐行填充,但不能全部填充,垂直滚动条应该可以同时滚动。

So how do you do this is general? The table should be filled row by row or chunkwise but not all by one and the vertical scrollbar should be scrollable meanwhile.

我的TableModel:

My TableModel:

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实施:

SwingWorker implementation:

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:

Add Objects to 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));
    //}
}


推荐答案

所以,从评论中发现了很多东西......

So, a number of things have being identified from the comments...


  • 你需要正确触发插入行的方法,仅表示那些已添加的行以及它们已被更新的位置。这非常重要,因为该表已经针对速度进行了优化

  • 您应该为表模型提供批量添加方法,这样您就可以在一个步骤或更少的步骤中更轻松地添加多个行尽可能

  • 你应该让 SwingWorker 定期睡觉或屈服,以便有时间公布结果。

  • You need to correctly fire the row inserted method, indicating only those rows that have being added and where they have being updated. This very important, as the the table has being optimised for speed
  • You should provide batch add method for your table model, allowing you to more easily add multiple rows in a single or as few steps as possible
  • You should have the SwingWorker periodically sleep or yield, to allow it time to publish the results.

因此,在这个例子中,我添加了1,000,000行。在我的测试中,它花了不到1秒......

So, in this example, I'm adding 1, 000, 000 rows. In my test it took slightly under 1 second...

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);
        }
    }
}

这篇关于使用大量行填充JTable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆