2012-05-07 67 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

不确定斯卡拉,但在Swing由TableRenderer返回的组件只是用于创建“邮票”。所以实际的组件不包含在JTable中,只是它的一个印记。这意味着如果你以后更新了这个组件,这并不反映在JTable中。

主要好处是您可以在渲染器中重用您的组件。例如。要呈现String s,您只需要一个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实现,以补充斯卡拉。

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'关键字就像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(new Runnable(){...})'。 – trashgod

+0

除非我错过了某些东西,否则这似乎是最佳解决方案,因为它消除了需要运行另一个线程的需求。我像这样调用'invokeLater':https://gist.github.com/2658997 –

+0

这种方法的局限性是它不必要地耦合模型和视图。 'Timer'仅用于演示目的;在实践中,新数据的可用性将推动进展状态的改变。链接为+1。 – trashgod