2010-03-12 44 views
29

Tôi tìm thấy một ví dụ trong đó nút được thêm vào bảng (trường hợp JPanel) sau đó bảng được thêm vào các thùng chứa (trường hợp được tạo bởi getContentPane()) và sau đó vùng chứa, bằng cách xây dựng, được đưa vào JFrame (cửa sổ).Quan hệ giữa ContentPane và JPanel là gì?

tôi đã cố gắng hai điều:

  1. Tôi đã thoát khỏi những container. Để biết thêm chi tiết, tôi đã thêm các nút vào bảng điều khiển (ví dụ: JPanel) và sau đó tôi đã thêm bảng điều khiển vào cửa sổ (ví dụ: JFrame). Nó hoạt động tốt.

  2. Tôi đã loại bỏ các bảng. Để biết thêm chi tiết, tôi đã thêm các nút trực tiếp vào vùng chứa và sau đó tôi thêm vùng chứa vào cửa sổ (ví dụ: JFrame).

Vì vậy, tôi không hiểu hai điều.

  1. Tại sao chúng ta có hai cơ chế cạnh tranh để làm những điều tương tự?

  2. Lý do sử dụng vùng chứa kết hợp với các bảng (JPanel) là gì? (Ví dụ, những gì chúng tôi bao gồm các nút trong JPanels và sau đó chúng tôi bao gồm JPanels trong Containers). Chúng tôi có thể bao gồm JPanel trong số JPanel không? Chúng ta có thể bao gồm một container trong container?

thêm:

Có lẽ bản chất của câu hỏi của tôi có thể được đưa vào một dòng mã:

frame.getContentPane().add(panel); 

gì cho chúng ta đặt getContentPane() ở giữa? Tôi đã thử chỉ frame.add(panel); và nó hoạt động tốt.

THÊM 2:

Tôi muốn thêm một số mã để được rõ ràng hơn về những gì tôi có ý nghĩa. Trong ví dụ này tôi sử dụng chỉ JPane:

import java.awt.*; 
import javax.swing.*; 
public class HelloWorldSwing { 
    public static void main(String[] args) { 
     JFrame frame = new JFrame("HelloWorldSwing"); 
     JPanel panel = new JPanel(); 
     panel.setLayout(new BorderLayout());   
     panel.add(new JButton("W"), BorderLayout.NORTH); 
     panel.add(new JButton("E"), BorderLayout.SOUTH); 
     frame.add(panel); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 
    } 
} 

Và trong ví dụ này tôi sử dụng Pane chỉ Nội dung:

import java.awt.*; 
import javax.swing.*; 
public class HelloWorldSwing { 
    public static void main(String[] args) { 
    JFrame frame = new JFrame("HelloWorldSwing"); 
    Container pane = frame.getContentPane(); 
    pane.setLayout(new BorderLayout()); 
    pane.add(new JButton("W"), BorderLayout.NORTH); 
    pane.add(new JButton("E"), BorderLayout.SOUTH); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.pack(); 
    frame.setVisible(true); 
    } 
} 

Cả hai làm việc tốt! Tôi chỉ muốn biết nếu giữa hai cách để làm những điều tốt hơn (an toàn hơn).

Trả lời

27

Đó không phải là hai cơ chế cạnh tranh - một JPanellà mộtContainer (chỉ cần nhìn vào hệ thống phân cấp lớp ở phía trên cùng của JPanel javadocs). JFrame.getContentPane() chỉ trả lại một Container để đặt số Component mà bạn muốn hiển thị trong JFrame. Nội bộ, sử dụng JPanel (theo mặc định - bạn có thể thay đổi điều này bằng cách gọi setContentPane()) Vì lý do trả lại số Container thay vì JPanel - đó là vì bạn nên program to an interface, not an implementation - ở cấp đó, tất cả những gì bạn cần quan tâm là có thể thêm Component s vào thứ gì đó - và mặc dù Container là một lớp chứ không phải là giao diện - nó cung cấp giao diện cần thiết để thực hiện chính xác điều đó.

Vì lý do cả hai số JFrame.add()JFrame.getContentPane().add() cả hai đều làm như vậy - JFrame.add() bị ghi đè để gọi JFrame.getContentPane().add(). Điều này không phải luôn luôn như vậy - trước JDK 1.5 bạn luôn phải chỉ định JFrame.getContentPane().add() một cách rõ ràng và JFrame.add() ném RuntimeException nếu bạn gọi nó, nhưng do nhiều khiếu nại, điều này đã được thay đổi trong JDK 1.5 để làm những gì bạn mong đợi.

+0

@Nate, ý bạn là gì "Nội bộ, nó sử dụng JPanel". Bạn có nghĩa là Container đang sử dụng JPanel? Ý bạn là như thế nào? Tôi cho rằng JPanel là một phân lớp của Container. Và những gì tôi có thể thay đổi bởi "setContentPane"? ĐƯỢC. Bạn nói rằng Container là một lớp (và tôi luôn coi Container là một lớp). Nhưng JPane cũng là một lớp học. Tại sao chúng ta không thể sử dụng chỉ JPane hay chỉ là Container?Tôi đã có thể làm những điều tương tự bằng cách chỉ sử dụng JPane. Tôi cũng có thể làm tương tự chỉ sử dụng Vùng chứa. – Roman

+0

'JFrame' là nội bộ bằng cách sử dụng một đối tượng' JPanel' để trả về phương thức 'getContentPane()'. Đây là lý do tại sao câu trả lời của Zachary hoạt động. Tham chiếu 'JPanel' thực tế được chôn trong trường' JFrame.rootPane'. Bạn sẽ gọi 'setContentPane()' trên 'JFrame' - ví dụ, bạn có thể thay đổi dòng 10 trong ví dụ đầu tiên của bạn từ' frame.add (panel) 'thành' frame.setContentPane (panel) '. 'Container' là một lớp. 'JPanel' là một lớp (là lớp con của' Vùng chứa'). Bạn đang nhầm lẫn kiểu tham chiếu với loại đối tượng tham chiếu tham chiếu. Hãy nghĩ về 'Container container = new JPanel()' – Nate

+0

@Nate nguồn (http://pragmaticjava.blogspot.com.ar/2008/08/program-to-interface-not-implementation.html) đã bị xóa. – Lucio

1

Tôi tin rằng lý do là vì Swing được xây dựng khỏi AWT và Container là đối tượng AWT cấp cao nhất. Nó thực sự không phải là sự lựa chọn thiết kế lớn nhất, mặc dù, vì bạn thường không muốn kết hợp các đối tượng AWT (hạng nặng) với Swing (trọng lượng nhẹ).

Tôi nghĩ cách tốt nhất để xử lý nó là luôn luôn truyền contentPane tới JPanel.

JPanel contentPanel = (JPanel)aFrame.getContentPane(); 
+0

Nó không trộn các thành phần AWT và Swing ... xem câu trả lời của tôi – Nate

1

Tất cả được viết trong phiên bản trước API doc rằng JFrame.add() (nowerdays) là đủ.

Bạn có thể so sánh với các phiên bản Java cũ hơn here.

3

Câu hỏi hay. Tôi thấy hữu ích khi hiểu rằng "Swing cung cấp ba lớp chứa cấp cao hữu ích nói chung: JFrame, JDialogJApplet. ... Để thuận tiện, phương pháp thêm và các biến thể của nó, xóa và setLayout đã bị ghi đè để chuyển tiếp đến contentPane nếu cần. "- Using Top-Level Containers

1

thú vị: jframe.setBackground(color) không hoạt động đối với tôi, nhưng jframe.getContentPane().setBackground(color) hoạt động.

1

Lịch sử và cơ chế của điều này cũng được thảo luận chi tiết tại this leepoint article. Lưu ý cụ thể:

getContentPane() trả về đối tượng Container. Đây không phải là đối tượng đơn giản là Container, nhưng thực ra là một số JPanel! Đây là một hệ số phân cấp là Container. Vì vậy, nếu chúng tôi nhận được khung nội dung được xác định trước, nó chỉ ra nó thực sự là một JPanel, nhưng chúng tôi thực sự không thể tận dụng các chức năng được thêm vào bởi JComponent.

Họ định nghĩa add() phương pháp trong JFrame mà chỉ đơn giản gọi add() phương pháp tương ứng cho khung nội dung. Có vẻ lạ khi thêm tính năng này ngay bây giờ, đặc biệt là vì nhiều bố cục sử dụng nhiều bảng lồng nhau nên bạn vẫn phải thoải mái khi thêm trực tiếp vào một số JPanel. Và không phải tất cả mọi thứ bạn muốn làm với khung nội dung có thể được thực hiện thông qua các cuộc gọi đến JFrame.

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