user1119859
user1119859

Reputation: 719

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

}

Upvotes: 1

Views: 105

Answers (1)

Marcin Kłopotek
Marcin Kłopotek

Reputation: 5931

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

Upvotes: 2

Related Questions