Andreas
Andreas

Reputation: 23

Get absolute position of character in JEditorPane

1
I need the absolute position of the charater. With:
editorPane.getFontMetrics(f).getAscent()
I only get a relative distance to the baseline. Maybe there is a way to get the absolute position of the baseline?

EDIT: This is the result of rect.y + rect.height - metrics.getDescent() - metrics.getAscent()

Upvotes: -1

Views: 314

Answers (2)

VGR
VGR

Reputation: 44414

Since all fonts in a line share a baseline*, you can compute a character’s visual position by calling modelToView and subtracting the descent and ascent from the bottom of the rectangle.

Since multiple fonts are involved, obviously the getFont method of JEditorPane is not sufficient. The document’s raw element attributes are also insufficient, as an HTMLDocument’s attributes merely model the HTML elements themselves. However, the actual font for any document position can be obtained from the corresponding View:

static Point getLocation(int pos,
                         JEditorPane editorPane)
throws BadLocationException {

    HTMLDocument doc = (HTMLDocument) editorPane.getDocument();

    View view = editorPane.getUI().getRootView(editorPane);
    int index;
    while ((index = view.getViewIndex(pos, Position.Bias.Backward)) >= 0) {
        view = view.getView(index);
    }

    AttributeSet attr = doc.getStyleSheet().getViewAttributes(view);
    Font f = doc.getStyleSheet().getFont(attr);

    FontMetrics metrics = editorPane.getFontMetrics(f);
    Rectangle rect = editorPane.modelToView(pos);

    return new Point(rect.x,
        rect.y + rect.height - metrics.getDescent() - metrics.getAscent());
}

* For simplicity, I’m ignoring characters with hanging baselines and vertical baselines.

Edit: Since the RTFEditorKit is rarely used, I incorrectly assumed you were using an HTMLEditorKit. This will work with RTF documents:

static Point getLocation(int pos,
                     JEditorPane editorPane)
throws BadLocationException {
    StyledDocument doc = (StyledDocument) editorPane.getDocument();
    View view = editorPane.getUI().getRootView(editorPane);
    int index;
    while ((index = view.getViewIndex(pos, Position.Bias.Backward)) >= 0) {
        view = view.getView(index);
    }

    AttributeSet attr = view.getAttributes();
    Font f = doc.getFont(attr);

    FontMetrics metrics = editorPane.getFontMetrics(f);
    Rectangle rect = editorPane.modelToView(pos);

    return new Point(rect.x,
        rect.y + rect.height - metrics.getDescent() - metrics.getAscent());
}

Upvotes: 1

Andreas
Andreas

Reputation: 23

I'm using the RTFEditorKit. So I changed the code:

static Point getLocation(int pos,
            JEditorPane editorPane)
            throws BadLocationException {

        View view = editorPane.getUI().getRootView(editorPane);
        int index;
        while ((index = view.getViewIndex(pos, Position.Bias.Backward)) >= 0) {
            view = view.getView(index);
        }

        AttributeSet set = view.getAttributes();
        if (set != null && set.getAttribute(StyleConstants.FontFamily) != null) {
            Font f = new Font((String) set.getAttribute(StyleConstants.FontFamily), Font.PLAIN, (Integer) set.getAttribute(StyleConstants.FontSize));
            FontMetrics metrics = editorPane.getFontMetrics(f);

            Rectangle rect = editorPane.modelToView(pos);
            return new Point(rect.x,
                    rect.y + rect.height - metrics.getDescent() - metrics.getAscent());
        }
        else {
            return new Point(0, 0);
        }
    }

But I always get the ascent of the current Font and not the ascent of the largest Font.

Upvotes: 0

Related Questions