Как подсчитать количество строк (и столбцов в каждой строке), которые занимает текст в 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]

Компилируя в голове то, что вы все говорите, я думаю, что возможно надежным решением может быть взлом способа, которым текстовая область устанавливает свой текст, и полный контроль над ним. Выполнив алгоритм (приведенный выше, обратите внимание, по предложению @trashgod '<' был заменен на '<=') в setText области.

Что натолкнуло меня на такую мысль... например, в приведенном мной примере, если вы изменить текст текстовой области на 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);
            }
        });
    }
}

Заранее спасибо.

12
задан Community 23 May 2017 в 10:26
поделиться