1

为什么以下代码中的进度条不更新,我将如何让它们更新?

import java.awt.event.{ActionListener, ActionEvent}
import javax.swing.table.{TableCellRenderer, AbstractTableModel}
import javax.swing.{Timer, JTable, JProgressBar, JFrame}

object TestProgressBar {
  val frame = new JFrame()
  val model = new TestModel()
  val table = new JTable(model)

  class TestModel extends AbstractTableModel {
    def getColumnCount = 4

    def getRowCount = 4

    def getValueAt(y: Int, x: Int) = "%d,%d".format(x, y)

    override def setValueAt(value: Any, row: Int, col: Int) {
      if (col == 0) {
        model.fireTableCellUpdated(row, col);
      }
    }
  }

  class TestCellRenderer extends TableCellRenderer with ActionListener {
    val progressBar = new JProgressBar()
    val timer = new Timer(100, this)

    progressBar.setIndeterminate(true)
    timer.start()

    override def getTableCellRendererComponent(tbl: JTable, value: AnyRef,
                                               isSelected: Boolean,
                                               hasFocus: Boolean,
                                               row: Int, column: Int) = {
      progressBar
    }

    override def actionPerformed(e: ActionEvent) {
      val model = table.getModel
      for (row <- 0 to model.getRowCount) {
        model.setValueAt(0, row, 0)
      }
    }
  }

  def main(args: Array[String]) {
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)

    table.getColumnModel.getColumn(0).setCellRenderer(new TestCellRenderer())

    frame.add(table)

    frame.pack()
    frame.setVisible(true)
  }
}
4

3 回答 3

3

正如@Robin 所指出的,只有在模型更新时才会调用渲染器。您需要定期更改所需行中的值。此示例使用javax.swing.Timer.

private class TestCellRenderer implements TableCellRenderer, ActionListener {

    JProgressBar bar = new JProgressBar();

    Timer timer = new Timer(100, this);

    public TestCellRenderer() {
        bar.setIndeterminate(true);
        timer.start();
    }

    @Override
    public Component getTableCellRendererComponent(JTable table,
        Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        return bar;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        TableModel model = table.getModel();
        for (int row = 0; row < model.getRowCount(); row++) {
            table.getModel().setValueAt(0, row, 0);
        }
    }
}

您可能还想实现setValueAt(),因为AbstractTableModel实现是空的:

@Override
public void setValueAt(Object aValue, int row, int col) {
    if (col == 1) {
        // update your internal model and notify listeners
        this.fireTableCellUpdated(row, col);
    }
}

附录:作为参考,这里有一个对应的 Java 实现来补充 Scala。

在此处输入图像描述

代码:

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

/**
* @see http://stackoverflow.com/a/10491290/230513
*/
public class TestProgressBar extends JPanel {

    private JTable table = new JTable(new TestModel());
    public TestProgressBar() {
        table.getColumnModel().getColumn(0).setCellRenderer(new TestCellRenderer());
        table.setPreferredScrollableViewportSize(new Dimension(320, 120));
        this.add(new JScrollPane(table));
    }

    private class TestModel extends AbstractTableModel {

        @Override
        public int getRowCount() {
            return 4;
        }

        @Override
        public int getColumnCount() {
            return 4;
        }

        @Override
        public Object getValueAt(int row, int col) {
            return String.valueOf(row) + ", " + String.valueOf(col);
        }

        @Override
        public void setValueAt(Object aValue, int row, int col) {
            // update internal model and notify listeners
            fireTableCellUpdated(row, col);
        }
    }

    private class TestCellRenderer implements TableCellRenderer, ActionListener {

        JProgressBar bar = new JProgressBar();
        Timer timer = new Timer(100, this);

        public TestCellRenderer() {
            bar.setIndeterminate(true);
            timer.start();
        }

        @Override
        public Component getTableCellRendererComponent(JTable table,
            Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            return bar;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            TableModel model = table.getModel();
            for (int row = 0; row < model.getRowCount(); row++) {
                table.getModel().setValueAt(0, row, 0);
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("TestProgressBar");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestProgressBar().display();
            }
        });
    }
}
于 2012-05-08T01:21:44.243 回答
2

不确定 Scala,但在 Swing 中,返回的组件TableRenderer仅用于创建“印章”。所以实际的组件不包含在 中JTable,只是它的一个标记。这意味着如果您之后更新组件,这不会反映在 `JTable.

主要好处是您可以在渲染器中重用您的组件。例如,要渲染Strings,您只需要一个JLabel实例来更新文本并让渲染器返回它。

Swing table 教程中的渲染器部分对此进行了更详细的解释

于 2012-05-07T18:38:11.410 回答
1

我似乎通过覆盖 JProgressBar 的 isDisplayable 和 repaint 方法解决了这个问题。

import javax.swing.table.{TableCellRenderer, AbstractTableModel}
import javax.swing.{JTable, JProgressBar, JFrame}

object TestProgressBar {
  val frame = new JFrame()
  val model = new TestModel()
  val table = new JTable(model)

  class TestModel extends AbstractTableModel {
    def getColumnCount = 4

    def getRowCount = 4

    def getValueAt(y: Int, x: Int) = "%d,%d".format(x, y)
  }

  class TestCellRenderer extends TableCellRenderer {
    val progressBar = new JProgressBar() {
      override def isDisplayable = true
      override def repaint() { table.repaint() }
    }

    progressBar.setIndeterminate(true)

    override def getTableCellRendererComponent(tbl: JTable, value: AnyRef,
                                               isSelected: Boolean,
                                               hasFocus: Boolean,
                                               row: Int, column: Int) = {
      progressBar
    }
  }

  def main(args: Array[String]) {
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)

    table.getColumnModel.getColumn(0).setCellRenderer(new TestCellRenderer())

    frame.add(table)

    frame.pack()
    frame.setVisible(true)
  }
}
于 2012-05-09T15:48:49.517 回答