Как рассчитать количество строк (и столбцов в каждой строке), которые текст принимает в 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 texts = new ArrayList(); 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? Пример ниже готов к использованию, вы должны resize windows и получить распечатку строк так же, как вы видите.

 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 texts = new ArrayList(); 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); } }); } } 

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

Что я делаю неправильно, о чем я забываю?

Не важно. Я изменил ваш пример, чтобы использовать «<=» по ширине и выделить несколько функций:

  1. FontMetrics , «продвижение String не обязательно является суммой достижений его персонажей, измеренных изолированно …»

  2. Предпочтительный размер текстового компонента очень близок к метрическим границам для самой широкой строки. Это зависит от размера шрифта из-за пропорционального расстояния.

  3. TextLayout показывает даже более жесткие границы, но обратите внимание на «базовые относительные координаты».

  4. Метод getLineCount() подсчитывает line.separator разделителями line.separator , а не завернутые строки.

 line: Twas brillig и slithy toves
 line: Делал ли дроу и прыгал в вабе;
 количество строк: 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]
 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 texts = new ArrayList(); 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()); } } 

Одна вещь, которую вы можете сделать, это использовать FontMetrics . Я написал код для разделения JTextArea на некоторые номера строк. Код установки выглядел так:

 Graphics2D g = (Graphics2D) g2; FontMetrics m = g.getFontMetrics(); int lineHeight = m.getHeight(); 

Это скажет вам, насколько высока строка текста.

К сожалению, в большинстве шрифтов буквы имеют разную ширину. Но для определения ширины строки можно использовать следующий код.

 int width = m.getStringBounds("Some String", g).getWidth(); 

Я знаю, что это не полностью отвечает на ваш вопрос, но я надеюсь, что это поможет.

Если вы не используете перенос слов, вот общий алгоритм, который вы можете использовать: (в методе компонента краски)

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

Это общая идея. Не уверен, насколько хорошо это сработает. Дайте мне знать, если вы попробуете.

Не уверен, что это помогает, но вам нужно установить ширину текстовой области, чтобы представление знало, когда нужно обернуть текст. Как только вы зададите размер, вы можете определить предпочтительную высоту. Когда вы знаете предпочтительную высоту, вы можете использовать высоту линии метрика шрифта, чтобы определить общее количество строк, включая обернутые строки, если таковые имеются.

 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(); } } 

Я видел людей, использующих TextLayout для чего-то вроде этого.

Хорошо, я написал программу, которую вы могли бы загрузить в изображении, и она преобразует ее в искусство ascii. Я хотел, чтобы он автоматически превращал текстовую область в правильный аспектный рацион на основе введенного изображения.

Тем не менее, я не мог заставить его работать правильно. Я сдался и заметил мои попытки, вот fragment того, что я пытался. То, что я закончил, – это просто текстовое поле, которое иногда не заполнялось полностью.

  //Graphics fontG = this.textBox4.CreateGraphics(); //fontG.PageUnit = GraphicsUnit.Point; //SizeF fontSize = fontG.MeasureString(RowData, this.textBox4.Font,(SizeF) this.textBox4.ClientSize); sb.AppendLine(); RowData = ""; //fontH += fontSize.Height + 1.2F; //fontW = (int) fontSize.Width; 

Вчера у андроида был аналогичный вопрос. Способ, которым я его вижу, должен быть решен путем итеративного подхода:

  • Получить ширину JTextArea
  • Используйте FontMetrics, чтобы получить ширину строки, как предположил jjnguy
  • разделите строку на слова.
  • Начните измерять witdh строки, добавляя по одному слову, пока не достигнете ширины области. Сохраните этот номер.
  • Как только вы достигнете этого, начните новую итерацию, добавив по одному слову за раз (начиная с сохраненного номера).
  • Число строк будет числом итераций.

К сожалению, длина строки будет зависеть от шрифта и конкретной строки (а не от каждого символа равной ширине). Вы можете подсчитать количество символов в словах на каждой итерации и вернуть массив длин или среднюю длину.

Это связанный андроид вопрос: Как найти android TextView количество символов в строке?

Я обнаружил, что подсчет количества строк путем текстового анализа только ничего не приводил. Вместо этого мое решение вычисляло его из предпочтительного размера текстовой области …

 import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; public class LineNumbering extends JFrame { private static final long serialVersionUID = 1L; private static final Font fixedFont = new Font("Monospaced", Font.PLAIN, 12); private static JTextArea jta; private static JTextArea lines; private static String lineSeparator = "\n"; private static int numRows = 10; private static int numCols = 30; public LineNumbering() { super("Line Numbering Example"); } public static void createAndShowGUI() { JFrame frame = new LineNumbering(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JScrollPane jsp = new JScrollPane(); jta = new JTextArea(numRows, numCols); jta.setFont(fixedFont); jta.setLineWrap(true); jta.setWrapStyleWord(true); lines = new JTextArea(numRows, 3); lines.setEditable(false); lines.setFocusable(false); lines.setEnabled(false); lines.setFont(fixedFont); lines.setBackground(Color.LIGHT_GRAY); lines.setDisabledTextColor(Color.BLACK); // do initial line numbering for (int i = 1; i <= lines.getRows(); i++) { lines.append(i + System.getProperty("line.separator")); } final class DebugCaretListener implements CaretListener { int rowHeight = jta.getFontMetrics(jta.getFont()).getHeight(); /** * @return total of lines showed in the text area */ private int getTotalLinesInView() { int insetsTotalHeight = jta.getInsets().top + jta.getInsets().bottom; return (jta.getPreferredSize().height - insetsTotalHeight) / rowHeight; } /** * @return text with line numbers */ public String getText() { StringBuffer text = new StringBuffer(); int totalLines = getTotalLinesInView(); System.out.println("totalLines : " + totalLines); for (int i = 1; i <= totalLines; i++) { text.append(i); if (i < totalLines) { text.append(lineSeparator); } } return text.toString(); } /** * 

* Reset line numbers on caret event. Since the total number of * lines is calculated from preferred size of text area, we do this * on an event that occurred after repainting of the text area. *

* (non-Javadoc) * * @see javax.swing.event.CaretListener#caretUpdate(javax.swing.event.CaretEvent) */ @Override public void caretUpdate(CaretEvent e) { int totalLines = getTotalLinesInView(); System.out.println("totalLines : " + totalLines); if (totalLines >= numRows) { lines.setText(getText()); } } } jta.addCaretListener(new DebugCaretListener()); jsp.getViewport().add(jta); jsp.setRowHeaderView(lines); jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); JPanel textPanel = new JPanel(); textPanel.add(jsp); JPanel contentPanel = new JPanel(); contentPanel.add(textPanel); frame.setContentPane(contentPanel); contentPanel.setOpaque(true); frame.pack(); frame.setPreferredSize(new Dimension(500, 500)); frame.setVisible(true); } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } }
  • Воспроизведение изменения значения в JTextField
  • Как resize текста в java
  • Как установить AUTO-SCROLLING JTextArea в Java GUI?
  • Порядок срабатывания EventListenerList
  • Какова связь между ContentPane и JPanel?
  • Как закрыть приложение Java Swing из кода
  • SwingUtilities.invokeLater
  • Как узнать, когда пользователь действительно выпустил ключ на Java?
  • Рисование слайдера иконки JSlider
  • Как заставить мои клавиши со стрелками ISO_Level5_Shift работать в графических интерфейсах Java Swing?
  • Как установить жесткий предел для JComponent, когда setMaximumSize () и setPrefferedSize () не работают?
  • Interesting Posts
    Давайте будем гением компьютера.