6

I'd like to implement a ToolTip in Swing that has customised behaviour: the longer the user hovers over the component, the more detail should be shown in the tooltip (i.e., a few new lines are added after a few seconds of the user hovering over the component). I just need to check whether this is really doable with Swing without things getting too messy. My idea at the moment would probably be:

  • Extend ToolTipManager
  • Override mouseEntered to start a timer (maybe use javax.swing.Timer?). Call setToolTipText and createToolTip to refresh the tooltip and add new information at regular intervals
  • Override mouseExited to reset the timer
  • Probably use setDismissDelay to set the dismiss delay to something a lot longer (or Integer.MAX_VALUE)

Is such a thing feasible or is this not a good way to work with Swing (sorry, I'm pretty new to it)? Is there a better way of doing this?

[edit] Hmm, just remembered that ToolTipManager is a singleton with a constructor that only has package visibility, so it can't be extended.

[edit 2] I'm trying out a few solutions at the moment. One thing that I forgot to add is that I do need to know which component is being hovered over - which I guess means I'll need to be working with some sort of listener with a mouseEntered() method (or be able to access this information). And no other interactivity with the popup/tooltip is needed - it just needs to display information.

false_azure
  • 1,333
  • 4
  • 25
  • 46
  • 1
    "*Is such a thing feasible?*" Yes. Your way looks like a good option, but without a concrete implementation it's hard to tell.. – user1803551 May 21 '15 at 09:13
  • True! If it sounds like a decent option I'll give it a go - probably the best way of finding out. – false_azure May 21 '15 at 09:21
  • With some more info I could guide you a bit more. Would something like "for every additional X seconds of hovering, add another line to the tooltip text" be a good example of what you want to achieve? – user1803551 May 21 '15 at 09:23
  • That makes sense, thank you. I just realised though that ToolTipManager is a singleton and can't be extended - makes things more complicated. – false_azure May 21 '15 at 10:06
  • 1
    I was actually constantly thinking about `JToolTip` instead of `ToolTipManager` when reading the question (oops). The former is the one you can override, but I think that there's a simpler way.with overriding `getToolTipText(MouseEvent event)` for the component. – user1803551 May 21 '15 at 10:11
  • Oh great, glad there's another option. I'd gotten the two mixed up - that sounds like it'll work. – false_azure May 21 '15 at 10:20
  • 1
    I got partial success via cheating. I think that overriding `JToolTip` is only necessary if you need something complicated. Is it working for you? Try to post some attempt in the question. – user1803551 May 21 '15 at 11:08
  • 1
    @false_azure JWindow/undecorated JDialog if some type of motality is there required (thats required:-) – mKorbel May 21 '15 at 15:15
  • 1
    @false_azure JPopup is very good also, maybe excelent, better than JWindow/JDialog because flow away on (methods in API) 1st. mouse/key event – mKorbel May 21 '15 at 15:18

2 Answers2

1

(This may seem a bit confusing so let me know if you need me to clarify let me know and I'll try to show you how I picture the code) I think your idea might work like if you extend it, and also make a private class that extends Threadand then in the run() method you do something like

while(true)
{
    sleep(1);
    timeElapsed++;
}

And in your class that extends ToolTipManager, create a field for that class that extends Thread and in the mouseEntered(MouseEvent e) instantiate the thing like:

extendsThreadClass = new ExtendsThreadClass();
extendsThreadClass.start();

and then in the mouseExited(MouseEvent e) method do

extendsThreadClass = null;

Then in that mouseEntered(MouseEvent e) method after starting the Thread then you can do what you want to do after the time thing like

if(timeElapsed > 3000)
{
   //what you want to do here
}

Sorry it may be confusing, let me know if i can clear it up for you

l1zZY
  • 100
  • 10
0

I thought I should update this with the approach I took before I saw l1zZY's answer (which I think is the better way of doing things - I still had bugs in my code before I moved onto something else, but this might still be helpful to someone). This is what I did:

  • Extend JToolTip
  • Use a Swing Timer for timing
  • Add a MouseMotion listener to the JTree (in my case I wanted the popup to show when a node was hovered over)
  • Somewhat inelegantly, detect when the mouse moved over a tree node like this:

    public void mouseMoved(MouseEvent e) {
    int x = (int) e.getX();
    int y = (int) e.getY();
    TreePath path = getPathForLocation(x, y);
    if (path == null) {
        tooltip.hide();
    } else {
        TreeNode node = (TreeNode) path.getLastPathComponent();
        tooltip.setHoveredNode(node); 
        if (!tooltip.isVisible) {
            int absX = e.getXOnScreen();
            int absY = e.getYOnScreen();
            final Popup tooltipContainer = PopupFactory.getSharedInstance().getPopup(PDTreeView.this, 
                    tooltip, absX, absY);
            tooltip.setToolTipContainer(tooltipContainer);
            tooltip.show();
        }
    }
    

    }

  • tooltip.show() refers to how the tooltip was contained in a Popup in order to show or hide it programmatically. show() shows the Popup (and therefore tooltip) and also starts the Swing timer.

  • Timer has a method called actionPerformed() which is called at whatever interval you set. I just had that method call the code that adds new information to the tooltip. in hide(), I reset the tooltip and the timer.

I had issues with the popup or tooltip not resizing to fit the content, but otherwise this seemed ok.

false_azure
  • 1,333
  • 4
  • 25
  • 46