javaswingjtextarea

How can I center a text vertically within a JTextArea?


I have a JTextArea with a long text. In the text there is the string "abc" that I want to be displayed in the middle (vertical) of the text area. I can use setCaretPosition to cause the ScrollPane to scroll enough for the string "abc" to scroll into view. The scrolling continues until the text "abc" becomes visible at the bottom of the text area (see example) How can I get the scrollbar to scroll so far that the text "abc" is displayed in the middle (vertically) in the visible area?

many thanks for your help!

public class TestCenter {

    public TestCenter() {
        JFrame frame = new JFrame();
        JTextArea ta = new JTextArea();

        frame.setMinimumSize(new Dimension(800, 600));
        frame.add(new JScrollPane(ta));
        frame.pack();
        frame.setVisible(true);

        SwingUtilities.invokeLater(() -> {
            StringBuilder testText = new StringBuilder();
            for (int t = 0; t < 100; t++) {
                testText.append("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
            }
            testText.append("abc");
            for (int t = 0; t < 100; t++) {
                testText.append("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
            }
            ta.setText(testText.toString());
            ta.setCaretPosition(testText.indexOf("abc"));
        });
    }

    public static void main(String[] args) {
        new TestCenter();
    }

}

Solution

  • To move the scroll bar to the position of the abc text to be displayed vertically in the middle of the viewport we have to first find the line number of the text and translate it to the view coordinates:

    // Find the line number of the "abc" text
    int lineNumber = ta.getLineOfOffset(testText.indexOf("abc"));
    // Translate the lineNumber to the view rectangle
    Rectangle viewRect = ta.modelToView(ta.getLineStartOffset(lineNumber));
    

    Now, having the viewRect we can get the viewport size and calculate the position Point to scroll to

    Dimension viewportSize = scrollPane.getViewport().getExtentSize();
    // Calculate new view position to scroll to
    Point scrollPoint = new Point(0, view.y - (viewportSize.height - view.height) / 2);
    

    Some explanation about calculating the scrollPoint. To calculate the y-coordinate at which the line should be centered, we use the following formula: rect.y - (viewportSize.height - viewRect.height) / 2. We subtract the height of the line (viewRect.height) from the total viewport size (viewportSize.height) which gives the remaining space in the viewport above and below the line. Then we divide the remaining space by 2 to get the position of the line in the center of viewport.

    And as we want to vertically center the line in the viewport, we subtract the resulting value from the top y-coordinate of the line to get the new y-coordinate of the viewport.

    Finally, we can set the viewport to the calculated scrollPoint using JViewport::setViewPosition(Point):

    public TestCenter() {
        JFrame frame = new JFrame();
        JTextArea ta = new JTextArea();
        JScrollPane scrollPane = new JScrollPane(ta);
    
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setMinimumSize(new Dimension(800, 600));
        frame.add(scrollPane);
        frame.pack();
        frame.setVisible(true);
    
        var testText =
            "xxxxxxxxxxxxxxxxxxxx\n".repeat(100) +
            "abc" +
            "xxxxxxxxxxxxxxxxxxxx\n".repeat(100);
        ta.setText(testText.toString());
    
        try {
            // Find the line number of the "abc" text
            int lineNumber = ta.getLineOfOffset(testText.indexOf("abc"));
            // Translate the lineNumber to the view rectangle
            Rectangle viewRect = ta.modelToView(ta.getLineStartOffset(lineNumber));
            // Get the size of the viewport
            Dimension viewportSize = scrollPane.getViewport().getExtentSize();
            // Calculate new view position to scroll to
            Point scrollPoint = new Point(0, viewRect.y - (viewportSize.height - viewRect.height) / 2);
            // Move the view to the new position
            scrollPane.getViewport().setViewPosition(scrollPoint);
        } catch (BadLocationException e) {
            throw new RuntimeException(e);
        }
    }
    
    

    enter image description here