Dynamically adding rows to JTable - Why do they appear at once?

后端 未结 3 406
隐瞒了意图╮
隐瞒了意图╮ 2020-12-21 22:55

In the example, I\'m seeking to add a table to my GUI and then dynamically add rows to it (to show the progress). What I don\'t understand is why all the rows are appearing

相关标签:
3条回答
  • 2020-12-21 23:38

    As pointed out by kleopatra and peeskillet, my initial example suffered from a stupid mistake. It's worth noting that peeskillet and I were following different approaches, though. In my example, the columns meant to represent connection attempts (more or less) that can take an unknown amount of time and that can actually fail (in that case, and only in that case, the next column would come into play and so on). Therefore, it wouldn't have made sense for me to add the rows at once (which was probably what made my example look weird to peeskillet). I've solved the task using a SwingWorker. As pointed out by kleopatra, there was a another mistake, which is now fixed. Here's my code:

    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]);
          }
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-21 23:45

    Because while your code is running, no other events (such as repaint events) can execute - you're blocking the event thread until you're done.

    You may be able to call repaint directly, but the UI will still be unresponsive to input while your code is running. You'd be better off running the loop in a separate worker thread, and using invokeLater or invokeAndWait to perform the updates to the UI when needed.

    0 讨论(0)
  • 2020-12-21 23:55

    Reiterating Kleopatra : Don't Sleep the EDT

    You can instead use a javax.swing.Timer as seen in this answer

    enter image description here


    EDIT

    I didn't want to mess with your code too much (just because it looks weird to me) but I changed it somewhat to add the 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++;
        }
    }
    
    0 讨论(0)
提交回复
热议问题