如何计算文本在 JTextArea 中的行数(和每行中的列数)? [英] How to calculate the number of rows (and columns in each row) a text takes in a JTextArea?

查看:31
本文介绍了如何计算文本在 JTextArea 中的行数(和每行中的列数)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在对 问题我试图接近它几次但失败了,我不喜欢那样:)

我认为如果将问题分解为子问题可能有助于解决它.

为简单起见,假设 JTextArea 不会改变其大小,因此我们无需担心重新评估等.我认为重要的问题是:

1.如何计算某个文本在JTextArea中所占的行数?

2.JTextArea 中的列数和它可以容纳在一行中的字符数之间的关系是什么?所以我们可以计算行长.

请在下面找到显示要处理的文本区域的示例代码:

import javax.swing.JFrame;导入 javax.swing.JPanel;导入 javax.swing.JTextArea;导入 javax.swing.SwingUtilities;公共类 TextAreaLines{public static void main(String[] args){SwingUtilities.invokeLater(new Runnable(){@覆盖公共无效运行(){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);//顺便说一句,下面的代码打印 1System.out.println("ta.getLineCount()="+ta.getLineCount());}});}}

所以我想出了下面的代码,但问题是输出不是你看到的,即

//用于输入//JTextArea ta = new JTextArea("alfred abcdefghijklmnoprstuwvxyz abcdefg");//我们有输出//s=alfred abcdefghijk//s=lmnoprstuwvxyz a//s=bcdefgFontMetrics fm = ta.getFontMetrics(ta.getFont());字符串文本 = ta.getText();列表<字符串>texts = new ArrayList();字符串行 = "";//没有自动换行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));线 += c;}别的{texts.add(line);//存储文本line = ""+c;//清空行,添加最后一个字符}}文本.添加(行);for(字符串:文本)System.out.println("s="+s);

我做错了什么,我忘记了什么?文本区域没有自动换行.

EDIT2:@trashgod 这是我得到的输出.显然,我们有不同的默认字体.事实上,问题可能与字体有关,甚至可能与系统有关.(PS:我用的是Win7).

line: Twas brillig and the slimy tovesD线路:id gyre 和 gimble in the wabe;行数:2首选: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]布局 1: 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]布局 2: java.awt.geom.Rectangle2D$Float[x=0.921875,y=-8.59375,w=177.34375,h=11.125]

在我的脑海中编译你们所有人所说的我认为可能可靠的解决方案可能是破解文本区域设置文本的方式,并采取完整的控制它.通过运行算法(以上一个,请注意,正如@trashgod 所建议的那样,该区域的 setText 中的<"已更改为<=').

是什么让我这么想...例如在我提供的示例中,如果您将 textarea 的文本更改为 JTextArea ta = new JTextArea("alfred abcdefghijkl mnoprstuwvxyz ab cdefg"); 因为它是在我的情况下计算出来的,然后它将完全适合 textarea.

这是我很快破解的一种解决方案,至少现在显示的字符和计算的完全相同.其他人可以检查一下并告诉我,它可能如何在其他机器上运行,然后在 Win7 上运行?下面的示例已准备好使用,您应该能够调整窗口大小并打印出与您看到的相同的行.

import java.awt.BorderLayout;导入 java.awt.FontMetrics;导入 java.awt.event.ComponentAdapter;导入 java.awt.event.ComponentEvent;导入 java.util.ArrayList;导入 java.util.List;导入 javax.swing.JFrame;导入 javax.swing.JPanel;导入 javax.swing.JTextArea;导入 javax.swing.SwingUtilities;公共类 TextAreaLines{public static void main(String[] args){SwingUtilities.invokeLater(new Runnable(){@覆盖公共无效运行(){JPanel p = new JPanel(new BorderLayout());JFrame f = new JFrame();final JTextArea ta = new JTextArea("alfred abcdefghijklmnoprstuwvxyz abcdefg");ta.addComponentListener(new ComponentAdapter(){@覆盖public void componentResized(ComponentEvent e){super.componentResized(e);System.out.println("ta componentResized");重新格式化TextAreaText(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);}私有无效重新格式化TextAreaText(JTextArea ta){字符串文本 = ta.getText();//删除所有换行符,因为我们要控制行制动text = text.replaceAll("
", "");FontMetrics fm = ta.getFontMetrics(ta.getFont());列表<字符串>texts = new ArrayList();字符串行 = "";//没有自动换行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));线 += c;}别的{texts.add(line);//存储文本line = "" + c;//清空行,添加最后一个字符}}文本.添加(行);//打印出行for(字符串:文本)System.out.println("s=" + s);//为字符串 newText = "";for(字符串:文本)newText += s + "
";ta.setText(newText);}});}}

提前致谢.

解决方案

我做错了什么,我忘记了什么?

没什么,真的.我修改了您的示例以在宽度上使用<="并突出显示一些功能:

  1. FontMetrics注意,String 的前进不一定是单独测量的其字符前进的总和......"

  2. 文本组件的首选大小与最宽行的度量边界非常匹配.由于比例间距,这因字体而异.

  3. TextLayout 显示更严格的边界,但请注意基线相对坐标".

  4. getLineCount() 方法计算 line.separator 分隔行,而不是包装行.

<前>线:Twas brillig 和slithy toves线:在wabe中进行了回旋和万向节;行数:2首选:java.awt.Dimension[width=207,height=48]bounds1: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.568359,w=205.0,h=15.310547]布局1:java.awt.geom.Rectangle2D$Float[x=0.0,y=-10.0,w=200.0,h=13.0]bounds2: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.568359,w=207.0,h=15.310547]布局 2: java.awt.geom.Rectangle2D$Float[x=1.0,y=-10.0,w=205.0,h=13.0]

import java.awt.Dimension;导入 java.awt.FontMetrics;导入 java.awt.font.FontRenderContext;导入 java.awt.font.TextLayout;导入 java.util.ArrayList;导入 java.util.List;导入 javax.swing.JFrame;导入 javax.swing.JTextArea;导入 javax.swing.SwingUtilities;/** #参见 http://stackoverflow.com/questions/5979795 */公共类 TextAreaLine {私有静态最终字符串 text1 ="光彩夺目,滑溜溜的
";私有静态最终字符串 text2 =在 wabe 中进行了旋转和万向节;";private static final JTextArea ta = new JTextArea(text1 + text2);公共静态无效主(字符串 [] args){SwingUtilities.invokeLater(new Runnable() {@覆盖公共无效运行(){展示();}});}静态无效显示(){JFrame f = new JFrame();ta.setWrapStyleWord(false);ta.setLineWrap(false);ta.setRows(3);f.add(ta);f.pack();f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);f.setLocationRelativeTo(null);f.setVisible(true);FontMetrics fm = ta.getFontMetrics(ta.getFont());列表<字符串>texts = new ArrayList();尺寸 d = ta.getPreferredSize();字符串文本 = ta.getText();字符串行 = "";for (int i = 0; i < text.length(); i++) {char c = text.charAt(i);如果 (c != '
') {if (fm.stringWidth(line + c) <= d.width) {线 += c;} 别的 {文本.添加(行);行 = "" + c;}}}文本.添加(行);for (String s : texts) {System.out.println("行:" + s);}System.out.println("行数:" + ta.getLineCount());System.out.println("首选:" + d);System.out.println("bounds1:" + fm.getStringBounds(text1, null));FontRenderContext frc = new FontRenderContext(null, false, false);TextLayout layout = new TextLayout(text1, ta.getFont(), frc);System.out.println("layout1:" + layout.getBounds());System.out.println("bounds2:" + fm.getStringBounds(text2, null));layout = new TextLayout(text2, ta.getFont(), frc);System.out.println("layout2:" + layout.getBounds());}}

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 mnoprstuwvxyz ab cdefg"); 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("
", "");
                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 + "
";
                ta.setText(newText);
            }
        });
    }
}

Thanks in advance.

解决方案

What am I doing wrong, what am I forgetting about?

Nothing, really. I modified your example to use "<=" on the width and to highlight a few features:

  1. FontMetrics notes, "the advance of a String is not necessarily the sum of the advances of its characters measured in isolation…"

  2. 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.

  3. TextLayout shows even tighter bounds, but note the "baseline-relative coordinates."

  4. The getLineCount() method counts line.separator delimited lines, not wrapped lines.

line: Twas brillig and the slithy toves
line: Did gyre and gimble in the wabe;
line count: 2
preferred: java.awt.Dimension[width=207,height=48]
bounds1: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.568359,w=205.0,h=15.310547]
layout1: java.awt.geom.Rectangle2D$Float[x=0.0,y=-10.0,w=200.0,h=13.0]
bounds2: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.568359,w=207.0,h=15.310547]
layout2: java.awt.geom.Rectangle2D$Float[x=1.0,y=-10.0,w=205.0,h=13.0]

import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

/** #see http://stackoverflow.com/questions/5979795 */
public class TextAreaLine {

    private static final String text1 =
        "Twas brillig and the slithy toves
";
    private static final String text2 =
        "Did gyre and gimble in the wabe;";
    private static final JTextArea ta = new JTextArea(text1 + text2);

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                display();
            }
        });
    }

    static void display() {
        JFrame f = new JFrame();
        ta.setWrapStyleWord(false);
        ta.setLineWrap(false);
        ta.setRows(3);
        f.add(ta);
        f.pack();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        FontMetrics fm = ta.getFontMetrics(ta.getFont());
        List<String> texts = new ArrayList<String>();
        Dimension d = ta.getPreferredSize();
        String text = ta.getText();
        String line = "";
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c != '
') {
                if (fm.stringWidth(line + c) <= d.width) {
                    line += c;
                } else {
                    texts.add(line);
                    line = "" + c;
                }
            }
        }
        texts.add(line);
        for (String s : texts) {
            System.out.println("line: " + s);
        }
        System.out.println("line count: " + ta.getLineCount());
        System.out.println("preferred: " + d);
        System.out.println("bounds1: " + fm.getStringBounds(text1, null));
        FontRenderContext frc = new FontRenderContext(null, false, false);
        TextLayout layout = new TextLayout(text1, ta.getFont(), frc);
        System.out.println("layout1: " + layout.getBounds());
        System.out.println("bounds2: " + fm.getStringBounds(text2, null));
        layout = new TextLayout(text2, ta.getFont(), frc);
        System.out.println("layout2: " + layout.getBounds());
    }
}

这篇关于如何计算文本在 JTextArea 中的行数(和每行中的列数)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆