簡體   English   中英

為什么我的JTextArea溢出GroupLayout中的幀?

[英]Why does my JTextArea overflow the frame in GroupLayout?

我正在使用GroupLayout觀察一些奇怪的行為。 我有一個包含在JScrollPane中的JTextArea,它正在調整大小並將其他組件推出JFrame。 奇怪的是,如果我重新排列布局,以便JTextArea上面或下面沒有任何東西(也沒有間隙),它可以正常工作。 就好像文本區域向容器詢問容器中有多少空間,然后占用100%的空間,而不管其他組件。 另一個奇怪的事情是它似乎只有當JTextArea(而不是JScrollPane)大小加上容器內的其他組件高度達到Short.MAX_VALUE時才會發生。

如果我將滾動窗格的垂直組中的最大大小(將組件添加到布局時)指定為小於Short.MAX_VALUE的值,則似乎可以解決問題(只要值與Short之間的差異。 MAX_VALUE大於所有其他組件的高度)。 例如

.addComponent(textArea, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE - 500)

此外,如果我將首選大小設置為一個小的正值而不是GroupLayout.PREFERRED_SIZE或GroupLayout.DEFAULT_SIZE,它似乎也會使這種行為消失。 例如

.addComponent(textArea, 0, 1, Short.MAX_VALUE)

GroupLayout上的Java教程似乎沒有提及任何相關內容,並傾向於在整個地方使用Short.MAX_VALUE。 我嘗試使用谷歌搜索來找到答案,但我發現這個問題在搜索術語中很難描述。

我發現了一個錯誤,還是我不了解GroupLayout? 后者肯定似乎更有可能。

此示例將創建一個簡單的文本區域。 按下按鈕以使用文本填充它(並調整JScrollPane內的JTextArea的大小)。 然后,您可以在文本區域內單擊並添加或刪除行。 添加一些額外的行后,單擊重繪按鈕(或調整框架大小)以查看奇怪的行為。

public class GroupLayoutTest {
    public GroupLayoutTest() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                final JFrame frame = new JFrame("GroupLayout test");
                Container panel = frame.getContentPane();

                GroupLayout layout = new GroupLayout(panel);
                panel.setLayout(layout);

                JButton addBtn = new JButton("Add Lines");
                JButton redrawBtn = new JButton("Redraw");

                final JTextArea textArea = new JTextArea();
                final JScrollPane textPane = new JScrollPane(textArea);

                layout.setHorizontalGroup(layout.createParallelGroup()
                        .addComponent(redrawBtn)
                        .addComponent(textPane)
                        .addComponent(addBtn));

                layout.setVerticalGroup(layout.createSequentialGroup()
                        .addComponent(redrawBtn)
                        .addComponent(textPane)
                        .addComponent(addBtn));

                addBtn.addActionListener(new ActionListener() {
                    int m = 0;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        for (int i = m; m < i + 2044; ++m) {
                            textArea.append("Line " + m + "\n");
                        }

                        // redraw the frame
                        frame.validate();
                    }
                });

                redrawBtn.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        frame.validate();
                    }
                });

                frame.setPreferredSize(new Dimension(640, 480));
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static void main(String[] args) {
        new GroupLayoutTest();
    }
}

我對GroupLayout並不熟悉,這正是我從查看文檔和思考它時所觀察到的。 希望它有用。 我的答案有點長,所以我總結一下:

為什么會這樣? 3件事的組合。

  1. GroupLayout尊重組件的首選大小。 (這就是你選擇它的原因,根據你的評論判斷)。
  2. 您的垂直組是順序的。 它一次布置一個組件 - 按其首選大小,如果有空間則更大。
  3. 您的JScrollPane具有無限制的首選大小。 無論JTextArea的首選大小是什么,它都會增長......一旦它的首選大小變得大於你的框架,它就不會留下它下面的組件。

將面向首選大小的布局管理器與具有非常大的首選大小的組件組​​合在一起通常會導致此問題。 我沒有進行過廣泛的測試,但我知道它也會在FormLayout中發生(如果你告訴它使用首選大小)。

更長時間嘗試解釋/思考過程:

就好像文本區域向容器詢問容器中有多少空間,然后占用100%的空間,而不管其他組件。

文本區域不是要求容器有多大 - 它是相反的 - 它告訴容器它想要多大。 在這種情況下,textArea直接包含在滾動窗格中。 文本區域的首選大小將隨着文本區域中文本的大小而增長。 除非您在滾動窗格上設置首選大小,否則滾動窗格的首選大小將隨文本區域的首選大小增長。 從那里,布局經理將決定如何解決問題。

在這種情況下,您使用具有SequentialGroup的GroupLayout作為垂直布局。 這將基於它們的min / pref / max尺寸按順序布置組件。 如果將textPane重新定位為組中的最后一項,則不會從其他組件中竊取空間...所以我的猜測是,對於非常大的大小,GroupLayout並不關心是否顯示所有組件 - 如果最后一個組件后沒有剩余空間,直到容器放大后才會顯示它們。 對於小尺寸,用戶可以調整框架的大小......但是對於像您的示例中那樣的大尺寸,這是不可行的。

與遺漏分開 - 它看起來只是一個巨大的滾動窗格和GroupLayout的組合,不知道何時停止...所以滾動窗格欄的底部被切斷。 這可以通過在JScrollPane上設置合理的首選大小來避免,但是,正如@camickr建議的那樣。

另一個奇怪的事情是它似乎只有當JTextArea(而不是JScrollPane)大小加上容器內的其他組件高度達到Short.MAX_VALUE時才會發生。

如果你記錄每個組件的大小,你會看到,除非你為JScrollPane指定一個首選大小,它的首選大小總是大於textArea的大小,所以我不認為上面的語句是真的。 滾動窗格的大小加上容器中的其他組件仍然會超過Short.MAX_VALUE,並且確實會導致GroupLayout出現問題,這是真的。

我認為JScrollPane的目的是在一個包含的較小區域中容納一個具有較大(或可能較大)的首選大小的組件(適當時使用滾動條)。 然后,您可以始終讓滾動窗​​格增大到大於其首選大小的大小...但它首先告訴滾動窗格它應該有多大。 事實上,設置首選大小有效地告訴JScrollPane何時需要滾動條。 例如,如果滾動窗格的首選大小為400,300,那么每當所包含組件的首選寬度超過400(或滾動窗格的大小時,如果它位於容器中,使其增長到超過其首選大小) ,顯示水平滾動條。 同樣,對於身高也是如此。 否則它總是會增長到你所擁有的大小,並且它不需要滾動條,消除了這一點,或者在某些情況下,阻止了其他組件的顯示。

GroupLayout的文檔提到它通常被其他布局構建器工具使用,而不是通常由開發人員使用(盡管你仍然可以)。 我會考慮使用不同的布局,通常要求您使用特殊的最大值才能正常工作。 我個人最喜歡的是FormLayout ,一個免費的,BSD許可的第三方布局管理器。 我認為您不應該為普通組件指定固定大小,但是對於滾動窗格,您確實希望在布局中為其指定首選大小。

我希望我的所有布局都尊重DPI,適當增長,並且在國際化(文本長度可能非常不同)的情況下工作得很好......所以我不想使用任何需要為所有內容指定固定大小的東西。 我認為在大多數布局中,在滾動窗格上設置固定的首選大小並不是一件壞事。 在按鈕,文本字段或其他明顯具有明顯首選大小的組件上這樣做,而不是這樣。

下面是它在FormLayout中的外觀(它也有構建器,但在這種情況下,我使用單元格約束來輕松地跨列):

FormLayout layout = new FormLayout(
      "pref,fill:pref:grow", // cols
      "pref,3dlu,fill:pref:grow,3dlu,pref" // rows
);

JPanel panel = new JPanel(layout);

CellConstraints cc = new CellConstraints();

panel.add(redrawBtn, cc.xy(1, 1));
panel.add(textPane, cc.xyw(1, 3, 2)); // span 2 columns
panel.add(addBtn, cc.xy(1, 5));

frame.setContentPane(panel);

我不知道GroupLayout的內部,但通常你需要指定textArea / scrollpane組合的首選大小,以給布局管理器一些信息。 這可以通過以下任一方式完成:

final JTextArea textArea = new JTextArea(10, 30);

要么

textPane.setPreferredSize( new Dimension(400, 200) );

否則我認為首選大小基本上是添加到文本區域的所有文本的大小。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM