2012-05-07 1 views
0

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

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

ответ

2

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

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

renderers section in the Swing table tutorial объясняет это более подробно

+0

Итак, есть ли проблема вокруг проблемы? –

+0

+1 для концепции; он должен работать одинаково в Scala. Я думаю, что ему просто нужно что-то водить, для [пример] (http://stackoverflow.com/a/10491290/230513). – trashgod

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.

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

Это не имеет никакого значения; индикаторы выполнения все еще заморожены. –

+0

Работает на Java; вы можете обновить пример Scala в своем вопросе, чтобы показать реализацию 'setValueAt()'. В чем разница между 'override def' и' def'? – trashgod

+0

Я обновил свой пример. Ключевое слово 'override' похоже на аннотацию' @ Override' на Java, за исключением того, что для избежания двусмысленности обязательно. –

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

Это не требуется, если 'setValueAt()' вызывает 'fireTableCellUpdated()'; Я надеялся увидеть, как вы называете EventQueue.invokeLater (новый Runnable() {...}) '. – trashgod

+0

Если мне не хватает чего-то, это кажется оптимальным решением, потому что это устраняет необходимость использования другого потока. Я вызываю 'invokeLater' следующим образом: https://gist.github.com/2658997 –

+0

Ограничение этого подхода состоит в том, что он без необходимости связывает модель и представление. «Таймер» предназначен только для демонстрационных целей; на практике доступность новых данных приведет к изменению состояния прогресса. +1 для ссылки. – trashgod