[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 866
  • Last Modified:

"Hover Style" for JTextPane

I am programming on a reporting system which shows text,
pictures and information (very much like an HTML page).
For this I use the JTextPane, the DefaultStyleDocument
and the StyleConstants, and this works very well. Now,
I would like to add another style: one which shows a
small tool-tip or pop-up whenever the mouse hovers for
a defined amount of time (say 100 ms.) I would like to
specify the text (or even a whole component) and the
delay.

How to define a style and how to implement the tool-tip?
0
chrisflch
Asked:
chrisflch
1 Solution
 
dnoelppCommented:
I just am writing a similar application. I am afraid I didn't find a simple solution.


Summary:

Use the MouseMotionListener and translate the Point to the Position using AccessibleText.getIndexAtPoint(). Using StyledDocument.getCharacterElement(offset).getAttributes() detect the hover style and then show the pop-up. I still am working on how to do the pop-up, so I am sorry I can't give you hints on how to do the delay. I would use a Timer and recheck the current position of the mouse later.


Detailed steps:

#1 -- I created a custom JComponent which has a JTextPane inside (if you prefer just extend JTextPane, this doesn't matter).

#2 -- I wrote a MouseMotionListener which catches the mouse movements. I then translated the coordinates to the offset into the text. This was difficult, but then I discovered in the AccessibleText the function getIndexAtPoint() which does exactly what I needed. See code:

public int getOffsetAtPoint(Point p) {
    return textPane.getAccessibleContext().getAccessibleText().getIndexAtPoint(p);
}

#3 -- I designed a HoverListener interface and wrote addHoverListener and removeHoverListener methods to access them. A HoverListener is a low-level event very similar to the MouseMotionListener, but gives a Position object which is the position of the mouse into the text. See code:

public class HoverEvent extends EventObject {
    private Position position;
       
    public HoverEvent(Position position) {
        super(SimpleTextPane.this);
        this.position = position;
    }
    public Position getPosition() {
        return position;
    }
}
   
public static interface HoverListener extends EventListener {
    public void hover(HoverEvent e);
}

protected void addHoverListener(HoverListener listener) {
    listeners.add(listener);
}
   
protected boolean removeHoverListener(HoverListener listener) {
    return listeners.remove(listener);
}
   
private void fireHover(Position position) {
    int len = listeners.size();
    for (int i = 0; i < len; i++) {
        ((HoverListener)listeners.get(i)).hover(new HoverEvent(position));
    }
}

#4 -- In the mouse motion event handler I called fireHover() with the position gathered in step 2.

#5 -- I designed a Hover style. See code:

private static class HoverStyle {
    int hoverTime = -1;
    JComponent hoverComponent = null;
    public HoverStyle(int time, String text) {
        this(time, new JLabel(text));
    }
    public HoverStyle(int time, JComponent component) {
        if (time >= 0) {
            hoverTime = time;
            hoverComponent = component;
        }
    }
    public String toString() {
        return "HoverStyle[time=" + hoverTime + ",component="
            + (hoverComponent == null
                ? "<null>"
                : hoverComponent.getClass().getName()) + "]";
    }
}

#6 -- Since the HoverStyle is a private nested class, I provided accessor methods to set a hover style like this:

public void setHoverOff() {
    currentStyle.removeAttribute(HOVER_STYLE_NAME);
}
   
public void setHover(int time, String text) {
    currentStyle.addAttribute(
        HOVER_STYLE_NAME, new HoverStyle(time, text));
}
   
public void setHover(int time, JComponent component) {
    currentStyle.addAttribute(
        HOVER_STYLE_NAME, new HoverStyle(time, component));
}

currentStyle is a Style object. Text added to the JTextPane will have the style of currentStyle. HOVER_STYLE_NAME is just a string "hover" which gives the attribute name of the hover style.

#7 -- Make your class (from step 1) listening to the hover event yourself and detect any hover styles at the Position and put a pop-up. Like this with an anonymous inner class:

addHoverListener(new HoverListener() {
    public void hover(HoverEvent e) {
        int offset = e.getPosition().getOffset();
            AttributeSet attr = textPane.getStyledDocument()
                .getCharacterElement(offset).getAttributes();

            Object attribute = attr.getAttribute("hover");
            if (attribute == null) return;
            System.out.println("hover");
            JComponent hover = ((HoverStyle)attribute).hoverComponent;
            // here show the JComponent hover and set its location... NOT YET IMPLEMENTED.
            // hover.setVisible(true);
        }
    });
}

#8 -- NOT YET IMPLEMENTED: Make the pop up show at the appropriate place with specified delay.

That's it!
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now