2010-01-29 19 views
8

Trong ứng dụng Swing, tôi có một số bảng phụ, mỗi bảng nghe một JSlider. Bảng cha mẹ xung quanh cũng lắng nghe tất cả các bảng phụ. Để có kết quả nhất quán trong ví dụ bên dưới, tôi phải thêm phụ huynh trước và rồi người nghe địa phương. Điều này có ý nghĩa, theo thứ tự được quy định trong EventListenerList và được giải thích trong số article này. Tôi có thể dựa vào thứ tự đó hay tôi nên sắp xếp để gửi một sự kiện khác?Thứ tự kích hoạt EventListenerList

class SubPanel extends JPanel implements ChangeListener { 

    private final JSlider slider = new JSlider(); 
    private final JLabel label = new JLabel(); 
    private final String name; 
    private float value; 

    public SubPanel(String name, float value, ChangeListener parent) { 
     this.name = name; 
     this.value = value; 
     ... 
     slider.addChangeListener(parent); 
     slider.addChangeListener(this); 
    } 
    ... 
} 

Phụ lục: thảo luận trong EventListenerList dường như là lời khuyên thực hiện chứ không phải đảm bảo. Cách tiếp cận chuỗi được đề xuất bởi pstanton thực thi đúng thứ tự chính xác hơn. Ví dụ: ChangeListener của SubPanel chỉ có thể chuyển tiếp sự kiện cho phụ huynh.

@Override 
    public void stateChanged(ChangeEvent e) { 
     ... 
     parent.stateChanged(e); 
    } 
+0

Câu hỏi và thảo luận thú vị! 1+ –

+0

Ứng dụng ['Converter'] (http://docs.oracle.com/javase/tutorial/uiswing/components/panel.html) bao gồm một ví dụ trong' ConverterRangeModel'. – trashgod

+0

Tôi vừa đăng bài của bạn trong khi 'googling', muốn giải thích chi tiết. xin vui lòng làm cho số lượng bài viết, và chỉ cho tôi ra nếu bất cứ điều gì tôi đã mô tả có thể là sai! – Sage

Trả lời

4

Vì tài liệu dành cho JSlider và JComponent vv không đề cập đến thứ tự thông báo người nghe, tôi sẽ ngần ngại dựa vào nó, ít nhất là không kiểm tra kỹ trên mỗi phiên bản tiếp theo của JRE.

Nếu bạn thực sự cần phải dựa vào trình tự, xem xét việc thiết lập một chuỗi các thính giả, tức là Listener ai sẽ thông báo cho người nghe hai, vv

+0

Nói chung về sự thay đổi trạng thái (như trái ngược với đầu vào) các sự kiện nó là mạnh mẽ hơn để hoàn toàn bỏ qua các đối tượng sự kiện. (Đừng nhầm lẫn về hiệu suất - hãy nghĩ về số lượng chu kỳ bạn đang sử dụng so với * triệu * một CPU trung bình có thể làm trong một phần nghìn giây). –

+0

@Tom: là nhận xét về câu trả lời của tôi hay câu hỏi của anh ấy? – pstanton

+0

ok, quan điểm của bạn không hoàn toàn rõ ràng. – pstanton

1

Một chút cũ và rất muộn để trả lời. Nhưng tâm trí không ổn định của tôi thực sự buộc tôi phải lẻn vào.

Tôi có thể dựa vào đơn hàng đó hay tôi nên sắp xếp để gửi sự kiện khác?

Tôi tin rằng họ duy trì trật tự, tài liệu của Hợp phần không cho chúng tôi nhiều, nhưng mã nguồn luôn là người bạn của chúng tôi. Chúng ta hãy bắt đầu từ addChangeListener(listener) chức năng của JSlider:

BƯỚC 1: gọi jSlider.addChangeListener(listener) thêm listener đến một listener list.

public void addChangeListener(ChangeListener l) { 
     listenerList.add(ChangeListener.class, l); 
    } 

BƯỚC 2: mã nguồn của EvenListenerList: synchronized add(Class<T> t, T l): thêm các thính giả và loại tương ứng như vậy mà người nghe mới được thêm vào cuối của Object[] và cho một chỉ số i, Object[i] là loại người nghe và Object[i+1] là phiên bản người nghe.

public synchronized <T extends EventListener> void add(Class<T> t, T l) { 
    // There were other checking here 
    // omitted as irrelevant to the discussion 
    } else { 
     // Otherwise copy the array and add the new listener 
     int i = listenerList.length; 
     Object[] tmp = new Object[i+2]; 
     System.arraycopy(listenerList, 0, tmp, 0, i); 

     tmp[i] = t; // add the class type 
     tmp[i+1] = l; // add the listener instance 

     listenerList = tmp; 
    } 
    } 

BƯỚC 3: Chức năng fireStateChanged() của JSlider có trách nhiệm gửi sự kiện cho mọi người nghe của danh sách. Mã nguồn cho chúng ta biết rằng nó gọi hàm của mỗi người nghe là hàm stateChanged() bằng cách truy cập chúng từ cuối danh sách người nghe.

protected void fireStateChanged() { 
     Object[] listeners = listenerList.getListenerList(); 
     for (int i = listeners.length - 2; i >= 0; i -= 2) { 
      if (listeners[i]==ChangeListener.class) { 
       if (changeEvent == null) { 
        changeEvent = new ChangeEvent(this); 
       } 
       ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); 
      } 
     } 
    } 

Summery: Cơ chế (đồng bộ) thêm và tham quan của người nghe trong danh sách người nghe cho chúng ta biết rằng: nó duy trì LAST ADD để lần đầu tiên. Nghĩa là, người nghe được thêm vào sau (con) sẽ được gọi là đầu tiên, sau đó trình nghe được thêm trước (cha mẹ) và vân vân.Mã xử lý sự kiện Swing chạy trên EDT. Và như EventQueue gửi sự kiện Theo thứ tự giống như họ là enqueued, sự kiện con sẽ được gửi đi trước sự kiện gốc.

Vì vậy, tôi tin rằng đơn đặt hàng đang được duy trì.

+1

Trong khi một mẫu thiết kế thú vị, đó là một chi tiết thực hiện mà tôi không muốn dựa vào. – trashgod

+0

có thể, nhưng với tôi, gọi cơ chế 'EventListListener' * không đáng tin cậy * dường như chúng ta đang mắng nó :);) – Sage

+1

chỉ để nhấn mạnh nhận xét của @ trashgod: thứ tự của thông báo rõ ràng là không xác định (xem f.i. bean spec). Ngoài ra, thứ tự có thể thay đổi trong suốt thời gian tồn tại của một quan sát, f.i. bằng cách xóa/thêm người nghe trên LAF thay đổi. Vì vậy, như một quy tắc chung ** không ** dựa vào bất kỳ triển khai cụ thể nào, nó có thể thay đổi mà không cần thông báo! – kleopatra

Các vấn đề liên quan