Java从另一个线程更新jtable行

时间:2012-08-09 20:29:12

标签: java multithreading swing jtable event-dispatching

我有一个多线程程序,我正在尝试使用JTable来查看每个线程的进度。每个线程都是JTable的一行。我已经发布了一个简化的相关代码,我现在有了。每次按下启动时,都会启动一个新线程并将该行添加到JTable中。但是如何从正在运行的线程更新属于该线程的行的“第2列”?

主要是我拥有的

JTable table = new JTable(new DefaultTableModel(new Object[]{"Thread Name", "Progress"}, 0));

btnBegin.addActionListener(new ActionListener()
{
  public void actionPerformed(ActionEvent arg0)
  {
    Thread newThread = new Thread(new MyThreadClass(country, category));
    newThread.start();
    DefaultTableModel model = (DefaultTableModel) table.getModel();
    model.addRow(new Object[]{"Thread " + threadNumber, "Column 2"});
  }
});

4 个答案:

答案 0 :(得分:3)

如果要在运行时更新列,并且如果知道要更新哪一行,则可以这样使用:

int row; // row number you want to update.
int column = 1; // You want to update the first row.
DefaultTableModel model = (DefaultTableModel)table.getModel();
Object value = "New Value Of This Cell";
model.setValueAt(value, row, column);

您可以将表格以及线程显示的行传递或设置到MyThreadClass,以便它可以自行更新其行。

您可以像MyThreadClass一样编写一个方法:

public void setTableAndRow(int row, JTable table) {
    this.table = table;
    this.row = row;
}

您可以在创建线程时传递这些参数:

btnBegin.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent arg0) {
        DefaultTableModel model = (DefaultTableModel) table.getModel();
        MyThreadClass myThread = new MyThreadClass(country, category);
        Thread newThread = new Thread(myThread);
        /**
         * We know, if there is n rows starting from 0,
         * index of the row that we're adding is n.
         */
        int row = model.getRowCount();
        myThread.setTableAndRow(row, table);
        // Now we add the row before starting the thread, because it
        // will try to reach that row, we don't want any exceptions.
        model.addRow(new Object[]{"Thread " + threadNumber, "Column 2"});
        newThread.start();
    }
});

答案 1 :(得分:3)

如果可以将字段tableModel添加到MyThreadClass(字段+构造函数参数),则可以从此类调用@sedran提到的代码。

示例:

public class T {

static int threadNumber = 0;

public static void main(String[] args) throws Exception {

    final JTable table = new JTable(new DefaultTableModel(new Object[] { "Thread Name", "Progress" }, 0));

    JButton btnBegin = new JButton("Begin");
    btnBegin.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent arg0) {
            DefaultTableModel model = (DefaultTableModel) table.getModel();
            MyThreadClass newThread = new MyThreadClass(model, threadNumber++);
            newThread.start();

            model.addRow(new Object[] { "Thread " + threadNumber, "Column 2" });
        }
    });

    JFrame frame = new JFrame();
    frame.add(btnBegin, BorderLayout.NORTH);
    frame.add(table);
    frame.setSize(400, 400);
    frame.setVisible(true);
}

static class MyThreadClass extends Thread {
    private final DefaultTableModel model;
    private final int threadNumber;

    public MyThreadClass(DefaultTableModel model, int threadNumber) {
        super();
        this.model = model;
        this.threadNumber = threadNumber;
    }

    @Override
    public void run() {
        for (int i = 0; i <= 5; i++) {
            final int index = i;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    model.setValueAt(index * 20, threadNumber, 1);
                }
            });
        }
    }
}

}

请注意,使用SwingUtilities.invokeLater很重要,因为必须在EDT中刷新视图。

答案 2 :(得分:3)

建议:

  • 使用SwingWorker对象创建后台线程。
  • 从SwingWorker获取更新的一种方法是使用其发布/处理方法对。这允许后台线程将数据传递给Swing事件线程上的Swing应用程序。这将允许后台进程将数据“推送”到GUI上。
  • 获取更新的另一种方法是将PropertyChangeListener添加到SwingWorker并使SwingWorker更新绑定属性。两者都可以正常工作。这将允许数据从后台进程“拉”到GUI上。
  • 要更新特定数据行中的数据,您需要以某种方式将模型的一行与您关注的线程相关联。您总是可以使用getValueAt(...)遍历表模型的某个列的单元格,直到找到包含与该线程的数据匹配的数据,可能是监视类的字段。然后,您可以使用JTable的setValueAt(...)
  • 更新该行的不同列所持有的数据

答案 3 :(得分:1)

我认为SwingUtilies.invokeLater()正是您所寻找的,因此您可以访问event dispatch thread