17

Given a JTextField (or any JComponent for that matter), how would one go about forcing that component's designated tooltip to appear, without any direct input event from the user? In other words, why is there no JComponent.setTooltipVisible(boolean)?

Nathan
  • 8,093
  • 8
  • 50
  • 76
Joseph
  • 171
  • 1
  • 1
  • 3

5 Answers5

6

The only way (besides creating your own Tooltip window) I've found is to emmulate the CTRL+F1 keystroke on focus:

new FocusAdapter()
{
    @Override
    public void focusGained(FocusEvent e)
    {
        try
        {
            KeyEvent ke = new KeyEvent(e.getComponent(), KeyEvent.KEY_PRESSED,
                    System.currentTimeMillis(), InputEvent.CTRL_MASK,
                    KeyEvent.VK_F1, KeyEvent.CHAR_UNDEFINED);
            e.getComponent().dispatchEvent(ke);
        }
        catch (Throwable e1)
        {e1.printStackTrace();}
    }
}

Unfortunately, the tooltip will disappear as soon as you move your mouse (outside of the component) or after a delay (see ToolTipManager.setDismissDelay).

pstanton
  • 35,033
  • 24
  • 126
  • 168
  • +1, my original suggestion was based on the F1 key invoking the "postTip" Action. I thought it was cleaner to invoke the Action directly rather than dispatch the KeyEvent. Not sure why it doesn't work anymore. – camickr May 06 '13 at 16:02
  • tooltips are really badly implemented in java imo. very inflexible. that such hacks are necessary (and hardly achieve what is needed) show the api is lacking. – pstanton Jun 11 '13 at 21:31
  • Is Ctrl+F1 platform independent? Should I expect it to work on a Mac the same as Windows? – Nicholas Miller Jul 20 '14 at 05:25
  • quite possibly not! post your solution if you find one... @NickMiller – pstanton Aug 01 '14 at 01:54
5

You need to invoke the default Action to show the tooltip. For example to show a tooltip when a component gains focus you can add the following FocusListener to the component:

FocusAdapter focusAdapter = new FocusAdapter()
{
    public void focusGained(FocusEvent e)
    {
        JComponent component = (JComponent)e.getSource();
        Action toolTipAction = component.getActionMap().get("postTip");

        if (toolTipAction != null)
        {
            ActionEvent postTip = new ActionEvent(component, ActionEvent.ACTION_PERFORMED, "");
            toolTipAction.actionPerformed( postTip );
        }

    }
};

Edit:

The above code doesn't seem to work anymore. Another approach is dispatch a MouseEvent to the component:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PostTipSSCCE extends JPanel
{
    public PostTipSSCCE()
    {
        FocusAdapter fa = new FocusAdapter()
        {
            public void focusGained(FocusEvent e)
            {
                JComponent component = (JComponent)e.getSource();

                MouseEvent phantom = new MouseEvent(
                    component,
                    MouseEvent.MOUSE_MOVED,
                    System.currentTimeMillis(),
                    0,
                    10,
                    10,
                    0,
                    false);

                ToolTipManager.sharedInstance().mouseMoved(phantom);
            }
        };

        JButton button = new JButton("Button");
        button.setToolTipText("button tool tip");
        button.addFocusListener( fa );
        add( button );

        JTextField textField = new JTextField(10);
        textField.setToolTipText("text field tool tip");
        textField.addFocusListener( fa );
        add( textField );

        JCheckBox checkBox =  new JCheckBox("CheckBox");
        checkBox.setToolTipText("checkbox tool tip");
        checkBox.addFocusListener( fa );
        add( checkBox );
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("PostTipSSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new JScrollPane(new PostTipSSCCE()) );
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

This approach will result in a slight delay before the tooltip is displayed as it simulated the mouse entering the component. For immediate display of the tooltip you can use pstanton's solution.

camickr
  • 321,443
  • 19
  • 166
  • 288
2

For me works the similar version stated above (instead of Timer I used SwingUtilities and invokeLater approach):

private void showTooltip(Component component)
{
    final ToolTipManager ttm = ToolTipManager.sharedInstance();
    final int oldDelay = ttm.getInitialDelay();
    ttm.setInitialDelay(0);
    ttm.mouseMoved(new MouseEvent(component, 0, 0, 0,
            0, 0, // X-Y of the mouse for the tool tip
            0, false));
    SwingUtilities.invokeLater(new Runnable()
    {
        @Override
        public void run() 
        {
            ttm.setInitialDelay(oldDelay);
        }
    });
}
0

You can access the ToolTipManager, set the initial delay to 0 and send it an event. Don't forget to restore the values afterwards.

private void displayToolTip()
{
    final ToolTipManager ttm = ToolTipManager.sharedInstance();
    final MouseEvent event = new MouseEvent(this, 0, 0, 0,
                                            0, 0, // X-Y of the mouse for the tool tip
                                            0, false);
    final int oldDelay = ttm.getInitialDelay();
    final String oldText = textPane.getToolTipText(event);
    textPane.setToolTipText("<html><a href='http://www.google.com'>google</a></html>!");
    ttm.setInitialDelay(0);
    ttm.setDismissDelay(1000);
    ttm.mouseMoved(event);

    new Timer().schedule(new TimerTask()
    {
        @Override
        public void run()
        {
            ttm.setInitialDelay(oldDelay);
            textPane.setToolTipText(oldText);
        }
    }, ttm.getDismissDelay());
}
Olivier Faucheux
  • 2,520
  • 3
  • 29
  • 37
0

It's not a ToolTip, but you can use a balloon tip: http://timmolderez.be/balloontip/doku.php

It is showing just on call and feels better in some moments then Default ToolTip

bench_doos
  • 172
  • 11