简体   繁体   English

JTable中的JProgressBar无法更新

[英]JProgressBar in JTable not updating

Why don't the progress bars in the following code update and how would I get them to? 为什么下面的代码中的进度条不更新,我该如何更新它们?

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)
  }
}

As @Robin notes, the renderer in only evoked when the model is updated. 正如@Robin所指出的,渲染器仅在模型更新时才被唤起。 You need to periodically change the value in the desired row(s). 您需要定期更改所需行中的值。 This example uses javax.swing.Timer . 本示例使用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);
        }
    }
}

You may also want to implement setValueAt() , as the AbstractTableModel implementation is empty: 您可能还想实现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);
    }
}

Addendum: For reference, here's a corresponding Java implementation to complement the Scala. 附录:作为参考,下面是一个与Scala互补的相应Java实现。

在此处输入图片说明

Code: 码:

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();
            }
        });
    }
}

Not sure about Scala, but in Swing the component returned by the TableRenderer is just used to create a 'stamp'. 不确定Scala,但在Swing中, TableRenderer返回的组件仅用于创建“邮票”。 So the actual component is not contained in the JTable , only a stamp of it. 因此,实际组件不包含在JTable ,仅包含它的一个标记。 Meaning that if you update the component afterwards, this is not reflected in the `JTable. 意味着如果以后更新组件,则这不会反映在`JTable中。

The main benefit is that you can reuse your component in the renderer. 主要好处是您可以在渲染器中重用组件。 Eg to render String s, you would only need one JLabel instance on which you update the text and let the renderer return it. 例如,渲染String ,您只需要一个JLabel实例即可在其上更新文本并让渲染器返回它。

The renderers section in the Swing table tutorial explains this in more detail Swing表教程中renderers部分对此进行了更详细的说明。

I seem to have solved the problem by overriding the isDisplayable and repaint methods of JProgressBar. 我似乎已经通过重写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)
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM