1

我有一个多线程程序,我正在尝试使用 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

4 回答 4

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,因此它可以自行更新其行。

您可以像这样编写一个方法 insie 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();
    }
});
于 2012-08-09T20:57:36.503 回答
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 中刷新视图。

于 2012-08-09T21:22:27.510 回答
3

建议:

  • 使用 SwingWorker 对象来创建您的后台线程。
  • 从 SwingWorker 获取更新的一种方法是使用其发布/处理方法对。这允许后台线程在 Swing 事件线程上将数据传递给 Swing 应用程序。这将允许后台进程将数据“推送”到 GUI 上。
  • 获取更新的另一种方法是将 PropertyChangeListener 添加到 SwingWorker 并让 SwingWorker 更新绑定属性。要么工作正常。这将允许将数据从后台进程“拉”到 GUI 上。
  • 要更新特定数据行中的数据,您需要以某种方式将模型的一行与您所关注的线程连接起来。您总是可以遍历表模型的某一列的单元格,getValueAt(...)直到您找到一个包含与线程匹配的数据的单元格,也许是被监视类的字段。然后您可以使用 JTable 更新由该行的不同列保存的数据setValueAt(...)
于 2012-08-09T22:00:14.600 回答
1

我认为SwingUtilies.invokeLater() 是您正在寻找的,因此您可以访问事件调度线程

于 2012-08-09T21:06:05.007 回答