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