如何确定哪些行在可滚动的JTextArea中可见?

如何确定第一个可见行的数量和可滚动的JTextArea(JScrollPane中的JTextArea)中当前可见的行数?

好的,这是我对这个问题的看法……(但问题很好)

在此处输入图像描述

您需要对此解决方案进行一些考虑。 它将返回部分显示的行。

public class TestTextArea { public static void main(String[] args) { new TestTextArea(); } public TestTextArea() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException ex) { } catch (InstantiationException ex) { } catch (IllegalAccessException ex) { } catch (UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestTextAreaPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestTextAreaPane extends JPanel { private JTextArea textArea; private JTextArea viewText; public TestTextAreaPane() { setLayout(new GridLayout(2, 1)); textArea = new JTextArea(20, 100); textArea.setWrapStyleWord(true); textArea.setLineWrap(true); textArea.setText(loadText()); viewText = new JTextArea(20, 100); viewText.setWrapStyleWord(false); viewText.setLineWrap(false); viewText.setEditable(false); JScrollPane scrollPane = new JScrollPane(textArea); add(scrollPane); add(viewText); scrollPane.getViewport().addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { if (textArea.getText().length() > 0) { JViewport viewport = (JViewport) e.getSource(); Rectangle viewRect = viewport.getViewRect(); Point p = viewRect.getLocation(); int startIndex = textArea.viewToModel(p); px += viewRect.width; py += viewRect.height; int endIndex = textArea.viewToModel(p); if (endIndex - startIndex >= 0) { try { viewText.setText(textArea.getText(startIndex, (endIndex - startIndex))); } catch (BadLocationException ex) { ex.printStackTrace(); viewText.setText(ex.getMessage()); } } } } }); } protected String loadText() { String text = null; File file = new File("src/testtextarea/TestTextArea.java"); BufferedReader br = null; try { br = new BufferedReader(new FileReader(file)); StringBuilder sb = new StringBuilder(128); String read = null; while ((read = br.readLine()) != null) { sb.append(read).append("\n"); } text = sb.toString(); } catch (IOException exp) { exp.printStackTrace(); } finally { try { br.close(); } catch (Exception e) { } } return text; } } } 

有趣的问题花了我一段时间,但我认为我有一个非常有效的答案。 然而,可能会有更好的方法; 随时评论以改善答案。

Stategy:

  1. 使用FontMetrics和getVisibleRect()查找哪些行可见
  2. 查找可见行的内容。

所以,我的想法是我们应该从可见的矩形开始。 基于此,我们可以找出第一个可见垂直偏移( getVisibleRect().y )和可见垂直偏移的结束( getVisibleRect().y+getVisibleRect().height )。 一旦我们有了这个,通过使用字体的高度,我们可以确定哪些行是可见的。

第二部分是找出这些行包含的内容。 这是我使用UtilitiesgetRowStart()getRowEnd()发挥作用的地方。

下面是我详细介绍的示例代码(在调整框架大小或滚动textarea时,结果会输出到控制台):

 import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; 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.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Utilities; public class TestTextAre { private void initUI() { JFrame frame = new JFrame(TestTextAre.class.getSimpleName()); final JTextArea ta = new JTextArea(5, 25); ta.setText("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has " + "been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of " + "type and scrambled it to make a type specimen book.\n It has survived not only five centuries, but also the " + "leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the" + " release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing " + "software like Aldus PageMaker including versions of Lorem Ipsum."); ta.setColumns(20); ta.setEditable(false); ta.setLineWrap(true); ta.setWrapStyleWord(true); JScrollPane scrollpane = new JScrollPane(ta); scrollpane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { @Override public void adjustmentValueChanged(AdjustmentEvent e) { if (e.getValueIsAdjusting()) { return; } printTAVisibleInfo(ta); } }); frame.add(scrollpane); frame.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { printTAVisibleInfo(ta); } }); frame.pack(); frame.setVisible(true); } private void printTAVisibleInfo(final JTextArea ta) { List taInfo = getTAInfo(ta); int y1 = ta.getVisibleRect().y; int y2 = y1 + ta.getVisibleRect().height; int lineHeight = ta.getFontMetrics(ta.getFont()).getHeight(); int startRow = (int) Math.ceil((double) y1 / lineHeight); int endRow = (int) Math.floor((double) y2 / lineHeight); endRow = Math.min(endRow, taInfo.size()); System.err.println(startRow + " " + endRow); for (int i = startRow; i < endRow; i++) { System.err.println(taInfo.get(i) + " is visible"); } } private List getTAInfo(final JTextArea ta) { List taInfo = new ArrayList(); int start = 0; int end = -1; int i = 0; try { do { start = Utilities.getRowStart(ta, end + 1); end = Utilities.getRowEnd(ta, start); taInfo.add(new Row(i, start, end, ta.getDocument().getText(start, end - start))); i++; } while (end < ta.getDocument().getLength()); } catch (BadLocationException e) { // TODO Auto-generated catch block e.printStackTrace(); } return taInfo; } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new TestTextAre().initUI(); } }); } public static class Row { private final int row; private final int start; private final int end; private final String text; public Row(int row, int start, int end, String text) { super(); this.row = row; this.start = start; this.end = end; this.text = text; } public int getRow() { return row; } public int getStart() { return start; } public int getEnd() { return end; } public String getText() { return text; } @Override public String toString() { return "Row " + row + " contains " + text + " (" + start + "," + end + ")"; } } } 

如果你还有一个水平滚动条,我猜你应该能够用FontMetrics.stringWidth()计算水平偏移。