java swing concurrency jprogressbar tablecellrenderer

java - JProgressBar setValue no funciona, intentado con SwingUtilities también



concurrency tablecellrenderer (3)

Implementé JProgressBar en una JTable. Usé el procesador para ProgressBar NOT EDITOR.

Ahora traté de implementar un valor establecido en ProgressBar, pero debido a EDT no funcionaba, utilicé SwingUtilties pero no funcionó tan bien.

COMPORTAMIENTO ESPERADO: JProgressBar debe establecer el valor en 80, actualmente muestra solo 0%

public class SkillSetTableProgressBarRenderer extends JProgressBar implements TableCellRenderer { public SkillSetTableProgressBarRenderer() { super(0, 100); super.setPreferredSize(new Dimension(100, 80)); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { final JProgressBar bar = (JProgressBar) value; if (bar.getString().equals("JAVA") || bar.getString().equals("SWING")) super.setString("Mellow"); else super.setString("GOOD"); setOpaque(true); table.setOpaque(true); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { System.err.println("MAIN ANDER"); setValue(80); bar.setValue(80); } }); super.setStringPainted(true); super.setIndeterminate(true); super.setPreferredSize(new Dimension(140, 16)); if (isSelected) { super.setBackground(table.getSelectionBackground()); super.setForeground(table.getSelectionForeground()); // this.setBackground(table.getSelectionBackground()); } else { super.setForeground(table.getForeground()); super.setBackground(Color.WHITE); } return this; } }


1) incluso es posible, no crea JComponents dentro de TableCellRenderer , ni re_create Object, Renderer es solo para formatear el contenido de la celda

2) utilice SwingWorker para moverse con progreso en JProgressBar (si tiene razones realmente importantes, utilice Runnable#Tread )

ejemplo sobre Runnable#Tread

import java.awt.Component; import java.util.Random; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; public class TableWithProgressBars { public static class ProgressRenderer extends JProgressBar implements TableCellRenderer { private static final long serialVersionUID = 1L; public ProgressRenderer(int min, int max) { super(min, max); this.setStringPainted(true); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { this.setValue((Integer) value); return this; } } private static final int maximum = 100; public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new TableWithProgressBars().createGUI(); } }); } public void createGUI() { final JFrame frame = new JFrame("Progressing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Integer[] oneRow = {0, 0, 0, 0}; String[] headers = {"One", "Two", "Three", "Four"}; Integer[][] data = {oneRow, oneRow, oneRow, oneRow, oneRow,}; final DefaultTableModel model = new DefaultTableModel(data, headers); final JTable table = new JTable(model); table.setDefaultRenderer(Object.class, new ProgressRenderer(0, maximum)); table.setPreferredScrollableViewportSize(table.getPreferredSize()); frame.add(new JScrollPane(table)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); new Thread(new Runnable() { @Override public void run() { Object waiter = new Object(); synchronized (waiter) { int rows = model.getRowCount(); int columns = model.getColumnCount(); Random random = new Random(System.currentTimeMillis()); boolean done = false; while (!done) { int row = random.nextInt(rows); int column = random.nextInt(columns); Integer value = (Integer) model.getValueAt(row, column); value++; if (value <= maximum) { model.setValueAt(value, row, column); try { waiter.wait(15); } catch (InterruptedException e) { e.printStackTrace(); } } done = true; for (row = 0; row < rows; row++) { for (column = 0; column < columns; column++) { if (!model.getValueAt(row, column).equals(maximum)) { done = false; break; } } if (!done) { break; } } } frame.setTitle("All work done"); } } }).start(); } }


Eche un vistazo al tutorial de la tabla Swing: representadores y editores . El renderizador usa el componente para hacer una especie de ''sello''. Cambiar el componente posteriormente no tiene ningún efecto ya que el componente no está realmente contenido en su UI. Esa es una de las razones por las que puede devolver el mismo componente una y otra vez, lo que no sería posible si el componente estuviera realmente contenido en la tabla. Todo esto se explica en el tutorial vinculado.

Para resolver su problema, solo elimine la llamada al método SwingUtilities.invokeLater y devuelva una JProgressBar donde se JProgressBar el progreso correcto.

Y si veo esto correctamente, tiene un JProgressBar contiene una JProgressBar . Espero que haya una buena razón para esto, ya que este es un componente de UI que normalmente no debería incluirse en el modelo. Esto se basa en tu

final JProgressBar bar = (JProgressBar) value;

llamar en el renderizador. Recomiendo encarecidamente echar un vistazo a su TableModel para ver si esto puede evitarse


Parece que estás tratando de usar una ProgressBar como CellRenderer. Una cosa que debes saber es que los CellRenders solo se llaman cuando se está dibujando una celda, y establecer los valores en otros momentos no tiene ningún efecto: esto es porque Swing usa un patrón flyweight para los renderizadores, y por lo tanto reutiliza el renderizador.

Para obtener el efecto que desea, debe

  • notifique a la mesa que la celda debe actualizarse, por ejemplo, actualizando su modelo subyacente (que activará los eventos necesarios), y
  • establezca todos los valores que necesita antes del retorno getTableCellRendererComponent , por lo tanto, elimine el invokeLater (se llama al getter en el EDT, por lo que no necesita preocuparse de enhebrar allí).