为什么以下代码中的进度条没有更新,如何将它们更新?
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)
}
}
答案 0 :(得分: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。
代码:
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 :(得分:2)
不确定Scala,但在Swing中,TableRenderer
返回的组件仅用于创建“标记”。因此实际组件不包含在JTable
中,只包含它的标记。这意味着如果之后更新组件,则不会反映在`JTable。
主要好处是您可以在渲染器中重用您的组件。例如。要呈现String
,您只需要一个JLabel
实例来更新文本并让渲染器返回它。
答案 2 :(得分:1)
我似乎通过覆盖JProgressBar的isDisplayable和重绘方法解决了这个问题。
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)
}
}