带换行的 JTextArea 向 JDialog 包报告不正确的首选大小?
JTextArea with line wrap reports incorrect preferred size to JDialog pack?
我使用多个 JTextAreas 来显示可变大小的文本,LineWrap 和 WrapStyleWord 都为真。它的一个应用是在 JScrollPane 中显示一个带有多个这些文本区域的 JDialog。包含所有这些文本区域的面板实现了 Scrollable(如 here 所述),允许 JDialog 具有最大尺寸,但仍会缩小。但是,JDialog 具有固定的水平尺寸。水平滚动条被强制永不出现,垂直滚动条不应出现,除非对话框达到其最大尺寸。但是,在 JTextArea 换行的情况下,当 JDialog 的高度小于其最大值时,会出现垂直滚动条。问题似乎是,当 JDialog 被打包时,JTextArea 报告了一行的首选高度,导致对话框的高度小于面板的高度,因为文本区域占据了不止一行。
这似乎是一个陷阱 22,为了获得文本区域的适当高度,需要将其添加到具有所需宽度的面板中以计算换行,这将允许计算实际行数(使用找到的方法 here)。但是 JDialog 在调用 pack 之前需要一个首选大小(据我所知),这导致了这个问题。演示问题:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Scrollable;
public class DisplayPopup extends JDialog {
public DisplayPopup() {
JPanel actual = new JPanel();
actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
actual.setOpaque(false);
JTextArea jta = new JTextArea();
jta.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ac dictum magna. Nam sed mattis sem. Donec tortor felis, finibus in lectus fringilla, semper finibus turpis. ");
jta.setFont(new java.awt.Font("Arial", 0, 18));
jta.setForeground(new java.awt.Color(204, 204, 204));
jta.setLineWrap(true);
jta.setWrapStyleWord(true);
jta.setEditable(false);
jta.setBackground(new Color(45,45,45));
jta.setHighlighter(null);
actual.add(jta);
PopupScroll ps = new PopupScroll(actual);
JScrollPane scroll = new JScrollPane();
scroll.getViewport().add(ps);
setModalityType(java.awt.Dialog.ModalityType.MODELESS);
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(scroll);
pack();
}
public static void launch() {
DisplayPopup dp = new DisplayPopup();
dp.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(DisplayPopup::launch);
}
private class PopupScroll extends JPanel implements Scrollable {
public PopupScroll(JPanel jp) {
setBackground(Color.PINK);
setLayout(new BorderLayout());
add(jp);
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(500,Math.min((int)getPreferredSize().getHeight(),700));
}
@Override
public int getScrollableUnitIncrement(Rectangle arg0, int arg1, int arg2) {
return 1;
}
@Override
public int getScrollableBlockIncrement(Rectangle arg0, int arg1, int arg2) {
return 1;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
}
对话框的大小无法包含所有文本行。与类似问题的 this 解决方案不同,调用 pack 并不能解决问题。我对解决方案有一些猜测,也许使用 JTextArea 之外的东西(因为我只是想显示文本......?),但我不知道那会是什么。我已经尝试在垂直滚动条上放置一个层次结构侦听器,这样我就可以在不使对话框可见的情况下检测它何时处于活动状态,但这没有用。这是一个难题还是我遗漏了一些明显的东西?
进行了一些更改,我看到文本显示在 3 行上:
pack();
pack();
是的,我添加了第二个 pack()。第一包似乎识别宽度,第二包导致文本被换行。
然而,我也不得不改变:
//actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
actual.setLayout(new BorderLayout());
我知道您并不是真的想使用 BorderLayout(因为您希望多个组件垂直对齐),但不知为何它的首选尺寸计算似乎可行。
您可以使用 GridBagLayout
而不是 BoxLayout。它允许您指定 "fill" 约束。我猜你会尝试只使用水平填充。
或者另一种选择是使用 Relative Layout。我会比 GridBagLayout 更容易,因为您不需要担心任何约束。使用它的代码是:
//actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true );
actual.setLayout( rl );
我使用多个 JTextAreas 来显示可变大小的文本,LineWrap 和 WrapStyleWord 都为真。它的一个应用是在 JScrollPane 中显示一个带有多个这些文本区域的 JDialog。包含所有这些文本区域的面板实现了 Scrollable(如 here 所述),允许 JDialog 具有最大尺寸,但仍会缩小。但是,JDialog 具有固定的水平尺寸。水平滚动条被强制永不出现,垂直滚动条不应出现,除非对话框达到其最大尺寸。但是,在 JTextArea 换行的情况下,当 JDialog 的高度小于其最大值时,会出现垂直滚动条。问题似乎是,当 JDialog 被打包时,JTextArea 报告了一行的首选高度,导致对话框的高度小于面板的高度,因为文本区域占据了不止一行。
这似乎是一个陷阱 22,为了获得文本区域的适当高度,需要将其添加到具有所需宽度的面板中以计算换行,这将允许计算实际行数(使用找到的方法 here)。但是 JDialog 在调用 pack 之前需要一个首选大小(据我所知),这导致了这个问题。演示问题:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Scrollable;
public class DisplayPopup extends JDialog {
public DisplayPopup() {
JPanel actual = new JPanel();
actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
actual.setOpaque(false);
JTextArea jta = new JTextArea();
jta.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ac dictum magna. Nam sed mattis sem. Donec tortor felis, finibus in lectus fringilla, semper finibus turpis. ");
jta.setFont(new java.awt.Font("Arial", 0, 18));
jta.setForeground(new java.awt.Color(204, 204, 204));
jta.setLineWrap(true);
jta.setWrapStyleWord(true);
jta.setEditable(false);
jta.setBackground(new Color(45,45,45));
jta.setHighlighter(null);
actual.add(jta);
PopupScroll ps = new PopupScroll(actual);
JScrollPane scroll = new JScrollPane();
scroll.getViewport().add(ps);
setModalityType(java.awt.Dialog.ModalityType.MODELESS);
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(scroll);
pack();
}
public static void launch() {
DisplayPopup dp = new DisplayPopup();
dp.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(DisplayPopup::launch);
}
private class PopupScroll extends JPanel implements Scrollable {
public PopupScroll(JPanel jp) {
setBackground(Color.PINK);
setLayout(new BorderLayout());
add(jp);
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(500,Math.min((int)getPreferredSize().getHeight(),700));
}
@Override
public int getScrollableUnitIncrement(Rectangle arg0, int arg1, int arg2) {
return 1;
}
@Override
public int getScrollableBlockIncrement(Rectangle arg0, int arg1, int arg2) {
return 1;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
}
对话框的大小无法包含所有文本行。与类似问题的 this 解决方案不同,调用 pack 并不能解决问题。我对解决方案有一些猜测,也许使用 JTextArea 之外的东西(因为我只是想显示文本......?),但我不知道那会是什么。我已经尝试在垂直滚动条上放置一个层次结构侦听器,这样我就可以在不使对话框可见的情况下检测它何时处于活动状态,但这没有用。这是一个难题还是我遗漏了一些明显的东西?
进行了一些更改,我看到文本显示在 3 行上:
pack();
pack();
是的,我添加了第二个 pack()。第一包似乎识别宽度,第二包导致文本被换行。
然而,我也不得不改变:
//actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
actual.setLayout(new BorderLayout());
我知道您并不是真的想使用 BorderLayout(因为您希望多个组件垂直对齐),但不知为何它的首选尺寸计算似乎可行。
您可以使用 GridBagLayout
而不是 BoxLayout。它允许您指定 "fill" 约束。我猜你会尝试只使用水平填充。
或者另一种选择是使用 Relative Layout。我会比 GridBagLayout 更容易,因为您不需要担心任何约束。使用它的代码是:
//actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true );
actual.setLayout( rl );