如何计算文本在JTextArea中的行数(以及每行中的列数)?

Bor*_*oro 12 java swing 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());
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑1:所以我提出了以下代码,但问题是输出不是你看到的,即

//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);
Run Code Online (Sandbox Code Playgroud)

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

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]
Run Code Online (Sandbox Code Playgroud)

在我的头脑中编译你们所有人都在说我认为可能可靠的解决方案可能是破解文本区域设置文本的方式,并完全控制它.通过运行算法(请注意,在@trashgod的建议中,'<'被改为'<=')在该区域的setText中.

是什么让我这样思考...例如在我提供的示例中,如果您将textarea的文本更改JTextArea ta = new JTextArea("alfred abcdefghijkl\nmnoprstuwvxyz ab\ncdefg");为在我的情况下计算,那么它将完全适合textarea.

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);
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

提前致谢.

tra*_*god 10

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

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

  1. FontMetrics注意到,"a的推进String不一定是孤立测量的人物进步的总和......"

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

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

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

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\n";
    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 != '\n') {
                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());
    }
}
Run Code Online (Sandbox Code Playgroud)


jjn*_*guy 5

你可以做的一件事是使用FontMetrics.我写了一些代码,用于JTextArea在某些行号上拆分.设置代码如下所示:

Graphics2D g = (Graphics2D) g2;
FontMetrics m = g.getFontMetrics();
int lineHeight = m.getHeight();
Run Code Online (Sandbox Code Playgroud)

这将告诉您文本行的高度.

不幸的是,大多数字体中的字母宽度不同.但是,您可以使用以下代码来确定String的宽度.

int width = m.getStringBounds("Some String", g).getWidth();
Run Code Online (Sandbox Code Playgroud)

我知道这并没有完全回答你的问题,但我希望它有所帮助.

如果你没有使用自动换行,这里是你可以使用的通用算法:(在paint组件方法中)

String text[] = getText().split("\n");
String newText = "";
for (String line: text) {
    newText = line + "| " + line.length() + "\n";
}
setText(newText);
Run Code Online (Sandbox Code Playgroud)

这是一般的想法.不确定它会有多好.如果你试试,请告诉我.


cam*_*ckr 5

不确定这是否有帮助,但您需要设置文本区域的宽度,以便视图知道何时包装文本.设置尺寸后,您可以确定首选高度.当您知道首选高度时,可以使用字体metrice行高来确定包括包裹行(如果有)的总行数.

import java.awt.*;
import javax.swing.*;

public class TextAreaPreferredHeight extends JFrame
{

    public TextAreaPreferredHeight()
    {
        JTextArea textArea = new JTextArea();
        textArea.setText("one two three four five six seven eight nine ten");
        textArea.setLineWrap( true );
        textArea.setWrapStyleWord( true );

        FontMetrics fm = textArea.getFontMetrics( textArea.getFont() );
        int height = fm.getHeight();

        System.out.println("000: " + textArea.getPreferredSize());
        textArea.setSize(100, 1);
        System.out.println("100: " + textArea.getPreferredSize());
        System.out.println("lines : " + textArea.getPreferredSize().height / height);

        textArea.setSize(200, 1);
        System.out.println("200: " + textArea.getPreferredSize());
        System.out.println("lines : " + textArea.getPreferredSize().height / height);

        textArea.setSize(300, 1);
        System.out.println("300: " + textArea.getPreferredSize());
        System.out.println("lines : " + textArea.getPreferredSize().height / height);
        add(textArea);
        pack();
        setVisible(true);
}

    public static void main(String[] args)
    {
        new TextAreaPreferredHeight();
    }
}
Run Code Online (Sandbox Code Playgroud)