2011-11-11 24 views
5

我張貼的答案,Java TableModelListener and Live Feed Listener?,但我通過獲得評論 - 克列奧帕特拉爲什麼永遠不變的通知在接收改變事件

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. 

能有人爲解釋我什麼的更改通知中接收更改事件,這可能是發生了,她真正的意思,因爲我什麼都試過了,我知道,我只收到非常快循環的RepaintManager例外,

我再也找不到一個例外,

  • 我multiplaeyd即到50×1000矩陣,

  • 與prepareRenderer(改變顏色爲獨到之處/負值)

  • 與刷新率175毫秒

代碼證明改變通知和另外兩個(也許是正確的)方式如何做

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

爲什麼你的MyTask.done()實現使用invokeLater?如果你需要在美國東部時間做一些事情()是你的機會。 – Ryan

+0

@Ryan代碼用於測試目的,使用invokeLater ---> a)通知EDT,b)將所需的代碼移動到EDT的末尾(多次提及JTextComponents及其XxxListeners,Focus等),確保實現在API中完成,處理,發佈,setProcess相當保證所有事件都在EDT上完成,Sry我討厭SwingWokrer – mKorbel

+0

一個SwingWorker.done()方法,只有invokeLater纔會有異樣的反模式。我明白「B/C測試」。我仍然不相信a)或b)在這個例子中完成任何事情。如果你想了解一些不必要的線程化怪癖並沒有幫助。 – Ryan

回答

5

我認爲她意味着如果你沒有真正考慮你的代碼,那麼你可以引入一個無限循環。

大多數人在創建表格時可能會使第1,2列可編輯,並使第3列不可編輯,因爲第3列僅僅是兩列之間的差異。

所以,當他們寫,他們將檢查更新事件卻忘了檢查,看哪一列被更新,因爲他們認爲該表將不會允許他們更新列3

他們忘記了當TableModelListener TableModelListener更新第3列,則會生成另一個UPDATE事件,從而導致無限循環。當然,正如你的例子一樣,正確的編碼將防止循環。

一般來說,它不應該引起異常。

第二點是關於業務規則。業務規則應該在一個地方定義,在這個例子中就是模型。數據本身和數據的更新應該在一個地方完成。

+1

感謝您澄清,+1 – mKorbel

相關問題