How to calculate the number of rows (and columns i

2019-01-01 16:13发布

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 were 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 including 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.

7条回答
后来的你喜欢了谁
2楼-- · 2019-01-01 17:03

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.

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();
    }
}
查看更多
登录 后发表回答