Вопрос по scala, java, swing, jtable, jprogressbar – JProgressBar в JTable не обновляется

1

Почему нет индикаторов в следующем обновлении кода и как я могу их получить?

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

Ваш Ответ

3   ответа
1

я решил проблему, переопределив isDisplayable и перекрасить методы JProgressBar.

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)
  }
}
Это не должно требоваться, еслиsetValueAt() ЗапускаетfireTableCellUpdated(); Я надеялся увидеть как ты звонишьEventQueue.invokeLater(new Runnable() {…}).
Ограничение этого подхода состоит в том, что он излишне связывает модель и представление.Timer только для демонстрационных целей; на практике наличие новых данных будет влиять на изменение состояния прогресса. +1 за ссылку.
Если я не пропустил что-то, это кажется оптимальным решением, поскольку избавляет от необходимости запускать другой поток. Я звонюinvokeLater как это:gist.github.com/2658997 Simon Morgan
2

TableRenderer просто используется для создания «штампа». Таким образом, фактический компонент не содержится вJTable, только печать этого. Это означает, что если вы обновите компонент впоследствии, это не будет отражено в `JTable.

Основным преимуществом является то, что вы можете повторно использовать свой компонент в рендерере. Например. оказыватьStrings, вам понадобится только одинJLabel экземпляр, в котором вы обновляете текст и позволяете средству визуализации вернуть его.

раздел рендеров в учебнике Swing table объясняет это более подробно

Так есть ли способ обойти проблему? Simon Morgan
+1 за концепцию; это должно работать так же в Scala. Я думаю, что просто нужно что-то для этого, дляexample.
3

средство рендеринга вызывается только при обновлении модели. Вам необходимо периодически менять значение в нужных строках. Этот пример использует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.

enter image description here

Код:

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();
            }
        });
    }
}
getValue должен быть реализацией, а не переопределяться. Я обновил свой пример, код, который я выполнял, имел правильную проверку столбцов (и я даже попробовал это вообще без), а индикаторы выполнения по-прежнему не обновляются. Simon Morgan
Это не имеет никакого значения; индикаторы выполнения все еще заморожены. Simon Morgan
Но нетoverride def getValueAt? Ваш обработчик действия таймера обновляет столбец 0, а вашsetValueAt() стреляет только по колонке 1.
Работает на Java; Вы можете обновить пример Scala в своем вопросе, чтобы показатьsetValueAt() реализация. В чем разница междуoverride def а такжеdef?
Я обновил свой пример.override Ключевое слово как@Override аннотация в Java, за исключением случаев, когда это необходимо, чтобы избежать двусмысленности. Simon Morgan

Похожие вопросы