Java Swing:;永久性工具提示“;在应用程序';s JFrame

Java Swing:;永久性工具提示“;在应用程序';s JFrame,java,swing,tooltip,mouseevent,hint,Java,Swing,Tooltip,Mouseevent,Hint,我想创建一个类似于工具提示(提示)的小窗口,该窗口将根据请求弹出,然后在应用程序的JFrame上的任意位置跟随鼠标光标,直到它被销毁。它实际上是一条全局提示消息,要求用户执行特定的任务(在许多不同的窗口之间),一旦用户执行了,它就会消失。例如: GlobalToolTip panelHint = new GlobalToolTip("Global hint message."); panelHint.show(); //Will remain visible and foll

我想创建一个类似于工具提示(提示)的小窗口,该窗口将根据请求弹出,然后在应用程序的
JFrame
上的任意位置跟随鼠标光标,直到它被销毁。它实际上是一条全局提示消息,要求用户执行特定的任务(在许多不同的窗口之间),一旦用户执行了,它就会消失。例如:

GlobalToolTip panelHint = new GlobalToolTip("Global hint message.");
panelHint.show(); //Will remain visible and follow mouse
... //Waiting for user to perform a specific action or cancel
panelHint.hide(); //Hidden/destroyed here
我希望创建自己的类,从
JToolTip
/
JPanel
扩展,或者尽可能覆盖默认的工具提示行为。也许使用应用程序JFrame的
JLayeredPane
或glassPane? 我检查了一些其他的解决方案,但都只适用于单个组件的行为。我还试着在玻璃窗格上画一个JPanel,但在其他一些窗口内容上画得不好。也许我没有在正确的地方调用它的绘制方法


这似乎是一个很容易解决的问题,但我一直无法解决。任何帮助都将不胜感激。

就我个人而言,我不会为玻璃窗格而烦恼,也不会为试图让JToolTip或ToolTimManager做他们不想做的事情而烦恼。我会制作一个模拟JToolTip的JLabel:

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Window;

import java.awt.event.MouseEvent;
import java.awt.event.AWTEventListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class FollowTip {
    private JWindow tip;

    private final AWTEventListener mouseHandler = e -> {
        Window window = tip.getOwner();
        MouseEvent event = null;

        switch (e.getID()) {
            case MouseEvent.MOUSE_ENTERED:
            case MouseEvent.MOUSE_MOVED:
            case MouseEvent.MOUSE_DRAGGED:
                event = (MouseEvent) e;
                if (window.isAncestorOf(event.getComponent())) {
                    Point loc = event.getLocationOnScreen();
                    tip.setLocation(loc.x + 10, loc.y + 10);
                    tip.setVisible(true);
                }
                break;
            case MouseEvent.MOUSE_EXITED:
                event = (MouseEvent) e;
                Point p = SwingUtilities.convertPoint(
                    event.getComponent(), event.getPoint(), window);
                if (!window.contains(p)) {
                    tip.setVisible(false);
                }
                break;
            default:
                break;
        }
    };

    public FollowTip(String text,
                     Window window) {

        JLabel tipLabel = new JLabel(text);

        tipLabel.setForeground(UIManager.getColor("ToolTip.foreground"));
        tipLabel.setBackground(UIManager.getColor("ToolTip.background"));
        tipLabel.setFont(UIManager.getFont("ToolTip.font"));
        tipLabel.setBorder(UIManager.getBorder("ToolTip.border"));

        tip = new JWindow(window);
        tip.setType(Window.Type.POPUP);
        tip.setFocusableWindowState(false);
        tip.getContentPane().add(tipLabel);
        tip.pack();
    }

    public void activate() {
        Window window = tip.getOwner();
        window.getToolkit().addAWTEventListener(mouseHandler,
            AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);

        Point p = window.getMousePosition();
        if (p != null) {
            SwingUtilities.convertPointToScreen(p, window);
            tip.setLocation(p.x + 10, p.y + 10);
            tip.setVisible(true);
        }
    }

    public void deactivate() {
        Window window = tip.getOwner();
        window.getToolkit().removeAWTEventListener(mouseHandler);

        tip.setVisible(false);
    }

    static void showWindow() {
        Object[][] data = new Object[12][];
        Object[] headings = new Object[data.length];
        for (int i = 0; i < data.length; i++) {
            data[i] = new Object[data.length];
            for (int j = 0; j < data[i].length; j++) {
                data[i][j] = (i + 1) * (j + 1);
            }
            headings[i] = i;
        }

        JTable table = new JTable(data, headings);

        JToggleButton button = new JToggleButton("Active");
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(button);

        JFrame frame = new JFrame("FollowTip");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new JScrollPane(table));
        frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

        FollowTip tip = new FollowTip("This is a tip", frame);

        button.addActionListener(e -> {
            if (button.isSelected()) {
                tip.activate();
            } else {
                tip.deactivate();
            }
        });
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> showWindow());
    }
}
import java.awt.AWTEvent;
导入java.awt.BorderLayout;
导入java.awt.Component;
导入java.awt.EventQueue;
导入java.awt.Point;
导入java.awt.Window;
导入java.awt.event.MouseEvent;
导入java.awt.event.AWTEventListener;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.JScrollPane;
导入javax.swing.JTable;
导入javax.swing.JToggleButton;
导入javax.swing.JWindow;
导入javax.swing.SwingUtilities;
导入javax.swing.UIManager;
公共类跟随提示{
私人窗口提示;
专用最终AWTEventListener mouseHandler=e->{
Window=tip.getOwner();
MouseEvent事件=null;
开关(如getID()){
case MouseEvent.MOUSE_输入:
case MouseEvent.MOUSE_已移动:
case MouseEvent.MOUSE_拖动:
事件=(MouseEvent)e;
if(window.isAncestorOf(event.getComponent())){
Point loc=event.getLocationOnScreen();
提示设置位置(位置x+10,位置y+10);
提示:设置可见(真);
}
打破
case MouseEvent.MOUSE_退出:
事件=(MouseEvent)e;
点p=SwingUtilities.convertPoint(
event.getComponent(),event.getPoint(),window);
如果(!window.contains(p)){
提示:设置可见(假);
}
打破
违约:
打破
}
};
公共跟随提示(字符串文本,
(窗口){
JLabel tipLabel=新JLabel(文本);
setForeground(UIManager.getColor(“ToolTip.foreground”);
setBackground(UIManager.getColor(“ToolTip.background”);
setFont(UIManager.getFont(“ToolTip.font”);
tipLabel.setboorder(UIManager.getBorder(“ToolTip.border”);
tip=新窗口(窗口);
设置类型(Window.Type.POPUP);
提示:setFocusableWindowsState(false);
tip.getContentPane().add(tipLabel);
tip.pack();
}
公开作废激活(){
Window=tip.getOwner();
window.getToolkit().addAWTEventListener(鼠标手柄,
AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
点p=window.getMousePosition();
如果(p!=null){
SwingUtilities.convertPointToScreen(p,窗口);
提示:设置位置(p.x+10,p.y+10);
提示:设置可见(真);
}
}
公开作废{
Window=tip.getOwner();
getToolkit().removeAWTEventListener(mouseHandler);
提示:设置可见(假);
}
静态void showWindow(){
对象[][]数据=新对象[12][];
Object[]headers=新对象[data.length];
对于(int i=0;i{
if(button.isSelected()){
tip.activate();
}否则{
tip.deactivate();
}
});
}
公共静态void main(字符串[]args){
invokeLater(()->showWindow());
}
}

向我们展示您的GlassPane解决方案的一些代码,这将是我的建议。否则,我们都会浪费时间想出一个解决方案,让您告诉我们,当超过X组件时,它不起作用。如果你展示了一些代码,我们可以用它来重现这个问题,也许我们可以想出一个solution@DavidKroukamp我准备发布一些代码(经过清理以隐藏项目外部性),但VGR的优雅解决方案完全符合我的要求,无需工具提示或玻璃窗格,所以我选择了这条路线。谢谢你的优雅解决方案,它大部分都有效!主框架中的某些区域