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

时间:2012-10-31 18:48:22

标签: java swing user-interface jtextcomponent

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

2 个答案:

答案 0 :(得分:5)

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

Stategy:

  1. 使用FontMetrics和getVisibleRect()
  2. 查找哪些行可见
  3. 查找可见行的内容。
  4. 所以,我的想法是我们应该从可见的矩形开始。基于此,我们可以找出第一个可见垂直偏移(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<Row> 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<Row> getTAInfo(final JTextArea ta) {
            List<Row> taInfo = new ArrayList<TestTextAre.Row>();
            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()来计算水平偏移。

答案 1 :(得分:2)

好的,这是我对这个问题的看法......(不过很好的问题)

enter image description here

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

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

                        p.x += viewRect.width;
                        p.y += 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;
        }
    }
}