2012-05-07 35 views
0

次のコードで進行状況バーが更新されないのはなぜですか?JTableのJProgressBarが更新されない

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のわから

ないが、SwingでTableRendererによって返されたコンポーネントは、単に「スタンプ」を作成するために使用されます。したがって、実際のコンポーネントはJTableには含まれておらず、そのスタンプだけです。後でコンポーネントを更新すると、これは `JTableに反映されません。

主な利点は、コンポーネントをレンダラーで再利用できることです。例えば。 Stringをレンダリングするには、テキストを更新してレンダラーがそれを返すように1つのJLabelインスタンスのみが必要です。

renderers section in the Swing table tutorialは、モデルが更新されたときのみでレンダラが誘発、@Robinノートとして、より詳細に

+0

問題を回避する方法はありますか?コンセプトのための –

+0

+1; Scalaでも同じように動作するはずです。私はそれを駆動するための何かが必要だと思う、[example](http://stackoverflow.com/a/10491290/230513)。 – trashgod

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

AbstractTableModel実装が空であるとしてあなたはまた、setValueAt()を実装することもできます。

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

補遺:参考のため、ここではScalaのを補完するために、対応するJava実装です。

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で動作します。あなたの 'setValueAt()'実装を表示するために質問のScalaサンプルを更新したいかもしれません。 'override def'と' def'の違いは何ですか? – trashgod

+0

私の例を更新しました。 'override'キーワードは、あいまいさを避けることを必須とすることを除いて、Javaの' @ Override'アノテーションと似ています。 –

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

このアプローチの限界は、モデルとビューを不必要に連結することです。 'Timer'はデモンストレーション用です。実際には、新しいデータの可用性は進行状況の変化を促進する。リンクの+1。 – trashgod

関連する問題