Tôi có nên tránh sử dụng các phương thức Kích thước tập hợp (Ưu tiên | Tối đa | Tối thiểu) trong Java Swing không?


481

Một vài lần tôi đã bị chỉ trích vì đã đề nghị sử dụng các phương pháp sau:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

trên Swingcác thành phần. Tôi không thấy bất kỳ sự thay thế nào cho việc sử dụng chúng khi tôi muốn xác định tỷ lệ giữa các thành phần được hiển thị. Tôi đã được nói điều này:

Với bố cục, câu trả lời luôn giống nhau: sử dụng Trình quản lý bố cục phù hợp

Tôi đã tìm kiếm trên web một chút, nhưng tôi không tìm thấy bất kỳ phân tích toàn diện nào về chủ đề này. Vì vậy, tôi có các câu hỏi sau đây:

  1. Tôi có nên tránh hoàn toàn việc sử dụng các phương pháp đó?
  2. Các phương pháp đã được xác định cho một lý do. Vậy khi nào tôi nên sử dụng chúng? Trong bối cảnh nào? Vì mục đích gì?
  3. Chính xác những hậu quả tiêu cực của việc sử dụng các phương pháp đó là gì? (Tôi chỉ có thể nghĩ thêm tính di động giữa các hệ thống có độ phân giải màn hình khác nhau).
  4. Tôi không nghĩ rằng bất kỳ LayoutManager nào có thể đáp ứng chính xác tất cả các nhu cầu bố trí mong muốn. Tôi có thực sự cần phải triển khai một Trình quản lý bố cục mới cho mỗi biến thể nhỏ trên bố cục của mình không?
  5. Nếu câu trả lời cho 4 là "có", điều này sẽ không dẫn đến sự phổ biến của các lớp LayoutManager sẽ trở nên khó duy trì?
  6. Trong tình huống tôi cần xác định tỷ lệ giữa các con của Thành phần (ví dụ: child1 nên sử dụng 10% dung lượng, child2 40%, child3 50%), có thể đạt được điều đó mà không cần thực hiện Trình quản lý bố cục tùy chỉnh không?

Câu trả lời:


236
  1. Tôi có nên tránh hoàn toàn việc sử dụng các phương pháp đó?

    Có cho mã ứng dụng.

  2. Các phương pháp đã được xác định cho một lý do. Vậy khi nào tôi nên sử dụng chúng? Trong bối cảnh nào? Vì mục đích gì?

    Tôi không biết, cá nhân tôi nghĩ đó là một tai nạn thiết kế API. Hơi bị ép buộc bởi các thành phần hỗn hợp có ý tưởng đặc biệt về kích thước trẻ em. "Hơi", vì lẽ ra họ nên thực hiện nhu cầu của mình với Trình quản lý bố cục tùy chỉnh.

  3. Chính xác những hậu quả tiêu cực của việc sử dụng các phương pháp đó là gì? (Tôi chỉ có thể nghĩ thêm tính di động giữa các hệ thống có độ phân giải màn hình khác nhau.)

    Một số (không đầy đủ và không may là các liên kết bị hỏng do di chuyển SwingLabs sang java.net), ví dụ như các lý do kỹ thuật được đề cập trong Quy tắc (hehe) hoặc trong liên kết @bendicott được tìm thấy trong nhận xét của anh ấy / cô ấy cho câu trả lời của tôi . Về mặt xã hội, đặt ra hàng tấn công việc cho người bạn không may của bạn, người phải duy trì mã và phải theo dõi một bố cục bị hỏng.

  4. Tôi không nghĩ rằng bất kỳ LayoutManager nào có thể đáp ứng chính xác tất cả các nhu cầu bố trí mong muốn. Tôi có thực sự cần phải triển khai một Trình quản lý bố cục mới cho mỗi biến thể nhỏ trên bố cục của mình không?

    Có, có Trình quản lý Bố cục đủ mạnh để đáp ứng xấp xỉ rất tốt cho "tất cả các nhu cầu bố trí". Ba công cụ lớn là Joodies FormLayout, MigLayout, DesignGridLayout. Vì vậy, trong thực tế, bạn hiếm khi viết Trình quản lý ngoại trừ các môi trường đơn giản có tính chuyên môn cao.

  5. Nếu câu trả lời cho 4 là "có", điều này sẽ không dẫn đến sự phổ biến của các lớp LayoutManager sẽ trở nên khó duy trì?

    (Câu trả lời cho 4 là "không".)

  6. Trong tình huống tôi cần xác định tỷ lệ giữa các con của Thành phần (ví dụ: con 1 nên sử dụng 10% dung lượng, con 2 40%, con 3 50%), có thể đạt được điều đó mà không cần thực hiện Trình quản lý bố cục tùy chỉnh không?

    Bất kỳ Big-Three nào cũng có thể, thậm chí không thể là GridBag (không bao giờ bận tâm đến việc thực sự thành thạo, quá nhiều rắc rối vì quá ít năng lượng).


4
Tôi không hoàn toàn chắc chắn rằng tôi đồng ý với lời khuyên này trong ít nhất hai tình huống. 1) Các thành phần được hiển thị tùy chỉnh 2) Sử dụng JEditorPanevới HTML không tự đề xuất chiều rộng. OTOH Tôi không chắc là tôi đã bỏ lỡ điều gì. Tôi sẽ xem xét cẩn thận các câu trả lời trên chủ đề, nhưng rất quan tâm nếu bạn có bất kỳ ý kiến ​​nào, đặc biệt là về trường hợp sau.
Andrew Thompson

2
@Andrew Thompson 1) comps tùy chỉnh: chính comp đó chịu trách nhiệm trả lại các gợi ý bố cục hữu ích, nếu chúng không có lỗi 2) ngay cả các comps lõi cũng bị lỗi ;-) 3) Tôi không bận tâm đến khoảng trắng (mặc dù không phải vậy cố ý lần này, cảm ơn :-)
kleopatra

8
Tôi không thể tin câu trả lời được chấp nhận là câu trả lời tránh sử dụng các phương thức setXXX (). Đôi khi bạn chỉ cần chúng để cung cấp một gợi ý cho trình quản lý bố cục. Nếu bạn đang đặt một bảng điều khiển thì bạn hoàn toàn nên sử dụng các phương pháp này khi cần thiết. Nói rằng tôi nghĩ rằng nếu bạn sử dụng trình quản lý bố cục phù hợp, bạn sẽ thấy mình không cần các phương thức này rất thường xuyên, nhưng đôi khi bạn chỉ cần chúng. Hãy thử đặt JComboBox hoặc JSpinner vào X_AXIS BoxLayout và không sử dụng chúng, tin rằng bạn sẽ thấy bạn cần setMaximumSize () ở đó.
Michael

5
@Michael không, tôi hoàn toàn không cần nó - câu trả lời là luôn luôn sử dụng một Trình quản lý
Bố cục

5
Bạn cứ nói "sử dụng một Trình quản lý bố cục hợp lý và cho nó biết kích thước bạn muốn" trên toàn bộ stackoverflow, nhưng bạn không bao giờ đưa ra bất kỳ ví dụ cụ thể nào về Trình quản lý bố cục "đàng hoàng". Và không ai trong số các nhà quản lý tiêu chuẩn cho phép kiểm soát kích thước trực tiếp.
Ti Strga

100

Một vài phương pháp phỏng đoán:

  • Không sử dụng set[Preferred|Maximum|Minimum]Size()khi bạn thực sự muốn ghi đè get[Preferred|Maximum|Minimum]Size(), như có thể được thực hiện trong việc tạo thành phần của riêng bạn, được hiển thị ở đây .

  • Không sử dụng set[Preferred|Maximum|Minimum]Size()khi bạn có thể dựa vào ghi đè cẩn thận của một thành phần getPreferred|Maximum|Minimum]Size, như hiển thị ở đây và bên dưới.

  • Sử dụng set[Preferred|Maximum|Minimum]Size()để lấy được hậu validate()hình học, như hiển thị bên dưới và ở đây .

  • Nếu một thành phần không có kích thước ưa thích, ví dụ JDesktopPane, bạn có thể phải kích thước thùng chứa, nhưng bất kỳ lựa chọn nào như vậy là tùy ý. Một bình luận có thể giúp làm rõ ý định.

  • Xem xét bố cục thay thế hoặc tùy chỉnh khi bạn thấy rằng bạn sẽ phải lặp qua nhiều thành phần để có được kích thước dẫn xuất, như đã đề cập trong các nhận xét này .

nhập mô tả hình ảnh ở đây

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
 * @see /programming/7229226
 * @see /programming/7228843
 */
public class DesignTest {

    private List<JTextField> list = new ArrayList<JTextField>();
    private JPanel panel = new JPanel();
    private JScrollPane sp = new JScrollPane(panel);

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                DesignTest id = new DesignTest();
                id.create("My Project");
            }
        });
    }

    private void addField(String name) {
        JTextField jtf = new JTextField(16);
        panel.add(new JLabel(name, JLabel.LEFT));
        panel.add(jtf);
        list.add(jtf);
    }

    private void create(String strProjectName) {
        panel.setLayout(new GridLayout(0, 1));
        addField("First Name:");
        addField("Last Name:");
        addField("Address:");
        addField("City:");
        addField("Zip Code:");
        addField("Phone:");
        addField("Email Id:");
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addPropertyChangeListener("permanentFocusOwner",
            new FocusDrivenScroller(panel));
        // Show half the fields
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        sp.validate();
        Dimension d = sp.getPreferredSize();
        d.setSize(d.width, d.height / 2);
        sp.setPreferredSize(d);

        JInternalFrame internaFrame = new JInternalFrame();
        internaFrame.add(sp);
        internaFrame.pack();
        internaFrame.setVisible(true);

        JDesktopPane desktopPane = new JDesktopPane();
        desktopPane.add(internaFrame);

        JFrame frmtest = new JFrame();
        frmtest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmtest.add(desktopPane);
        frmtest.pack();
        // User's preference should be read from java.util.prefs.Preferences
        frmtest.setSize(400, 300);
        frmtest.setLocationRelativeTo(null);
        frmtest.setVisible(true);
        list.get(0).requestFocusInWindow();
    }

    private static class FocusDrivenScroller implements PropertyChangeListener {

        private JComponent parent;

        public FocusDrivenScroller(JComponent parent) {
            this.parent = parent;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            Component focused = (Component) evt.getNewValue();
            if (focused != null
                && SwingUtilities.isDescendingFrom(focused, parent)) {
                parent.scrollRectToVisible(focused.getBounds());
            }
        }
    }
}

2
không đồng ý (như bạn có thể đoán :-) với lý do bởi "các yếu tố bên ngoài": các thuộc tính XXSize có nghĩa là để thể hiện nhu cầu chỉ nội bộ . Tinh chỉnh những người từ bên ngoài là sử dụng sai, hay còn gọi là hack. Nếu bạn muốn khung (Nội bộ hoặc J-) có kích thước cụ thể tương ứng với kích thước được ưu tiên ... kích thước khung, không phải nội dung
kleopatra

2
@kleopatra: chỉ cần nhấn mạnh một chút: nếu không bao giờ sử dụng các phương thức setXXSize từ bên ngoài, tại sao không được tuyên bố là riêng tư hoặc được bảo vệ? Đây không phải là thiếu thiết kế sao? Không phải công cụ sửa đổi công khai ngầm nói với người dùng có thể sử dụng các phương thức đó sao?
Heisenorms

2
Tôi phải đồng ý với @kleopatra: setPreferredSize()luôn thay thế phép tính của thành phần bằng một lựa chọn tùy ý.
thùng rác

1
@trashgod +100 với bạn Tôi nghĩ không có vấn đề gì với việc ghi đè các phương thức này, thậm chí gọi chúng (nhưng tất nhiên điều này có nghĩa là bạn có một thành phần tùy chỉnh do đó ghi đè sẽ tốt hơn)
David Kroukamp

5
@DavidKroukamp: Cảm ơn bạn. Tôi trì hoãn trải nghiệm lớn hơn của kleopatra, nhưng tôi thấy giá trị trong việc kiểm tra quan điểm trái ngược một cách nghiêm túc.
thùng rác

47

Tôi có nên tránh hoàn toàn việc sử dụng các phương pháp đó?

Không, không có bằng chứng chính thức nào cho thấy việc gọi hoặc ghi đè các phương thức này là không được phép. Trên thực tế, Oracle cho biết các phương thức này được sử dụng để đưa ra gợi ý về kích thước: http://docs.oracle.com/javase/tutorial/uiswing/layout/USE.html#sizealocate .

Chúng cũng có thể bị ghi đè (đó là cách thực hành tốt nhất cho Xoay) khi mở rộng thành phần Xoay (thay vì gọi phương thức trên thể hiện thành phần tùy chỉnh)

Quan trọng nhất cho dù bạn chỉ định kích thước thành phần của mình như thế nào, hãy chắc chắn rằng bộ chứa thành phần của bạn sử dụng trình quản lý bố cục tôn trọng kích thước được yêu cầu của thành phần.

Các phương pháp đã được xác định cho một lý do. Vậy khi nào tôi nên sử dụng chúng? Trong bối cảnh nào? Vì mục đích gì?

Khi bạn cần cung cấp gợi ý kích thước tùy chỉnh cho bộ chứa Trình quản lý bố cục để thành phần sẽ được bố trí tốt

Chính xác những hậu quả tiêu cực của việc sử dụng các phương pháp đó là gì? (Tôi chỉ có thể nghĩ để thêm tính di động giữa các hệ thống có độ phân giải màn hình khác nhau).

  • Nhiều người quản lý bố cục không chú ý đến kích thước tối đa được yêu cầu của một thành phần. Tuy nhiên, BoxLayoutSpringLayoutlàm. Hơn nữa, GroupLayoutcung cấp khả năng đặt kích thước tối thiểu, ưu tiên hoặc tối đa một cách rõ ràng mà không cần chạm vào thành phần.

  • Đảm bảo rằng bạn thực sự cần đặt kích thước chính xác của thành phần. Mỗi thành phần Swing có kích thước ưa thích khác nhau, tùy thuộc vào phông chữ mà nó sử dụng và giao diện. Như vậy có kích thước bộ có thể tạo đa dạng ngoại hình của giao diện người dùng trên hệ thống khác nhau

  • đôi khi các vấn đề có thể gặp phải GridBagLayoutvà các trường văn bản, trong đó nếu kích thước của vùng chứa nhỏ hơn kích thước ưa thích, kích thước tối thiểu được sử dụng, điều này có thể khiến các trường văn bản co lại đáng kể.

  • JFramekhông thực thi overriden getMinimumSize()chỉ kêu gọi setMinimumSize(..)các công trình của nó

Tôi không nghĩ rằng bất kỳ LayoutManager nào có thể đáp ứng chính xác tất cả các nhu cầu bố trí mong muốn. Tôi có thực sự cần phải triển khai một Trình quản lý bố cục mới cho mỗi biến thể nhỏ trên bố cục của mình không?

Nếu bằng cách thực hiện bạn có nghĩa là sử dụng thì có. Không ai LayoutMangercó thể xử lý tất cả mọi thứ, mỗi cái đều LayoutManagercó ưu và nhược điểm, do đó mỗi cái có thể được sử dụng cùng nhau để tạo ra bố cục cuối cùng.

Tài liệu tham khảo:


3
cung cấp gợi ý kích thước tùy chỉnh, bản thân nó là một mâu thuẫn: cung cấp gợi ý kích thước (tính bằng px!) là nhiệm vụ độc quyền của thành phần. Nó tính toán chúng dựa trên các chi tiết trạng thái nội bộ mà không bên nào khác ngoại trừ chính nó có thể biết (cũng không thể theo dõi). Từ góc độ máy khách, phương tiện tùy chỉnh có thể là một Trình quản lý phù hợp và / hoặc chuyên api trên thành phần cho phép định cấu hình các yêu cầu kích thước theo các thuộc tính kích thước "ngữ nghĩa", số lượng hàng / cột trong thành phần văn bản
kleopatra

3
@kleopatra Tôi vẫn muốn biết lý do tại sao Oracle sau đó cho chúng tôi biết cách sử dụng các phương thức này và cách sử dụng chúng chính xác. Chúng tôi có thể có sở thích riêng của chúng tôi nhưng chúng tôi không thể nói rằng các nhà thiết kế đề nghị không sử dụng nó khi không có bằng chứng cho thấy điều này. Nhưng đó là lý do tại sao tôi đưa tiền thưởng xem có thể nếu nó sẽ thu hút những người khác có thể cung cấp thông tin từ một nguồn đáng tin cậy trong đó các nhà tiên tri không sử dụng các phương thức này (do đó, thực tế là nếu bạn thực hiện, ví dụ như setMinimumSize phải kêu gọi những thứ như JSplitPane, v.v. điều này có thể được nhìn thấy trong hướng dẫn của Oracle về các tấm chia.
David Kroukamp

4
@David: Tôi đã đến để xem các setXxxSizephương pháp như một lá cờ đỏ mà tôi có thể ở đây , ngay cả khi các tài liệu đề xuất nó. Tôi hầu như luôn luôn bị ghi đè getXxxSize, nơi người ta có quyền truy cập vào hình học cần thiết; và thậm chí các ví dụ ngắn được tái chế nhiều hơn tôi muốn nghĩ. +1 để đề cập đến sự thay đổi giữa các trình quản lý bố cục và trích dẫn hướng dẫn.
thùng rác

1
D'oh, trong nhận xét của tôi ở trên, tôi muốn trích dẫn câu trả lời ở đây .
thùng rác

13
+1 "Không, không có bằng chứng chính thức nào cho thấy việc gọi hoặc ghi đè các phương thức này là không được phép." Tại chỗ trên. Bài đăng được gắn thẻ là câu trả lời là BS.
TT.

25

Có rất nhiều câu trả lời hay ở đây nhưng tôi muốn nói thêm một chút về lý do tại sao bạn thường nên tránh những câu hỏi này (câu hỏi chỉ xuất hiện lại trong một chủ đề trùng lặp):

Với một vài ngoại lệ, nếu bạn đang sử dụng các phương pháp này, có lẽ bạn đang tinh chỉnh GUI của mình để trông đẹp hơn trên giao diện cụ thể (và với các cài đặt dành riêng cho hệ thống của bạn, ví dụ: phông chữ trên màn hình ưa thích của bạn, v.v.). Bản thân các phương pháp không phải là xấu, nhưng lý do điển hình cho việc sử dụng chúng . Ngay khi bạn bắt đầu điều chỉnh các vị trí và kích thước pixel trong bố cục, bạn sẽ có nguy cơ bị vỡ GUI (hoặc tối thiểu, trông xấu), trên các nền tảng khác.

Để làm ví dụ cho điều này, hãy thử thay đổi giao diện mặc định của ứng dụng của bạn. Ngay cả với các tùy chọn có sẵn trên nền tảng của bạn, bạn có thể ngạc nhiên về kết quả có thể được hiển thị kém như thế nào.

Vì vậy, nhân danh việc giữ cho GUI của bạn hoạt động tốt và đẹp mắt trên tất cả các nền tảng (hãy nhớ rằng, một trong những lợi ích chính của Java là tính đa nền tảng của nó), bạn nên dựa vào các trình quản lý bố cục, v.v., để tự động điều chỉnh kích thước của các thành phần của bạn để nó hiển thị chính xác bên ngoài môi trường phát triển cụ thể của bạn.

Tất cả những gì đã nói, bạn chắc chắn có thể hình dung ra các tình huống trong đó các phương pháp này là hợp lý. Một lần nữa, chúng không phải là xấu, nhưng việc sử dụng chúng thường là một lá cờ đỏ lớn cho thấy các vấn đề GUI tiềm ẩn. Chỉ cần đảm bảo rằng bạn nhận thức được khả năng biến chứng cao nếu / khi bạn sử dụng chúng và luôn cố gắng suy nghĩ nếu có một giải pháp độc lập khác về ngoại hình cho các vấn đề của bạn - thường xuyên hơn là bạn sẽ không thấy rằng những điều này phương pháp không cần thiết.

Nhân tiện, nếu bạn thấy mình nản lòng với các trình quản lý bố cục tiêu chuẩn, có rất nhiều bên thứ ba nguồn mở, miễn phí tốt, ví dụ như Joodies 'FormLayout , hoặc MigLayout. Một số trình xây dựng GUI thậm chí còn có hỗ trợ tích hợp cho các trình quản lý bố cục của bên thứ ba - ví dụ, trình soạn thảo GUI WindowBuilder của Eclipse có các hỗ trợ cho FormLayoutMigLayout.


2
+1 một câu trả lời ân cần - chỉ không đồng ý với chúng không phải là xấu xa đơn giản chỉ vì chúng là :-) Thông thường, khách hàng bên ngoài không có cơ hội nào để đoán - và các giả định chỉ gần giống như người ngoài có thể nhận được - gợi ý về bố cục chính xác: bản thân các thành phần luôn có tất cả thông tin để trả về bất cứ thứ gì hữu ích. Và kể từ thời điểm người ngoài can thiệp, đó là trách nhiệm của họ để giữ cho những gợi ý đó được cập nhật mà họ không thể.
kleopatra

1
Chà, bạn biết đấy, tôi có một quan điểm "súng không giết người, giết người" nhiều hơn về những thứ này. :) Nếu ai đó sử dụng các phương pháp này, họ cần nhận thức được những điều như những điểm tốt mà bạn nêu ra về cách sử dụng gợi ý bố cục không thể đoán trước (đó là lý do tại sao các tình huống mà các phương pháp này phù hợp thực sự hiếm).
Jason C

Tôi nghĩ rằng thiết lập kích thước ưa thích hoàn toàn không phải là một lá cờ đỏ lớn. Thay vào đó, không đặt nó một lá cờ đỏ lớn. Hãy để tôi giải thích. Trình quản lý bố cục - cho dù nó thông minh đến đâu - không biết về chức năng logic của tiện ích gui. Ví dụ: trình quản lý bố cục không thể phân biệt giữa JTextField để nhập mã ZIP và JTextField để nhập tên. Tương tự, nó không thể phân biệt giữa một nút công cụ bên cạnh JTextField hoặc nút OK lớn ở cuối biểu mẫu. Do đó, một bộ widget tốt hơn, hoặc một số gợi ý kích thước là cần thiết, không?
Gee Bee

@GeeBee Không, đó là một ví dụ điển hình của cờ đỏ, trên thực tế. Những gì bạn nên làm là sử dụng JTextField.setColumnsđể đặt số lượng cột, điều chỉnh kích thước ưa thích cho phù hợp. Nếu bạn làm như vậy setPreferredSizethì bạn khó mã hóa một kích thước, điều này sẽ phá vỡ bố cục của bạn tùy thuộc vào kích thước phông chữ của nền tảng. Dưới đây là một số trường văn bản trong bố trí túi lưới với cách setColumnsgọi phù hợp . Đối với các nút của bạn, sử dụng bố cục / trọng lượng lưới thích hợp để kiểm soát kích thước.
Jason C

@GeeBee Và bây giờ, với điều đó được thực hiện chính xác, hãy chú ý cách giảm độ rộng của trường văn bản khi tôi giảm kích thước phông chữ: i.snag.gy/ZULulh.jpg . Ngay cả việc thay đổi kích thước phông chữ ngay bây giờ cũng hoạt động tự động, thay vì bạn phải tính toán lại tất cả độ rộng của trường văn bản và gọi lại setPreferredSize một cách rõ ràng, tất cả những gì bạn phải làm là vô hiệu hóa bố cục và kích thước của chúng sẽ điều chỉnh.
Jason C

20

Nếu bạn đang gặp rắc rối với các bố cục trong Java Swing, thì tôi hoàn toàn có thể đề xuất các Joodies FormLayoutđược cung cấp miễn phí như một phần của thư viện phần mềm miễn phí Forms của Karsten Lentzsch tại đây .

Trình quản lý bố cục rất phổ biến này cực kỳ linh hoạt, cho phép phát triển các UI Java rất bóng bẩy.

Bạn sẽ tìm thấy tài liệu của Karsten ở đây , và một số tài liệu khá hay từ nhật thực ở đây .


16

Những phương pháp này được hầu hết mọi người hiểu kém. Bạn tuyệt đối không nên bỏ qua các phương pháp này. Tùy thuộc vào trình quản lý bố cục nếu họ tôn trọng các phương thức này. Trang này có một bảng cho biết người quản lý bố cục nào tôn vinh phương thức nào:

http://thebadprogrammer.com/swing-layout-manager-sizing/

Tôi đã viết mã Swing trong hơn 8 năm và các trình quản lý bố cục có trong JDK luôn phục vụ nhu cầu của tôi. Tôi chưa bao giờ cần một người quản lý bố trí bên thứ 3 để đạt được bố cục của mình.

Tôi sẽ nói rằng bạn không nên cố gắng đưa ra gợi ý cho trình quản lý bố cục với các phương thức này cho đến khi bạn chắc chắn rằng mình cần chúng. Thực hiện bố cục của bạn mà không đưa ra bất kỳ gợi ý kích thước nào (nghĩa là để trình quản lý bố cục thực hiện công việc của nó) và sau đó bạn có thể thực hiện các chỉnh sửa nhỏ nếu bạn cần.


1
hoặc có một quan niệm sai lầm nhỏ (về phía bạn) hoặc hiểu lầm (về phía tôi), hãy lựa chọn :-) Bạn cứ lặp đi lặp lại (ở đây, trong blog của bạn, trong câu trả lời của bạn liên quan đến BoxLayout), bộ XXSize rất quan trọng - thực sự là LayoutManager (hoặc không) quan tâm đến XXSize, đó là gợi ý kích thước độc lập với cách thức hoạt động (tính toán nội bộ theo thành phần hoặc bắt buộc bằng mã ứng dụng)
kleopatra

1
Tôi không chắc chắn tôi hiểu những gì bạn đang nhận được ở đây. Tôi đã đề cập ở trên rằng các phương thức XXSize () chỉ là gợi ý. Tôi thực sự thấy không có gì sai khi đưa ra một trình quản lý bố cục một chút gợi ý, nếu cần. Trong mã swing của tôi, bạn sẽ tìm thấy một phương thức setXXSize () không thường xuyên. Không nhiều, nhưng thỉnh thoảng tôi thấy chúng là cần thiết. JComboBox và JSpinner thường xuyên cần gợi ý. Đặc biệt là một JComboBox được đưa vào sau khi nó được nhận ra. Bạn dường như chống lại bất kỳ và tất cả việc sử dụng các phương pháp này và tôi không biết tại sao. (có lẽ tôi là người mất thuyền trên này tôi đoán vậy).
Michael

5
không phải các phương thức là gợi ý, các thuộc tính là: các thành phần sẽ báo cáo điều gì đó hợp lý cho tất cả các gợi ý, một số (như fi JComboBox) không - trong việc trả về maxInteger hoặc hơn thế. Đó là một lỗi và nên được sửa bởi combo. Theo thói quen của bạn: hãy chắc chắn ở xa khi đồng nghiệp bảo trì phải dọn dẹp nó :) Gợi ý mã hóa cứng có xu hướng phá hỏng bố cục ở mức thay đổi nhỏ nhất và khó phát hiện là lý do cho bố cục bị hỏng.
kleopatra

15

Trong tình huống tôi cần xác định tỷ lệ giữa các con của Thành phần (con 1 nên sử dụng 10% dung lượng, con2 40%, con3 50%), có thể đạt được điều đó mà không cần thực hiện trình quản lý bố cục tùy chỉnh không?

Có lẽ GridBagLayoutsẽ đáp ứng nhu cầu của bạn. Bên cạnh đó, có rất nhiều trình quản lý bố cục trên web và tôi cá là có một trình quản lý phù hợp với yêu cầu của bạn.


cảm ơn câu trả lời Tôi phải giả sử rằng bạn cũng có nghĩa là: "hoàn toàn không sử dụng setPreferredSize", phải không?
Heisenorms

1
GridBagLayout sử dụng các ràng buộc, trong đó bạn có thể chỉ định "trọng số" cả trong X và Y cho một thành phần nhất định, do đó, Trình quản lý bố cục có thể quyết định phải làm gì với không gian bổ sung trên thay đổi kích thước. NHƯNG bạn vẫn cần / có thể sử dụng setPreferredSize để xác định kích thước ưa thích của từng thành phần, lưu ý rằng "ưa thích" không có nghĩa là nó sẽ luôn được tôn vinh. Đối với các trường hợp đặc biệt, bạn cũng có thể cần setMinimumSize và setMaximumSize. Họ không xấu xa , đừng mua vào đó. docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
マ ル ち ゃ ん だ

5

Tôi đang thấy nó khác với câu trả lời được chấp nhận.

1) Tôi có nên tránh hoàn toàn việc sử dụng các phương pháp đó không?

Không bao giờ tránh! Chúng ở đó để thể hiện các ràng buộc kích thước của các thành phần của bạn với trình quản lý bố cục. Bạn có thể tránh sử dụng chúng nếu bạn không sử dụng bất kỳ trình quản lý bố cục nào và cố gắng tự mình quản lý bố cục trực quan.

Thật không may, Swing không đến với kích thước mặc định hợp lý. Tuy nhiên, thay vì đặt kích thước của một thành phần, OOP tốt hơn là hạ xuống thành phần của chính bạn với mặc định hợp lý. (Trong trường hợp đó, bạn gọi setXXX trong lớp con cháu của mình.) Ngoài ra, bạn có thể ghi đè các phương thức getXXX cho cùng một hiệu ứng.

2) Các phương pháp đã được xác định vì một lý do. Vậy khi nào tôi nên sử dụng chúng? Trong bối cảnh nào? Vì mục đích gì?

Luôn luôn. Khi bạn tạo một thành phần, hãy đặt kích thước tối thiểu / ưa thích / tối đa thực tế của nó theo việc sử dụng thành phần đó. Ví dụ: nếu bạn có JTextField để nhập các ký hiệu quốc gia như Vương quốc Anh, kích thước ưa thích của nó sẽ rộng bằng hai ký tự (với phông chữ hiện tại, v.v.) nhưng có lẽ sẽ vô nghĩa khi để nó lớn hơn nữa. Rốt cuộc, biểu tượng đất nước là hai ký tự. Ngược lại, nếu bạn có JTextField để nhập ví dụ như tên khách hàng, nó có thể có kích thước ưa thích như kích thước pixel cho 20 ký tự, nhưng có thể tăng lên lớn hơn nếu bố cục được thay đổi kích thước, vì vậy hãy đặt kích thước tối đa thành nhiều hơn. Đồng thời, việc có một JTextField rộng 0px là vô nghĩa, vì vậy hãy đặt kích thước tối thiểu thực tế (tôi sẽ nói kích thước pixel là 2 ký tự).

3) Chính xác những hậu quả tiêu cực của việc sử dụng các phương pháp đó là gì?

(Tôi chỉ có thể nghĩ thêm tính di động giữa các hệ thống có độ phân giải màn hình khác nhau).

Không có hậu quả tiêu cực. Đây là những gợi ý cho người quản lý bố trí.

4) Tôi không nghĩ rằng bất kỳ Trình quản lý bố cục nào có thể đáp ứng chính xác tất cả các nhu cầu bố trí mong muốn.

Tôi có thực sự cần phải triển khai một Trình quản lý bố cục mới cho mỗi biến thể nhỏ trên bố cục của mình không?

Không chắc chắn không. Cách tiếp cận thông thường là xếp tầng các cách bố trí cơ bản khác nhau như bố trí ngang và dọc.

Ví dụ: bố cục bên dưới:

<pre>
+--------------+--------+
| ###JTABLE### | [Add]  | 
| ...data...   |[Remove]|
| ...data...   |        |
| ...data...   |        |
+--------------+--------+
</pre>

đang có hai phần. Phần bên trái và bên phải là một bố cục ngang. Phần bên phải là một JPanel được thêm vào bố cục theo chiều ngang và JPanel này có bố cục dọc để đặt các nút theo chiều dọc.

Tất nhiên, điều này có thể phát triển khó khăn với một bố cục thực tế. Do đó, các trình quản lý bố cục dựa trên lưới như MigLayout sẽ tốt hơn nhiều nếu bạn sắp phát triển bất cứ điều gì nghiêm trọng.

5) Nếu câu trả lời cho 4 là "có", điều này sẽ không dẫn đến sự phổ biến của các lớp LayoutManager sẽ trở nên khó duy trì?

Không, bạn chắc chắn sẽ không phát triển trình quản lý bố cục, trừ khi bạn cần một cái gì đó rất đặc biệt.

6) Trong tình huống tôi cần xác định tỷ lệ ...

giữa các con của Thành phần (ví dụ: child1 nên sử dụng 10% dung lượng, child2 40%, child3 50%), có thể đạt được điều đó mà không cần thực hiện Trình quản lý tùy chỉnh không?

Về cơ bản, một khi các kích thước ưa thích được đặt đúng, bạn có thể không muốn làm bất cứ điều gì theo tỷ lệ phần trăm. Đơn giản, bởi vì tỷ lệ phần trăm là vô nghĩa (ví dụ như vô nghĩa khi có JTextField 10% kích thước cửa sổ - vì người ta có thể thu nhỏ cửa sổ để JTextField trở nên rộng 0px hoặc có thể mở rộng cửa sổ để JTextField nằm trên hai màn hình trên một thiết lập đa màn hình).

Nhưng, đôi khi bạn có thể sử dụng tỷ lệ phần trăm để kiểm soát kích thước của các khối xây dựng lớn hơn của gui của bạn (ví dụ: bảng điều khiển).

Bạn có thể sử dụng JSplitPane nơi bạn có thể đặt trước tỷ lệ của hai bên. Hoặc, bạn có thể sử dụng MigLayout cho phép bạn đặt các ràng buộc đó theo tỷ lệ phần trăm, pixel và các đơn vị khác.


Có thật không? Đây là 0? Điều này tốt hơn câu trả lời được chấp nhận có hơn 100 lần. Điều đó về cơ bản nói rằng "Bạn sẽ sử dụng setPreferredSize!" đó là TERRIBLE. Trong công việc của tôi, có RẤT NHIỀU yêu cầu kích thước cụ thể, chẳng hạn như "Các nút trên màn hình cảm ứng phải là [X] bởi [Y] với [M] x [N] khoảng cách giữa" yêu cầu an toàn. btnBar.setPreferredSize( dimTouchBtn );là cách tốt nhất để làm điều đó Đơn giản, không cần quản lý bố trí tùy chỉnh. Tôi sử dụng chủ yếu GridBagLayoutvới một số BorderLayoutBoxLayout, làm tổ khi thuận tiện. Đây là một sự kết hợp mạnh mẽ và dễ sử dụng.
Loduwijk

Tôi đã vội vàng trong nhận xét trên của tôi. Đây là câu trả lời đầu tiên tôi thấy sau câu trả lời được chấp nhận. Tại sao SO không sắp xếp theo số phiếu nữa? Tôi nghĩ rằng đó là một trong những lý do cốt lõi để kiểm phiếu ban đầu. Tuy nhiên, tôi vẫn đứng theo nhận xét ban đầu; đây là một trong những câu trả lời tốt hơn Ngoại trừ điểm 6 của nó - cái đó không tuyệt vời bằng. Có rất nhiều lý do (thiểu số vẫn có thể là một số lượng lớn) lý do để thay đổi kích thước và GridBagLayout hỗ trợ tốt trong hầu hết các trường hợp tôi đã có.
Loduwijk

Tôi nghĩ thay đổi kích thước so với không thay đổi kích thước sẽ không được coi là một quyết định tôn giáo. Có những trường hợp sử dụng khi không ai muốn thay đổi kích thước bất cứ thứ gì, ví dụ nếu bạn phát triển GUI cho kiosk, với độ phân giải cố định được đặt trước. Nếu bạn có các mục tiêu khác nhau, chẳng hạn như màn hình HMI công nghiệp và trường hợp "nút", thì vâng, bạn phải có ít nhất 1cm x 1cm cho một nút trên màn hình cảm ứng. Trong trường hợp này, DPI của màn hình sẽ đặt cách bạn thay đổi kích thước. Các đầu vào khác như trường văn bản hoàn toàn không thể thay đổi kích thước theo chiều dọc và đôi khi (chẳng hạn như mã zip) thay đổi kích thước ngang cũng vô nghĩa.
Gee Bee

0

Tôi có nên tránh hoàn toàn việc sử dụng các phương pháp đó? Tôi sẽ không nói "tránh" chúng. Tôi muốn nói rằng nếu bạn nghĩ rằng bạn cần họ, có lẽ bạn đã làm sai điều gì đó. Kích thước thành phần được xác định trong bối cảnh. Ví dụ: Kích thước thành phần Văn bản được xác định theo số lượng hàng và cột bạn chỉ định, kết hợp với phông chữ bạn có thể đã chọn. Nút và kích thước nhãn của bạn sẽ là kích thước của đồ họa, nếu bạn đặt một hoặc không gian cần thiết để hiển thị văn bản bạn đặt. Mỗi thành phần có kích thước tự nhiên và trình quản lý bố cục sẽ sử dụng các kích thước đó để bố trí mọi thứ mà không cần bạn chỉ định kích thước. Ngoại lệ chính là JScrollPane, có kích thước độc lập với bất cứ thứ gì nó chứa. Đối với những người đó, đôi khi tôi sẽ gọi setSize()và để kích thước đó xác định kích thước cửa sổ ban đầu, bằng cách gọiJFrame.pack(). Thông thường, tôi sẽ để kích thước cửa sổ xác định kích thước JScrollPane. Người dùng sẽ xác định kích thước của cửa sổ. Nhiều trình quản lý bố cục bỏ qua các kích thước bạn đặt, vì vậy chúng thường không hoạt động tốt.

Các phương pháp đã được xác định cho một lý do. Vậy khi nào tôi nên sử dụng chúng? Trong bối cảnh nào? Vì mục đích gì? Tôi tin rằng họ đã được thêm vào để cung cấp gợi ý cho các nhà quản lý bố trí. Chúng có thể đã được viết vì lý do lịch sử, bởi vì các trình quản lý bố cục là mới và mọi người không hoàn toàn tin tưởng chúng. Tôi biết một vài nhà phát triển đã tránh các trình quản lý bố cục và đặt mọi thứ theo cách thủ công, chỉ vì họ không muốn bận tâm đến việc học một mô hình mới. Đó là một ý tưởng khủng khiếp.

Chính xác những hậu quả tiêu cực của việc sử dụng các phương pháp đó là gì? (Tôi chỉ có thể nghĩ thêm tính di động giữa các hệ thống có độ phân giải màn hình khác nhau). Chúng không hiệu quả, và chúng tạo ra bố cục xấu, với các vật thể bị ép hoặc kéo dài đến kích thước không tự nhiên. Và các bố trí sẽ giòn. Thay đổi kích thước cửa sổ đôi khi sẽ phá vỡ bố cục và đặt mọi thứ ở sai vị trí.

Tôi không nghĩ rằng bất kỳ LayoutManager nào có thể đáp ứng chính xác tất cả các nhu cầu bố trí mong muốn. Tôi có thực sự cần phải triển khai một Trình quản lý bố cục mới cho mỗi biến thể nhỏ trên bố cục của mình không? Bạn không nên "triển khai" một Trình quản lý bố cục mới. Bạn nên khởi tạo những cái hiện có. Tôi thường sử dụng một số trình quản lý bố cục trong một cửa sổ duy nhất. Mỗi JPanel sẽ có trình quản lý bố cục riêng. Một số người chùn bước tại các bố cục lồng nhau, vì họ khó duy trì. Khi tôi sử dụng chúng, tôi cung cấp cho mỗi người một phương pháp sáng tạo riêng để dễ dàng xem những gì mỗi người làm. Nhưng tôi không bao giờ "thực hiện" một trình quản lý bố cục. Tôi chỉ cần khởi tạo chúng.

Nếu câu trả lời cho 4 là "có", điều này sẽ không dẫn đến sự phổ biến của các lớp LayoutManager sẽ trở nên khó duy trì? Nếu bạn đang triển khai các lớp trình quản lý bố cục mới cho các thay đổi nhỏ trong bố cục, thì bạn đang sử dụng chúng sai. Nếu bạn chỉ thực hiện các trình quản lý bố cục mới, có lẽ bạn đã làm sai điều gì đó. Lần duy nhất tôi đã mở rộng một lớp LayoutManager, đó là thêm một thanh trượt thu phóng vào một JScrollPane.

Trong tình huống tôi cần xác định tỷ lệ giữa các con của Thành phần (ví dụ: child1 nên sử dụng 10% dung lượng, child2 40%, child3 50%), có thể đạt được điều đó mà không cần thực hiện Trình quản lý bố cục tùy chỉnh không? JSplitPane có cách chỉ định tỷ lệ phần trăm mà mỗi thành phần sẽ nhận được. Bộ chia có thể di chuyển theo mặc định, nhưng bạn có thể tắt nó nếu bạn muốn. Tôi không sử dụng tính năng đó nhiều. Tôi thường có một số thành phần chiếm kích thước đã đặt và phần còn lại của không gian được chiếm bởi một ngăn cuộn. Kích thước khung cuộn sẽ điều chỉnh với kích thước cửa sổ. Nếu bạn có hai tấm cuộn cạnh nhau, bạn có thể đặt chúng vào một JSplitPane và chỉ định tỷ lệ phần trăm không gian mới được cung cấp cho mỗi cái khi người dùng mở rộng và ký hợp đồng với các cửa sổ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.