2011-11-11 6 views
5

tôi đăng một câu trả lời cho Java TableModelListener and Live Feed Listener?, nhưng tôi nhận được một lời nhận xét bởi - KleopatraTại sao không bao giờ thay đổi notifier trong việc tiếp nhận một sự kiện thay đổi

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. 

thể somone để giải thích cho tôi những gì của Thay đổi notifier trong việc tiếp nhận một sự kiện thay đổi, những gì có thể xảy ra, những gì cô ấy thực sự có nghĩa là, bởi vì như tôi đã cố gắng tất cả mọi thứ mà tôi biết rằng tôi chỉ nhận Exceptions RepaintManager từ rất nhanh chóng vòng lặp,

tôi không bao giờ có được ngoại lệ khác, nơi

  • tôi multiplaeyd đó đến ma trận 50 x 1000,

  • với prepareRenderer (thay đổi màu cho giá trị possitive/âm)

  • với tốc độ làm tươi 175 miliseconds

đang chứng minh thay đổi trình thông báo và hai cách khác (có thể chính xác) cách làm như thế nào

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

Tại sao việc triển khai MyTask.done() của bạn sử dụng invokeLater? Nếu bạn cần phải làm một cái gì đó trên EDT thực hiện() là cơ hội của bạn. – Ryan

+0

@Ryan mã là dành cho mục đích thử nghiệm, sử dụng invokeLater ---> a) thông báo cho EDT, b) chuyển mã mong muốn đến cuối EDT (nhiều lần được đề cập đến cho JTextComponents và XxxListeners, Focus etc ...), chắc chắn triển khai trong API để thực hiện, xử lý, xuất bản, setProcess khá bảo đảm rằng tất cả các sự kiện được thực hiện trên EDT, sry tôi ghét SwingWokrer – mKorbel

+0

Một phương thức SwingWorker.done() mà chỉ thực hiện một invokeLater có mùi giống như anti-pattern. Tôi hiểu "thử nghiệm b/c". Tôi vẫn không tin a) hoặc b) hoàn thành bất cứ điều gì trong ví dụ này. Nếu bạn đang cố gắng để hiểu một cái gì đó có quirks luồng không cần thiết không giúp đỡ. – Ryan

Trả lời

5

Tôi nghĩ rằng cô ấy có nghĩa là nếu bạn không thực sự nghĩ về mã của bạn thì bạn có thể giới thiệu một vòng lặp vô hạn.

Hầu hết mọi người khi họ tạo bảng có thể làm cho cột 1, 2 có thể chỉnh sửa và làm cho cột 3 không thể chỉnh sửa vì cột 3 chỉ là sự khác biệt giữa hai cột.

Vì vậy, khi họ viết TableModelListener họ sẽ kiểm tra sự kiện CẬP NHẬT nhưng quên kiểm tra để xem những cột được cập nhật bởi vì họ nghĩ rằng bảng sẽ không cho phép họ để cập nhật cột 3.

Họ quên rằng khi các cập nhật TableModelListener cột 3 một sự kiện UPDATE sẽ được tạo ra do đó gây ra vòng lặp vô hạn. Tất nhiên, mã hóa thích hợp, như trong ví dụ của bạn, sẽ ngăn chặn vòng lặp.

Nói chung, không nên gây ra ngoại lệ.

Điểm thứ hai là về quy tắc kinh doanh. Các quy tắc kinh doanh nên được xác định ở một nơi, trong trường hợp này là mô hình. Bản thân dữ liệu và việc cập nhật dữ liệu nên được thực hiện ở một nơi duy nhất.

+1

cảm ơn bạn đã làm rõ, +1 – mKorbel