如何计算 JTextArea 中文本所占的行数(以及每行中的列数)?
对 问题 我尝试了几次但失败了,我不喜欢这样:)
我认为如果将问题分解为子问题可能有助于解决它。
为了简单起见,我们假设 JTextArea 不会改变其大小,因此我们不需要担心重新评估等问题。我认为重要的问题是:
1.如何计算某个文本在 JTextArea 中所占的行数?
2. JTextArea 中的列数和行中可以容纳的字符数之间有什么关系?这样我们就可以计算出行的长度。
请在下面找到包含要处理的文本区域的示例代码:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class TextAreaLines
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
JPanel p = new JPanel();
JFrame f = new JFrame();
JTextArea ta = new JTextArea("dadsad sasdasdasdasdasd");
ta.setWrapStyleWord(true);
ta.setLineWrap(true);
ta.setRows(5);
ta.setColumns(5);
p.add(ta);
f.setContentPane(p);
f.setSize(400, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
//BTW the code below prints 1
System.out.println("ta.getLineCount()="+ta.getLineCount());
}
});
}
}
EDIT1: 所以我想出了以下代码,但问题是输出不是您所看到的,即
//for input
//JTextArea ta = new JTextArea("alfred abcdefghijklmnoprstuwvxyz abcdefg");
//we have output
//s=alfred abcdefghijk
//s=lmnoprstuwvxyz a
//s=bcdefg
FontMetrics fm = ta.getFontMetrics(ta.getFont());
String text = ta.getText();
List<String> texts = new ArrayList<String>();
String line = "";
//no word wrap
for(int i = 0;i < text.length(); i++)
{
char c = text.charAt(i);
if(fm.stringWidth(line +c) <= ta.getPreferredSize().width)
{
//System.out.println("in; line+c ="+(line + c));
line += c;
}
else
{
texts.add(line);//store the text
line = ""+c;//empty the line, add the last char
}
}
texts.add(line);
for(String s: texts)
System.out.println("s="+s);
我在做什么错了,我忘记了什么?文本区域没有自动换行。
EDIT2:@trashgod 这是我得到的输出。由此可见,我们有不同的默认字体。事实上,问题可能与字体有关,甚至与系统有关。 (PS:我是Win7)。
line: Twas brillig and the slithy tovesD
line: id gyre and gimble in the wabe;
line count: 2
preferred: java.awt.Dimension[width=179,height=48]
bounds1: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.064453,w=170.0,h=15.09375]
layout1: java.awt.geom.Rectangle2D$Float[x=0.28125,y=-8.59375,w=168.25,h=11.125]
bounds2: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.064453,w=179.0,h=15.09375]
layout2: java.awt.geom.Rectangle2D$Float[x=0.921875,y=-8.59375,w=177.34375,h=11.125]
在我的脑海中整理一下你们所有人的想法,我认为可能可靠的解决方案可能是破解文本区域设置文本的方式,并完全控制它。通过运行该区域的 setText 中的算法(请注意上面的算法,请注意,按照 @trashgod 的建议,“<”已更改为“<=”)。
是什么让我这样想......例如,如果您在我提供的示例中 将文本区域的文本更改为 JTextArea ta = new JTextArea("alfred abcdefghijkl\nmnoprstuwvxyz ab\ncdefg"); 因为它是在我的情况下计算的,那么它将完美地适合文本区域。
EDIT3:这是我很快破解的一种解决方案,至少现在显示的字符和计算的完全一样。其他人可以检查一下并告诉我它在除 Win7 之外的其他计算机上的工作原理吗?下面的示例已准备好使用,您应该能够调整窗口大小并获得与您所看到的相同的行的打印输出。
import java.awt.BorderLayout;
import java.awt.FontMetrics;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class TextAreaLines
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
JPanel p = new JPanel(new BorderLayout());
JFrame f = new JFrame();
final JTextArea ta = new JTextArea("alfred abcdefghijklmnoprstuwvxyz abcdefg");
ta.addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent e)
{
super.componentResized(e);
System.out.println("ta componentResized");
reformatTextAreaText(ta);
}
});
//ta.setWrapStyleWord(true);
ta.setLineWrap(true);
p.add(ta);
f.setContentPane(p);
f.setSize(200, 100);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
private void reformatTextAreaText(JTextArea ta)
{
String text = ta.getText();
//remove all new line characters since we want to control line braking
text = text.replaceAll("\n", "");
FontMetrics fm = ta.getFontMetrics(ta.getFont());
List<String> texts = new ArrayList<String>();
String line = "";
//no word wrap
for(int i = 0; i < text.length(); i++)
{
char c = text.charAt(i);
if(fm.stringWidth(line + c) <= ta.getPreferredSize().width)
{
//System.out.println("in; line+c ="+(line + c));
line += c;
}
else
{
texts.add(line);//store the text
line = "" + c;//empty the line, add the last char
}
}
texts.add(line);
//print out of the lines
for(String s : texts)
System.out.println("s=" + s);
//build newText for the
String newText = "";
for(String s : texts)
newText += s + "\n";
ta.setText(newText);
}
});
}
}
提前致谢。
After getting interested in the problem presented in the question
I tried to approach it few times and failed, and I do not like that :)
I think if the problem was split into sub issues it might help to solve it.
For simplicity lets assume the JTextArea will not change its size, so we do not need to worry about re-evaluation etc. I think the important issues are:
1.How to calculate the number of rows a certain text takes in a JTextArea?
2.What is the relation between the number of columns in a JTextArea and a number of characters it can fit in a row? So we can calculate row length.
Please find included below the sample code presenting the text area to process:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class TextAreaLines
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
JPanel p = new JPanel();
JFrame f = new JFrame();
JTextArea ta = new JTextArea("dadsad sasdasdasdasdasd");
ta.setWrapStyleWord(true);
ta.setLineWrap(true);
ta.setRows(5);
ta.setColumns(5);
p.add(ta);
f.setContentPane(p);
f.setSize(400, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
//BTW the code below prints 1
System.out.println("ta.getLineCount()="+ta.getLineCount());
}
});
}
}
EDIT1: So I have come up with the following code but the problem is that the output is not what you see, i.e
//for input
//JTextArea ta = new JTextArea("alfred abcdefghijklmnoprstuwvxyz abcdefg");
//we have output
//s=alfred abcdefghijk
//s=lmnoprstuwvxyz a
//s=bcdefg
FontMetrics fm = ta.getFontMetrics(ta.getFont());
String text = ta.getText();
List<String> texts = new ArrayList<String>();
String line = "";
//no word wrap
for(int i = 0;i < text.length(); i++)
{
char c = text.charAt(i);
if(fm.stringWidth(line +c) <= ta.getPreferredSize().width)
{
//System.out.println("in; line+c ="+(line + c));
line += c;
}
else
{
texts.add(line);//store the text
line = ""+c;//empty the line, add the last char
}
}
texts.add(line);
for(String s: texts)
System.out.println("s="+s);
What am I doing wrong, what am I forgetting about? There is no word wrap on the text area.
EDIT2: @trashgod This is the output I am getting. Apparent from this is that we have different default fonts. And the problem in fact might be either font or even system dependent. (PS: I am on Win7).
line: Twas brillig and the slithy tovesD
line: id gyre and gimble in the wabe;
line count: 2
preferred: java.awt.Dimension[width=179,height=48]
bounds1: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.064453,w=170.0,h=15.09375]
layout1: java.awt.geom.Rectangle2D$Float[x=0.28125,y=-8.59375,w=168.25,h=11.125]
bounds2: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.064453,w=179.0,h=15.09375]
layout2: java.awt.geom.Rectangle2D$Float[x=0.921875,y=-8.59375,w=177.34375,h=11.125]
Compiling in my head what all of you guys are saying I think that the possibly reliable solution might be to hack the way in which the text area sets its text, and take a full control over it. By running the algorithm (above one, please notice, as suggested by @trashgod the '<' was changed to '<=') in the setText of the area.
What got me to think like this... for example in the sample I have provided if you
change text of the textarea to JTextArea ta = new JTextArea("alfred abcdefghijkl\nmnoprstuwvxyz ab\ncdefg");
as it is calculated in my case then it will fit perfectly into the textarea.
EDIT3: This is a kind of solution I quickly hacked, at least now the shown characters and calculated are exactly the same. Can someone else please check it out and let me know, possibly how it works on other machine then Win7? The example below is ready to use you should be able to resize the window and get the printout of lines the same as you see.
import java.awt.BorderLayout;
import java.awt.FontMetrics;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class TextAreaLines
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
JPanel p = new JPanel(new BorderLayout());
JFrame f = new JFrame();
final JTextArea ta = new JTextArea("alfred abcdefghijklmnoprstuwvxyz abcdefg");
ta.addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent e)
{
super.componentResized(e);
System.out.println("ta componentResized");
reformatTextAreaText(ta);
}
});
//ta.setWrapStyleWord(true);
ta.setLineWrap(true);
p.add(ta);
f.setContentPane(p);
f.setSize(200, 100);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
private void reformatTextAreaText(JTextArea ta)
{
String text = ta.getText();
//remove all new line characters since we want to control line braking
text = text.replaceAll("\n", "");
FontMetrics fm = ta.getFontMetrics(ta.getFont());
List<String> texts = new ArrayList<String>();
String line = "";
//no word wrap
for(int i = 0; i < text.length(); i++)
{
char c = text.charAt(i);
if(fm.stringWidth(line + c) <= ta.getPreferredSize().width)
{
//System.out.println("in; line+c ="+(line + c));
line += c;
}
else
{
texts.add(line);//store the text
line = "" + c;//empty the line, add the last char
}
}
texts.add(line);
//print out of the lines
for(String s : texts)
System.out.println("s=" + s);
//build newText for the
String newText = "";
for(String s : texts)
newText += s + "\n";
ta.setText(newText);
}
});
}
}
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
不确定这是否有帮助,但您需要设置文本区域的宽度,以便视图知道何时换行文本。设置尺寸后,您可以确定首选高度。当您知道首选高度时,您可以使用字体公制行高来确定总行数,包括换行(如果有)。
Not sure if this helps but you need to set the width of the text area so that the view knows when to wrap the text. Once you set the size you can determine the preferred height. When you know the preferred height you can use the font metrice line height to determine the total number of lines including the wrapped lines if any.
我见过人们使用
TextLayout< /code>
对于这样的事情。
I've seen people using
TextLayout
for something like this.好的,我编写了一个程序,您可以加载图像,并将其转换为 ascii 艺术。我希望它根据输入的图像自动使文本区域具有正确的宽高比。
然而,我永远无法让它正常工作。我放弃了并指出了我的尝试,这是我尝试过的片段。我最终所做的只是有一个有时没有完全填满的文本区域。
Okay, I had written a program that you could load in an image, and it would convert it to ascii art. I wanted it to automatically make the text area the right aspect ration based on the image that was input.
However, I could never get it to work quite right. I gave up and remarked out my attempts, here is the snippet of what I tried. What I ended up doing was just having a textarea that sometimes didn't fill all the way.
昨天android也有类似的问题。我认为需要解决的方法是通过迭代方法:
不幸的是,行长度将取决于字体和特定字符串(并非每个字符都具有相同的宽度)。您可以计算每次迭代中单词中的字符数,并返回长度数组或长度平均值。
这是相关的android问题:如何查找 android TextView 每行的字符数?
There was a similar question for android yesterday. The way I see it need to be solved is by an iterative approach:
Unfortunately, row length will depend on the font and the particular string (not every character as the same width). You can count the number of characters in the words in each iteration, and return an array of lengths or a length average.
This is the related android question: How to find android TextView number of characters per line?
我发现通过文本分析来计算行数只会导致任何结果。相反,我的解决方案是根据文本区域的首选大小来计算它......
I found that counting the number of lines by text analysis only led to nothing. Instead my solution was calculating it from the preferred size of the text area ...
没什么,真的。我修改了您的示例以在宽度上使用“<=”并突出显示一些功能:
FontMetrics
指出,“String
的进步不一定是单独测量的字符进步的总和......”< /p>文本组件的首选大小与最宽行的度量边界非常匹配。由于比例间距,这会因字体而异。
TextLayout
显示甚至更严格的界限,但请注意“基线相对坐标”。getLineCount()
方法对line.separator
分隔行进行计数,而不是换行。Nothing, really. I modified your example to use "<=" on the width and to highlight a few features:
FontMetrics
notes, "the advance of aString
is not necessarily the sum of the advances of its characters measured in isolation…"The preferred size of the text component matches the metric bounds pretty well for the widest line. This varies by font due to proportional spacing.
TextLayout
shows even tighter bounds, but note the "baseline-relative coordinates."The
getLineCount()
method countsline.separator
delimited lines, not wrapped lines.您可以做的一件事是使用
FontMetrics
。我编写了一些代码,用于在某些行号处拆分 JTextArea。设置代码如下所示:这将告诉您一行文本有多高。
不幸的是,大多数字体中的字母具有不同的宽度。但是,您可以使用以下代码来确定字符串的宽度。
我知道这并不能完全回答您的问题,但希望对您有所帮助。
如果您不使用自动换行,则可以使用以下通用算法:(在绘制组件方法中)
这就是总体思路。不确定效果如何。如果您尝试一下,请告诉我。
One thing you can do is use
FontMetrics
. I wrote some code for splittingJTextArea
s up at certain line numbers. The setup code looked like:This will tell you how tall a line of text is.
Unfortunately, letters have different widths in most fonts. But, you can use the following code to determine the width of a String.
I know this doesn't fully answer your question, but I hope it helps.
If you aren't using word wrap, here is the general algorithm you could use: (in the paint component method)
That's the general idea. Not sure how well it would work out. Let me know if you try it.