如何创建具有指定宽度和显示所有文本所需的最小高度的 JTextArea?
Posted
技术标签:
【中文标题】如何创建具有指定宽度和显示所有文本所需的最小高度的 JTextArea?【英文标题】:How can I create a JTextArea with a specified width and the smallest possible height required to display all the text? 【发布时间】:2011-05-04 06:09:10 【问题描述】:在我能找到的所有使用JTextArea
的示例中,高度和宽度在构造JTextArea
之前是已知的,如果JTextArea
需要更多高度,则将其放在@ 内987654324@。显然,JTextArea
的高度取决于宽度和文本内容。
现在,我的情况要求我不使用JScrollPane
,而是让JTextArea
足够高以显示所有文本。当我创建JTextArea
时,我知道文本内容以及它必须使用的宽度;我不知道高度 - 我希望它尽可能小而不切断任何文本。这似乎很难实现。
附带说明,JTextArea
将添加到没有布局管理器的 JPanel
- 它使用基于添加组件的首选大小的绝对定位。这要求我的JTextArea
将在getPreferredSize()
上返回正确的尺寸。正确的尺寸应该是我在构建它时提供的宽度,以及以提供的宽度显示所有文本所需的最小高度。
我发现了一些类似的线程来讨论与 JTextArea
相关的奇怪/错误,有时可以通过在父容器上调用两次 pack()
来解决这些问题。这不是我的选择。我很想创建自己的JTextArea
,它采用宽度和字符串,并根据宽度和字体设置计算必要的最小高度,但我想在花时间这样做之前我会先询问一下。
希望我的问题很清楚。谢谢大家的帮助!
【问题讨论】:
JLabel 会代替 JTextArea 吗? @Andrew Thompson 当然,我可以使用JLabel
,但是我仍然需要手动在字符串中插入换行符,这需要我根据宽度计算它们应该在哪里和字体设置,然后我必须添加一些特殊处理以使其包含整个单词而不是字符。这些是JTextArea
提供的东西,所以如果可以的话,我更愿意使用它。
见下面的例子。我喜欢使用一点“html 技巧”来实现这样的事情。 ;)
【参考方案1】:
它使用基于添加组件的首选大小的绝对定位。
听起来像是布局管理器的工作。
这要求我的 JTextArea 在 getPreferredSize() 上返回正确的尺寸。
JTextArea textArea = new JTextArea();
textArea.setLineWrap( true );
textArea.setWrapStyleWord( true );
textArea.setText("one two three four five six seven eight nine ten");
System.out.println("000: " + textArea.getPreferredSize());
textArea.setSize(100, 1);
System.out.println("100: " + textArea.getPreferredSize());
textArea.setSize( textArea.getPreferredSize() );
【讨论】:
我不能使用布局管理器——我都试过了,得出的结论是使用绝对定位更容易。我所说的...it uses absolute positioning based on the added component's preferred size
的意思是这个方法是依赖的,所以它一定是正确的。
哇!这行得通!太感谢了!我从没想过要试试这个。
您不必强制使用单个布局管理器。您可以使用具有不同布局管理器的嵌套面板来完成工作。同样,“根据组件的首选大小确定位置”正是布局管理器的工作。如果您不喜欢现有的布局管理器,请编写自己的。无论如何,这就是您正在做的事情,除非您实现 LayoutManager 接口时,您有一个众所周知的接口可以编写代码。
我知道我可以嵌套布局管理器,事实上这正是我所做的。我降到了一个嵌套级别,没有完全符合我需要的布局管理器,所以我使用了绝对定位。我考虑编写自己的布局管理器,但决定先看看是否可以让它工作,然后再选择是否值得将这个逻辑放入布局管理器中。再次感谢!
对我来说,它回复 000: java.awt.Dimension[width=100,height=16] 100: java.awt.Dimension[width=100,height=48]。我想知道窗口管理器如何处理具有变化的维度的组件,比如显然 JTextFields 可以......【参考方案2】:
import java.awt.*;
import javax.swing.*;
class FixedWidthLabel
public static void main(String[] args)
Runnable r = new Runnable()
public void run()
String pt1 = "<html><body width='";
String pt2 =
"px'><h1>Label Height</h1>" +
"<p>Many Swing components support HTML 3.2 &" +
" (simple) CSS. By setting a body width we can cause the " +
" component to find the natural height needed to display" +
" the component.<br><br>" +
"<p>The body width in this text is set to " +
"";
String pt3 =
" pixels." +
"";
JPanel p = new JPanel( new BorderLayout() );
JLabel l1 = new JLabel( pt1 + "125" + pt2 + "125" + pt3 );
p.add(l1, BorderLayout.WEST);
JLabel l2 = new JLabel( pt1 + "200" + pt2 + "200" + pt3 );
p.add(l2, BorderLayout.CENTER);
JOptionPane.showMessageDialog(null, p);
;
SwingUtilities.invokeLater(r);
【讨论】:
啊啊啊太聪明了!干得好,只需要使用body
标签。【参考方案3】:
FixedWidthLabel 中描述的解决方案,使用<html><body width="..."
将要求程序员提供消息作为 html 字符串的一部分。
如果消息类似于 invalid integer: i<0 not allowed
,
那么<
必须被转义(编码?),否则不知道 JLabel 将如何解释 html。
这增加了该解决方案的复杂性。
只有当您知道消息中不包含任何此类字符时,您才会没事。
【讨论】:
【参考方案4】:好吧,也许如果您知道您的宽度,您可以运行一些测试并计算出文本的每个字符的宽度,这样您就可以使用循环来确定每行可以容纳多少个字符并总计要包含的字符如图所示,那么您可以根据有多少行来设置高度。
假设你的文本有 1000 个字符,包括空格,一个字符的宽度相当于 4 像素,那么你可以计算出如果宽度是 400,每行 100 个字符,那么你需要 10 行。现在说字体大小的高度是 10,你现在知道你需要 10 x 10 == 100 像素,所以你的 TextArea 应该是 400x100
【讨论】:
这种方法不适用于非固定宽度的字体。换行时会出现更多问题,浪费了行尾的一部分。 感谢您的回复,但如前所述,如果我想支持可变大小的字体(我需要),这种方法不太适用。另外,这些都是JTextArea
提供的东西,所以我宁愿不重新发明***。以上是关于如何创建具有指定宽度和显示所有文本所需的最小高度的 JTextArea?的主要内容,如果未能解决你的问题,请参考以下文章
如何计算 NSAttributedString 的高度,给定宽度和行数?