2011-11-11 5 views
5

he publicado una respuesta a Java TableModelListener and Live Feed Listener?, pero me da un comentario por - kleopatraPor qué no cambiar el notificador en recibir un evento de cambio

nonono - you never change the notifier in receiving a change event. 
As to probable effects, think: nasty loops. As to code sanity, think: 
indecent intimacy. It's the task of the model itself to internally 
update related values if necessary. 

puede somone me explique lo que a cambiar el notificador en recibir un evento de cambio, lo que podría ser suceda, lo que realmente significa, porque como ya he intentado todo lo que sé que sólo recibir excepciones RepaintManager de bucle muy rápidamente,

nunca consigo otra excepción, donde

  • I multiplaeyd que a la matriz de 50 x 1000,

  • con prepareRenderer (cambio de color para el valor possitive/negativo)

  • con frecuencia de actualización de 175 milisegundos

código demuestra el cambio de la notificador y dos de otra manera (tal vez correcta) cómo hacerlo

import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.util.Random; 
import java.util.concurrent.*; 
import javax.swing.*; 
import javax.swing.event.*; 
import javax.swing.table.DefaultTableModel; 

public class ChangeNotifiersOnEvent extends JFrame implements Runnable { 

    private static final long serialVersionUID = 1L; 
    private boolean runProcess = true; 
    private Random random = new Random(); 
    private javax.swing.Timer timerRun; 
    private Executor executor = Executors.newCachedThreadPool(); 
    private String[] columnNames = {"Source", "Hit", "Last", "Ur_Diff"}; 
    private JTable table; 
    private Object[][] data = {{"Swing Timer", 2.99, 5, 1.01}, 
     {"Swing Worker", 7.10, 5, 1.010}, {"TableModelListener", 25.05, 5, 1.01}}; 
    private DefaultTableModel model = new DefaultTableModel(data, columnNames); 

    public ChangeNotifiersOnEvent() { 
     table = new JTable(model) { 

      private static final long serialVersionUID = 1L; 

      @Override 
      public Class getColumnClass(int column) { 
       return getValueAt(0, column).getClass(); 
      } 
     }; 
     model.addTableModelListener(new TableModelListener() { 

      @Override 
      public void tableChanged(TableModelEvent tme) { 
       if (tme.getType() == TableModelEvent.UPDATE) { 
        if (tme.getColumn() == 1 && tme.getLastRow() == 2) { 
         double dbl = ((Double) table.getModel().getValueAt(2, 1)) 
           - ((Integer) table.getModel().getValueAt(2, 2)); 
         table.getModel().setValueAt(dbl, 2, 3); 
        } else if (tme.getColumn() == 1 && tme.getLastRow() == 0) { 
         prepareUpdateTableCell(); 
        } else if (tme.getColumn() == 1 && tme.getLastRow() == 1) { 
         executor.execute(new MyTask(MyTask.UPDATE_TABLE_COLUMN)); 
        } 
       } 
      } 
     }); 
     table.setRowHeight(30); 
     table.setFont(new Font("Serif", Font.BOLD, 20)); 
     table.getColumnModel().getColumn(0).setPreferredWidth(180); 
     table.setPreferredScrollableViewportSize(table.getPreferredSize()); 
     JScrollPane scrollPane = new JScrollPane(table); 
     add(scrollPane, BorderLayout.CENTER); 
     new Thread(this).start(); 
    } 

    private void prepareUpdateTableCell() { 
     timerRun = new javax.swing.Timer(10, UpdateTableCell()); 
     timerRun.setRepeats(false); 
     timerRun.start(); 
    } 

    private Action UpdateTableCell() { 
     return new AbstractAction("Update Table Cell") { 

      private static final long serialVersionUID = 1L; 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       double dbl = ((Double) table.getModel().getValueAt(0, 1)) 
         - ((Integer) table.getModel().getValueAt(0, 2)); 
       table.getModel().setValueAt(dbl, 0, 3); 
      } 
     }; 
    } 

    @Override 
    public void run() { 
     while (runProcess) { 
      try { 
       Thread.sleep(250); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      changeTableValues(); 
     } 
    } 

    private void changeTableValues() { 
     Runnable doRun = new Runnable() { 

      @Override 
      public void run() { 
       table.getModel().setValueAt(random.nextInt(128) + random.nextDouble(), 0, 1); 
       table.getModel().setValueAt(random.nextInt(256) + random.nextDouble(), 1, 1); 
       table.getModel().setValueAt(random.nextInt(512) + random.nextDouble(), 2, 1); 

       table.getModel().setValueAt(random.nextInt(128), 0, 2); 
       table.getModel().setValueAt(random.nextInt(128), 1, 2); 
       table.getModel().setValueAt(random.nextInt(128), 2, 2); 
      } 
     }; 
     SwingUtilities.invokeLater(doRun); 
    } 

    private class MyTask extends SwingWorker<Void, Integer> { 

     private static final String UPDATE_TABLE_COLUMN = "update"; 
     private String namePr; 
     private double dbl; 

     MyTask(String str) { 
      this.namePr = str; 
     } 

     @Override 
     protected Void doInBackground() throws Exception { 
      dbl = ((Double) table.getModel().getValueAt(1, 1)) 
        - ((Integer) table.getModel().getValueAt(1, 2)); 
      return null; 
     } 

     @Override 
     protected void done() { 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        table.getModel().setValueAt(dbl, 1, 3); 
       } 
      }); 
     } 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       ChangeNotifiersOnEvent frame = new ChangeNotifiersOnEvent(); 
       frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
       frame.setLocation(150, 150); 
       frame.pack(); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
+0

¿Por qué la implementación de MyTask.done() usa invokeLater? Si necesita hacer algo en el EDT hecho() es su oportunidad. – Ryan

+0

@El código de Ryan es para propósitos de prueba, uso de invokeLater ---> a) notificar a EDT, b) mover el código deseado hasta el final de EDT (muchas veces mencionado para JTextComponents y sus XxxListeners, Focus etc ...), implemententations seguros en API para done, process, publish, setProcess garantizo que todos los eventos se realizan en EDT, sry I'm hate SwingWokrer – mKorbel

+0

Un método SwingWorker.done() que solo hace que invokeLater huela como un antipatrón. Entiendo "prueba de b/c". Todavía no creo a) ob) logre algo en este ejemplo. Si intentas entender algo que tiene cabos innecesarios para enhebrar, no ayuda. – Ryan

Respuesta

5

Creo ella quiere decir que si realmente no piensas en tu código, entonces puedes introducir un ciclo infinito.

La mayoría de las personas cuando crean la tabla probablemente edita las columnas 1, 2 y hacen que la columna 3 no sea editable, ya que la columna 3 es solo la diferencia entre las dos columnas.

Así que cuando escriben la TableModelListener le verificarán el evento de actualización, pero se olvide de comprobar para ver qué columna se actualiza porque piensan que la mesa no les permitirá actualizar la columna 3.

Se olvidan que cuando el TableModelListener actualiza la columna 3, se generará otro evento UPDATE, causando el bucle infinito. Por supuesto, una codificación adecuada, como en su ejemplo, evitará el ciclo.

En general, no debe causar una excepción.

El segundo punto es acerca de las reglas comerciales. Las reglas comerciales deben definirse en un solo lugar, en este caso el modelo. Los datos en sí y la actualización de los datos se deben hacer en un solo lugar.

+1

gracias por aclarar, +1 – mKorbel

Cuestiones relacionadas