Swing Tooltips not working while FocusableWindowState is false

57 views Asked by At

this problem is for some swing masters, maybe someone will be able to help me.

So I have an application which is an overlay for fullscreen game. Because of that my JFrame is set to these values

    this.setFocusableWindowState(false);
    this.setFocusable(false);
    this.setAlwaysOnTop(true);

On this JFrame I have few buttons with tooltips but the tooltips won't ever show. According to documentation

    JComponent.setTooltipText(String text)

should register itself to tooltipManager.sharedInstance but "only if component has focus bindings" <- documentation of ToolTipManager.registerComponent(JComponent component)

I tried setting

this.setFocusableWindowState(true);

for my JFrame but it results in JFrame flickering instead of being on top of the game.

Finally after a lot of tries I came up with a code which works (you should focus on parts with "tooltip magic":

  button.addMouseListener(new MouseAdapter() {
        Border prevBorder;

        @Override
        public void mouseEntered(MouseEvent e) {
            prevBorder = button.getBorder();
            button.setBorder(BorderFactory.createCompoundBorder(
                    BorderFactory.createLineBorder(AppThemeColor.ADR_SELECTED_BORDER),
                    BorderFactory.createEmptyBorder(3, 3, 3, 3)));
            button.setCursor(new Cursor(Cursor.HAND_CURSOR));

            // Tooltip magic - start
            UIManager.put("ToolTipManager.enableToolTipMode", "test");
            try {
                Method method = ToolTipManager.class.getDeclaredMethod("showTipWindow");
                Field field = ToolTipManager.class.getDeclaredField("mouseEvent");
                field.setAccessible(true);
                field.set(ToolTipManager.sharedInstance(), e);
                method.setAccessible(true);
                method.invoke(ToolTipManager.sharedInstance());
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
                     NoSuchFieldException ex) {
                ex.printStackTrace();
            }
            ToolTipManager.sharedInstance().mouseMoved(e);
            ToolTipManager.sharedInstance().mouseEntered(e);
            // Tooltip magic - end

        }

        @Override
        public void mouseExited(MouseEvent e) {
            button.setBorder(prevBorder);
            button.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            // Tooltip magic - reverse setting
            UIManager.put("ToolTipManager.enableToolTipMode", "activeApplication");
        }
    });

And here is my question:

How to do it in a way that should be possible within built in functions instead of hacking private fields and methods?

Btw. I also tried creating my own tooltip system but it resulted in a lot of other problems. If you want to know more about application and the code itself, here is the link: https://github.com/Morph21/MercuryTrade-Community-Fork

JFrame that I'm talking about here is TaskBarFrame, button creation is in ComponentsFactory.getIconButton

Here is a minimal reproducible example

import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {

    public static void main(String args[]) {
        JFrame frame = new JFrame("Tooltip test");
        frame.setVisible(true);
        frame.setFocusable(false);
        frame.setFocusableWindowState(false);
        frame.setAlwaysOnTop(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300,300);
        JButton button = new JButton("Press");
        String tooltip = "tooltip value";

        //notWorkingTooltip(button, tooltip);
        workingTooltip(button, tooltip);

        frame.getContentPane().add(button);
    }

    private static void notWorkingTooltip(JButton button, String tooltip) {
        button.setToolTipText(tooltip);
    }

    private static void workingTooltip(JButton button, String tooltip) {
        button.setToolTipText(tooltip);
        button.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseEntered(MouseEvent e) {
                UIManager.put("ToolTipManager.enableToolTipMode", "test");
                try {
                    Method method = ToolTipManager.class.getDeclaredMethod("showTipWindow");
                    Field field = ToolTipManager.class.getDeclaredField("mouseEvent");
                    field.setAccessible(true);
                    field.set(ToolTipManager.sharedInstance(), e);
                    method.setAccessible(true);
                    method.invoke(ToolTipManager.sharedInstance());
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
                         NoSuchFieldException ex) {
                    ex.printStackTrace();
                }
                ToolTipManager.sharedInstance().mouseMoved(e);
                ToolTipManager.sharedInstance().mouseEntered(e);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                UIManager.put("ToolTipManager.enableToolTipMode", "activeApplication");
            }
        });
    }
}
0

There are 0 answers