[英]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件事的組合。
將面向首選大小的布局管理器與具有非常大的首選大小的組件組合在一起通常會導致此問題。 我沒有進行過廣泛的測試,但我知道它也會在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.