Search code examples
javaswinguser-interfacejtextcomponent

How to determine which lines are visible in scrollable JTextArea?


How to determine number of the first visible line and the number of lines currently visible in scrollable JTextArea (JTextArea inside a JScrollPane)?


Solution

  • Okay, this is my take on the problem... (Nice question though)

    enter image description here

    There is a small consideration you need to have with this solution. It will return partially displayed lines.

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