java - programacion - JProgressBar en JTable no está actualizando
manual de programacion android pdf (3)
No estoy seguro acerca de Scala, pero en Swing el componente devuelto por el TableRenderer
solo se usa para crear un ''sello''. Por lo tanto, el componente real no está contenido en la JTable
, solo un sello. Lo que significa que si actualiza el componente posteriormente, esto no se refleja en `JTable.
La principal ventaja es que puede reutilizar su componente en el renderizador. Por ejemplo, para representar String
, solo necesitaría una instancia de JLabel
en la que actualice el texto y permita que el procesador lo devuelva.
La sección de renderizadores en el tutorial de la tabla Swing explica esto con más detalle
¿Por qué no se actualizan las barras de progreso en el siguiente código y cómo las obtendré?
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)
}
}
Parece que he resuelto el problema anulando los métodos isDisplayable y repaint de 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)
}
}
Como señala @Robin, el renderizador solo se evoca cuando se actualiza el modelo. Necesita cambiar periódicamente el valor en la (s) fila (s) deseada (s). Este ejemplo usa 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);
}
}
}
Es posible que también desee implementar setValueAt()
, ya que la implementación de AbstractTableModel
está vacía:
@Override
public void setValueAt(Object aValue, int row, int col) {
if (col == 1) {
// update your internal model and notify listeners
this.fireTableCellUpdated(row, col);
}
}
Adición: como referencia, aquí hay una implementación de Java correspondiente para complementar Scala.
Código:
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://.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();
}
});
}
}