2012-04-19 50 views
5

Tôi có một ứng dụng có lớp trừu tượng mở rộng JDialog. Các lớp như một abstract void onClose(), và trong constructor của lớp, các mã sau đây được thêm vào:`WindowListener` hoạt động, bắn vĩnh viễn

addWindowListener(new WindowAdapter() { 
    @Override 
    public void windowClosed(WindowEvent e) { 
     onClose(); 
    } 
} 

Sự kiện này được kích hoạt khi mong đợi, nhưng sau đó một điều kỳ lạ xảy ra. Khi phần mở rộng cụ thể của lớp này có mã để tạo mới JDialog theo phương pháp onClose() vàcủa defaultCloseOperationJDialog.DISPOSE_ON_CLOSE, sự kiện này được kích hoạt liên tục, cho đến khi tôi buộc phải ngừng hoạt động.

Chúng tôi đã tách mã để các SSCCE sau:

// package removed 
// imports removed 
public class SSCCE extends JDialog { 
    public static void main(String[] args) { 
     SSCCE s = new SSCCE(); 
     s.pack(); 
     s.setVisible(true); 
    } 
    public SSCCE() { 
     setLayout(new GridLayout(1, 0, 0, 0)); 
     JButton btn = new JButton("click me"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       dispose(); 
      } 
     }); 
     addWindowListener(new WindowAdapter() { 
      @Override 
      public void windowClosed(WindowEvent e) { 
       System.out 
         .println("SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()"); 
       onClose(); 
      } 
     }); 
     add(btn); 
    } 

    public void onClose() { 
     JDialog dialog = new JDialog(); 
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
     dialog.setVisible(true); 
    } 

} 

Khi nhấp vào nút "nhấp tôi", sự xuất hiện JDialog trống và SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() xuất hiện trong cửa sổ giao diện điều khiển. Khi tôi đóng hộp thoại trống, nó xuất hiện lại và văn bản xuất hiện trở lại.

Một điều thực sự thú vị là khi tôi thay đổi dòng khởi tạo từ

JDialog dialog = new JDialog(); 

để

JDialog dialog = new JDialog() { 
     @Override 
     public synchronized void addWindowListener(WindowListener l) { 
      super.addWindowListener(l); 
      System.out 
        .println("SSCCE.onClose().new JDialog() {...}.addWindowListener()"); 
     } 
    }; 

tôi nhận được đầu ra sau trong giao diện điều khiển:

Khi nhấp "nhấp chuột tôi "button:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 

Tại đóng cửa đầu tiên của hộp thoại:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 

Tại đóng cửa thứ hai của hộp thoại:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 

Mỗi lần tôi đóng hộp thoại, addWindowListener(WindowListener l) được gọi là thời gian thêm, mặc dù tôi không cố ý gọi nó.

Tôi không thực sự muốn bất kỳWindowListener s được đăng ký trên hộp thoại, nhưng tôi nghĩ rằng chỉ đơn giản là trọng phương pháp addWindowListener(...) và không gọi super.addWindowListener(...) sẽ là quá cẩu thả.

Tôi đang chạy Java 1.6.0_31 trên Mac OS X 10.6.8, sử dụng Eclipse Indigo (với WindowBuilder, nếu nó quan trọng).

Có ai có ý tưởng nào không?

Cảm ơn!

Trả lời

7

Theo Java Dialog tutorial,

Mỗi thoại phụ thuộc vào một thành phần Frame. Khi Khung đó bị hủy, thì các Hộp thoại phụ thuộc của nó.

Khi bạn sử dụng JDialog constructor without any arguments, nó

Tạo hộp thoại không chế mà không có một tiêu đề và không có một chủ sở hữu khung quy định. Khung được chia sẻ, ẩn sẽ được đặt làm chủ sở hữu của hộp thoại.

Khung bị ẩn được chia sẻ là SwingUtilities$SharedOwnerFrame và khi khởi tạo, nó đăng ký WindowListener cho tất cả các cửa sổ được sở hữu.

Khi bạn đóng hộp thoại, phương thức windowClosed của SharedOwnerFrame được gọi, kiểm tra tất cả các cửa sổ mà nó sở hữu (tại thời điểm này là hộp thoại SSCCE gốc và hộp thoại mới), không tìm thấy được, và do đó tự nó. Điều này có tác động xử lý tất cả các hộp thoại mà nó sở hữu, đăng một sự kiện đóng cửa sổ cho mỗi hộp thoại. Điều này gọi số windowClosed trong trình nghe của bạn, mở hộp thoại mới. Và vòng chúng ta đi một lần nữa :-). Về những nhận xét cuối cùng của bạn, bạn sẽ nhận được các dòng nhật ký bổ sung mỗi lần bởi vì bạn nhận được một hộp thoại cho mỗi hộp thoại mà SharedOwnerFrame sở hữu.

Nếu bạn thực hiện thoại SSCCE riêng hộp thoại mới (bằng cách thông qua this vào constructor của nó) sau đó bạn không kết thúc với quyền sở hữu được chia sẻ và nó hoạt động tốt:

public void onClose() { 
    JDialog dialog = new JDialog(this); 
    dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
    dialog.setVisible(true); 
} 
+0

Cảm ơn! Điều đó có ý nghĩa hoàn hảo. – wchargin

4
import java.awt.GridLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 

import javax.swing.JButton; 
import javax.swing.JDialog; 
import javax.swing.JOptionPane; 

public class SSCCE extends JDialog { 
    public static void main(String[] args) { 
     SSCCE s = new SSCCE(); 
     s.pack(); 
     s.setVisible(true); 
    } 

    private WindowAdapter wa = new WindowAdapter() { 
     @Override 
     public void windowClosed(WindowEvent e) { 
      System.out 
        .println("SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()"); 
      onClose(); 
     } 
    }; 

    public SSCCE() { 
     setLayout(new GridLayout(1, 0, 0, 0)); 
     JButton btn = new JButton("click me"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       dispose(); 
      } 
     }); 
     addWindowListener(
     wa); 
     add(btn); 
    } 

    public void onClose() { 
     removeWindowListener(wa); 
     JDialog dialog = new JDialog(); 
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
     dialog.setVisible(true); 

    } 

} 
+0

tôi xem những gì bạn' đã thực hiện, và tôi thấy lý do tại sao nó hoạt động, nhưng tôi thực sự tự hỏi tại sao người nghe ('wa') đang được thêm vào hộp thoại' ở vị trí đầu tiên. Bạn có thể giải thích cho tôi tại sao? – wchargin

+0

Tôi ước gì tôi có câu trả lời tốt cho bạn. Tôi nghĩ rằng nó có thể phải làm với thực tế là lớp học của bạn mở rộng JDialog. – ControlAltDel

+0

user1291492 'với thực tế là lớp của bạn mở rộng JDialog' +++++ 1k, chính xác – mKorbel

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