Принудительная всплывающая подсказка Java

Учитывая JTextField (или любой JComponent, если на то пошло), как можно было заставить форматировать эту компонентную подсказку, без какого-либо прямого события ввода от пользователя? Другими словами, почему нет JComponent.setTooltipVisible(boolean)?

Ответы

Ответ 1

Единственный способ (помимо создания собственного окна всплывающей подсказки), я нашел для эмуляции нажатия клавиши CTRL + F1 в фокусе:

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

К сожалению, всплывающая подсказка исчезнет, ​​как только вы переместите мышь (вне компонента) или после задержки (см. ToolTipManager.setDismissDelay).

Ответ 2

Вам нужно вызвать действие по умолчанию, чтобы показать всплывающую подсказку. Например, чтобы показать всплывающую подсказку, когда компонент получает фокус, вы можете добавить в компонент следующий FocusListener:

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:

Вышеприведенный код больше не работает. Другим подходом является отправка MouseEvent компоненту:

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

Этот подход приведет к небольшой задержке перед отображением всплывающей подсказки, поскольку он моделирует мышь, входящую в компонент. Для немедленного отображения всплывающей подсказки вы можете использовать решение pstanton.

Ответ 3

Для меня работает аналогичная версия, указанная выше (вместо Timer я использовал SwingUtilities и invokeLater):

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

Ответ 4

Вы можете получить доступ к ToolTipManager, установить начальную задержку на 0 и отправить ей событие. Не забудьте впоследствии восстановить значения.

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

Ответ 5

Это не ToolTip, но вы можете использовать подсказку: http://timmolderez.be/balloontip/doku.php

Он показывает только по вызову и чувствует себя лучше в некоторые моменты, затем по умолчанию ToolTip