2013-07-01 4 views
0

Я хотел бы заполнить JTable во время выполнения множеством строк (скажем, 10000). Но все мои попытки очень плохи и неэффективны.Заполнение JTable с большим количеством строк

Отправной точкой является метод addData, который получает список объектов, представляющих строку. Я попытался заполнить таблицу через SwingWorker, но это работает только для небольших данных для меня.

Другая попытка заключается в установке данных непосредственно без использования каких-либо потоков, но это также очень медленно, по крайней мере, пользовательский интерфейс не блокируется, как в случае с SwingWorker.

Итак, как вы это делаете, общий? Таблица должна быть заполнена по строкам или по очереди, но не по одному, а вертикальная полоса прокрутки должна прокручиваться между тем.

Мои 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:

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)); 
    //} 
} 
+3

Лучший способ, ИМХО, не делать этого. Никто не может ничего сделать с этим количеством строк. Добавьте форму поиска. Добавить разбивку на страницы. –

+1

Проблема с вашим 'SwingWorker' заключается в том, что он забивает. Это означает, что он никогда не получает время «публиковать» результаты до тех пор, пока (или близко к концу) основного цикла. Приходят две вещи. 1- Добавьте небольшую задержку в основной цикл (5-10 миллисекунд), который позволит «SwingWorker» и возможность обрабатывать все опубликованные результаты. 2. Добавьте пакетную таблицу добавления к вам, которая позволит вам добавить несколько строк в один вызов метода – MadProgrammer

+1

И почему вы запускаете событие, указывающее, что все строки были вставлены в ваш метод 'addRow'? – Robin

ответ

10

Таким образом, целый ряд вещей, которые выявляются из комментариев .. .

  • Необходимо правильно запустить метод вставленной строки, указав только те строки, которые были добавлены и где они были обновлены. Это очень важно, поскольку таблица оптимизирована для скорости
  • Вам следует предоставить метод пакетной загрузки для вашей модели таблицы, что позволит вам легко добавить несколько строк на одном или нескольких шагах, насколько это возможно
  • Вы должны иметь SwingWorker периодически спать или уступать, чтобы позволить ему опубликовать результаты.

Итак, в этом примере я добавляю 1 000 000 строк. В моем тесте потребовалось немного меньше 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); 
     } 
    } 
} 
+1

См. Также эту [вариант] (http://stackoverflow.com/a/17384208/230513). – trashgod

Смежные вопросы