Java 如何更改1个组件的jtooltip计时器

Java 如何更改1个组件的jtooltip计时器,java,swing,Java,Swing,我有一个组件,我想在其中显示自定义jtooltip。这很简单,只需更改getTooltip方法。位置和文本类似 然而,我也想改变计时器。如果鼠标位于组件的cellrenderer上,则应始终显示工具提示。如果它离开了所有这些,它应该变成隐形的。 我知道我可以使用ToolTimManager来全局控制时间。但最好的解决方案可能是缩短这个时间,自己用鼠标听器显示工具提示。但是,当我尝试这样做时(在ToolTimManager中注销组件,并在鼠标侦听器中将工具提示设置为可见,文本和位置正确),工具提示

我有一个组件,我想在其中显示自定义jtooltip。这很简单,只需更改getTooltip方法。位置和文本类似

然而,我也想改变计时器。如果鼠标位于组件的cellrenderer上,则应始终显示工具提示。如果它离开了所有这些,它应该变成隐形的。 我知道我可以使用ToolTimManager来全局控制时间。但最好的解决方案可能是缩短这个时间,自己用鼠标听器显示工具提示。但是,当我尝试这样做时(在ToolTimManager中注销组件,并在鼠标侦听器中将工具提示设置为可见,文本和位置正确),工具提示根本没有显示。我做错了什么

编辑: 现在问题变了!分成两个问题

目前我的解决方案是这样的,但是它会丢失jtooltip有时总是令人沮丧地显示的阴影,并且如果鼠标退出到弹出窗口中,它会被隐藏。如果弹出窗口甚至不是一个组件,如何通过弹出窗口过滤mouseexit事件?我可以根据最后的位置进行一些黑客攻击,但这似乎很愚蠢,因为我不知道它的宽度

    private Popup lastPopup;
    private final JToolTip tooltip = ...;
    private Point lastPoint;
   @Override public void mouseMoved(MouseEvent e) {
        Point p = privateToolTipLocation(e);
        if (p == null || p.equals(lastPoint)) {
            return;
        }
        lastPoint = p;
        tooltip.setTipText(privateToolTipText(e));
        //copy
        p = new Point(p);
        SwingUtilities.convertPointToScreen(p, this);
        Popup newPopup = PopupFactory.getSharedInstance().getPopup(this, tooltip, p.x, p.y);
        if (lastPopup != null) {
            lastPopup.hide();
        }
        lastPopup = newPopup;
        newPopup.show();
    }

    @Override public void mouseExited(MouseEvent e) {
        if (lastPopup != null && someUnknownCondiction) {
            lastPopup.hide();
            lastPopup = null;
        }
    }

显然,控制工具提示显示的是getToolTiptText是否返回null。如果将其设置为null,则消除一个npe并允许显示内容。然而,仍然有一些人工制品

但最好的解决办法可能是 只需将其短接并显示 用鼠标听器提示我自己

调用组件的默认操作以显示工具提示:

Action toolTipAction = component.getActionMap().get("postTip");

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

上述代码似乎不再有效。Ctrl+F1是用于显示零部件工具提示的默认击键。因此,另一种方法是将Ctrl+F1键发送到组件。例如:

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

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

                KeyEvent ke = new KeyEvent(
                    component,
                    KeyEvent.KEY_PRESSED,
                    System.currentTimeMillis(),
                    KeyEvent.CTRL_MASK,
                    KeyEvent.VK_F1,
                    KeyEvent.CHAR_UNDEFINED);

                component.dispatchEvent( ke );
            }
        };

        MouseAdapter ma = new MouseAdapter()
        {
            @Override
            public void mouseEntered(MouseEvent e)
            {
                JComponent component = (JComponent)e.getSource();

                KeyEvent ke = new KeyEvent(
                    component,
                    KeyEvent.KEY_PRESSED,
                    System.currentTimeMillis(),
                    KeyEvent.CTRL_MASK,
                    KeyEvent.VK_F1,
                    KeyEvent.CHAR_UNDEFINED);

                component.dispatchEvent( ke );
            }
        };

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

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

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

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

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

与其尝试重新实现工具提示的显示,不如向组件添加鼠标侦听器,以便在鼠标进入和离开组件上方的区域时更改全局工具提示计时器

下面是一些示例代码:

instantTooltipComponent.addMouseListener(new MouseAdapter() 
{    
    final int defaultTimeout = ToolTipManager.sharedInstance().getInitialDelay();

    @Override
    public void mouseEntered(MouseEvent e) {
        ToolTipManager.sharedInstance().setInitialDelay(0);
    }

    @Override
    public void mouseExited(MouseEvent e) {
        ToolTipManager.sharedInstance().setInitialDelay(defaultTimeout);
    }
});

这应该会在鼠标移动到组件上时将工具提示延迟更改为零,并在鼠标离开组件时将其更改回默认延迟。

我想这是可行的。脏但有效,因为不能有两个鼠标指针。好啊你被标记为正确。编程的一个更深层次的谜团是“什么时候‘脏但能用’才是正确的?”;-)当应用程序小而简单时。对于较大的应用程序,这种黑客行为可能会开始增加,并导致各种问题。此外,对于奇怪的黑客行为(用最好的话说),也可能发生意外情况,在本例中,如果用户将鼠标放在组件上,然后将焦点更改为另一个应用程序(例如通过alt tab)然后,直到应用程序恢复焦点,鼠标退出事件才会发布。可能给你想要的,也可能不给你想要的——谁知道呢?这个解决方案很有道理,但它不起作用。我不明白为什么,行动是调用工具提示之类东西的合乎逻辑的方式。@TomášZato,嗯,你说得对。我确信它曾经起过作用,我不记得编了一个动作名:)添加了另一种方法将Ctrl+F1键发送到组件。但这只适用于可聚焦组件。我想立即显示一些悬停工具提示,我必须使用公认的答案。但我认为,如果存在这样的情况,将来我将不得不切换到更复杂的工具提示类。@TomášZato,
这将只适用于可聚焦组件,尽管
——我认为这是在使用GUI时。Swing需要知道哪个组件具有焦点,以便能够分派事件。在本例中,我们根据MouseEvent指定组件,
dispatchEvent(…)
似乎在组件没有焦点时也能工作。我更新了示例,使其也包含一个MouseListener,效果很好。无论如何,你有一个解决方案,不确定哪一个更优雅。