-
Bug
-
Resolution: Duplicate
-
P4
-
8u231, 11.0.5, 13, 14
-
x86_64
-
windows_10
ADDITIONAL SYSTEM INFORMATION :
Currently every system / Java is affected
A DESCRIPTION OF THE PROBLEM :
A developer should be able to force the tooltips to be displayed in a heavyweight popup rather than in a medium weight popup.
At the moment you can use illegal reflective access to force the PopupManager to display the popup in a heavyweight popup with the following code:
protected void installDefaults(JPanel p) {
super.installDefaults(p);
p.setFont(AbstractLookAndFeel.getTheme().getControlTextFont());
// We don't want medium weight popups for tool tips, so we try to force heavy weight popups.
try {
Class clazz = Class.forName("javax.swing.ClientPropertyKey");
Field field = clazz.getDeclaredField("PopupFactory_FORCE_HEAVYWEIGHT_POPUP");
field.setAccessible(true);
p.putClientProperty(field.get(null), Boolean.TRUE);
} catch (Exception ex) {
}
}
But since such a reflective access to the enum javax.swing.ClientPropertyKey is illegal (and will be removed in future releases) we do not have any chance to force the tooltips to be shown in a heavyweight popup.
In the JPopupMenu you have the option to set "setLightWeightPopupEnabled(false)" to force a heavywight popup because of
if (isLightWeightPopupEnabled()) {
popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
} else {
popupFactory.setPopupType(PopupFactory.HEAVY_WEIGHT_POPUP);
}
but if you do the same in the "ToolTipManager.setLightWeightPopupEnabled(false)" you can only force a medium weight popup because of
if (lightWeightPopupEnabled) {
int y = getPopupFitHeight(popupRect, insideComponent);
int x = getPopupFitWidth(popupRect,insideComponent);
if (x>0 || y>0) {
popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
} else {
popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
}
}
else {
popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
}
In addition, there is also a field "heavyWeightPopupEnabled" inside the ToolTipManager which is not used..
There should be at least one way to force a heavy weight popup in the ToolTipManager. Furthermore a different behavior between the JPopupMenu.setLightWeightPopupEnabled(false) and ToolTipManager.setLightWeightPopupEnabled(false) should be avoided!
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Just add a JLabel to a JPanel and set a tooltip to the JLabel. Check if the tooltip is being rendered in a lightweight or mediumweight popup.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
you should be able to force the tooltip to be rendered in a heavyweight popup either via
ToolTipManager.setLightWeightPopupEnabled(false) (to be consistent with the JPopupMenu) or add a new method ToolTipManager.setHeavyWeightPopupEnabled(false) (to use the unused field heavyWeightPopupEnabled inside the ToolTipManager)
ACTUAL -
you need reflection to achieve the tooltip to be displayed in a heavyweight popup which will not be possible any more in future releases
---------- BEGIN SOURCE ----------
// -*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
// @homepage@
package example;
import java.awt.*;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.swing.*;
public final class MainPanel extends JPanel {
private MainPanel() {
super();
JLabel label = makeLabel("FORCE_HEAVYWEIGHT_POPUP", Color.PINK);
ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override public Void run() {
try {
Field field;
if (System.getProperty("java.version").startsWith("1.6.0")) {
// https://community.oracle.com/thread/1357949 ComboBox scroll and selected/highlight on glasspane
// Class<?> clazz = Class.forName("javax.swing.PopupFactory"); // errorprone: LiteralClassName
// field = clazz.getDeclaredField("forceHeavyWeightPopupKey");
field = PopupFactory.class.getDeclaredField("forceHeavyWeightPopupKey");
} else { // JDK 1.7.0, 1.8.0
Class<?> clazz = Class.forName("javax.swing.ClientPropertyKey");
field = clazz.getDeclaredField("PopupFactory_FORCE_HEAVYWEIGHT_POPUP");
}
field.setAccessible(true);
label.putClientProperty(field.get(null), Boolean.TRUE);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException ex) {
throw new UnsupportedOperationException(ex);
}
return null;
}
});
JComponent glass = new JPanel(new BorderLayout()) {
private final Color backgroundColor = new Color(0x64_64_64_C8, true);
@Override protected void paintComponent(Graphics g) {
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
glass.setOpaque(false);
glass.add(makeLabel("Default: ToolTipText", Color.ORANGE), BorderLayout.WEST);
glass.add(label, BorderLayout.EAST);
glass.add(Box.createVerticalStrut(60), BorderLayout.SOUTH);
EventQueue.invokeLater(() -> {
getRootPane().setGlassPane(glass);
getRootPane().getGlassPane().setVisible(true);
});
setPreferredSize(new Dimension(320, 240));
}
private static JLabel makeLabel(String title, Color color) {
JLabel label = new JLabel(title);
label.setOpaque(true);
label.setBackground(color);
label.setToolTipText("1234567890");
return label;
}
public static void main(String[] args) {
EventQueue.invokeLater(MainPanel::createAndShowGui);
}
private static void createAndShowGui() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
Toolkit.getDefaultToolkit().beep();
}
JFrame frame = new JFrame("@title@");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
actual workaround is reflection, but this will not work in future releases
FREQUENCY : always
Currently every system / Java is affected
A DESCRIPTION OF THE PROBLEM :
A developer should be able to force the tooltips to be displayed in a heavyweight popup rather than in a medium weight popup.
At the moment you can use illegal reflective access to force the PopupManager to display the popup in a heavyweight popup with the following code:
protected void installDefaults(JPanel p) {
super.installDefaults(p);
p.setFont(AbstractLookAndFeel.getTheme().getControlTextFont());
// We don't want medium weight popups for tool tips, so we try to force heavy weight popups.
try {
Class clazz = Class.forName("javax.swing.ClientPropertyKey");
Field field = clazz.getDeclaredField("PopupFactory_FORCE_HEAVYWEIGHT_POPUP");
field.setAccessible(true);
p.putClientProperty(field.get(null), Boolean.TRUE);
} catch (Exception ex) {
}
}
But since such a reflective access to the enum javax.swing.ClientPropertyKey is illegal (and will be removed in future releases) we do not have any chance to force the tooltips to be shown in a heavyweight popup.
In the JPopupMenu you have the option to set "setLightWeightPopupEnabled(false)" to force a heavywight popup because of
if (isLightWeightPopupEnabled()) {
popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
} else {
popupFactory.setPopupType(PopupFactory.HEAVY_WEIGHT_POPUP);
}
but if you do the same in the "ToolTipManager.setLightWeightPopupEnabled(false)" you can only force a medium weight popup because of
if (lightWeightPopupEnabled) {
int y = getPopupFitHeight(popupRect, insideComponent);
int x = getPopupFitWidth(popupRect,insideComponent);
if (x>0 || y>0) {
popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
} else {
popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
}
}
else {
popupFactory.setPopupType(PopupFactory.MEDIUM_WEIGHT_POPUP);
}
In addition, there is also a field "heavyWeightPopupEnabled" inside the ToolTipManager which is not used..
There should be at least one way to force a heavy weight popup in the ToolTipManager. Furthermore a different behavior between the JPopupMenu.setLightWeightPopupEnabled(false) and ToolTipManager.setLightWeightPopupEnabled(false) should be avoided!
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Just add a JLabel to a JPanel and set a tooltip to the JLabel. Check if the tooltip is being rendered in a lightweight or mediumweight popup.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
you should be able to force the tooltip to be rendered in a heavyweight popup either via
ToolTipManager.setLightWeightPopupEnabled(false) (to be consistent with the JPopupMenu) or add a new method ToolTipManager.setHeavyWeightPopupEnabled(false) (to use the unused field heavyWeightPopupEnabled inside the ToolTipManager)
ACTUAL -
you need reflection to achieve the tooltip to be displayed in a heavyweight popup which will not be possible any more in future releases
---------- BEGIN SOURCE ----------
// -*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
// @homepage@
package example;
import java.awt.*;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.swing.*;
public final class MainPanel extends JPanel {
private MainPanel() {
super();
JLabel label = makeLabel("FORCE_HEAVYWEIGHT_POPUP", Color.PINK);
ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override public Void run() {
try {
Field field;
if (System.getProperty("java.version").startsWith("1.6.0")) {
// https://community.oracle.com/thread/1357949 ComboBox scroll and selected/highlight on glasspane
// Class<?> clazz = Class.forName("javax.swing.PopupFactory"); // errorprone: LiteralClassName
// field = clazz.getDeclaredField("forceHeavyWeightPopupKey");
field = PopupFactory.class.getDeclaredField("forceHeavyWeightPopupKey");
} else { // JDK 1.7.0, 1.8.0
Class<?> clazz = Class.forName("javax.swing.ClientPropertyKey");
field = clazz.getDeclaredField("PopupFactory_FORCE_HEAVYWEIGHT_POPUP");
}
field.setAccessible(true);
label.putClientProperty(field.get(null), Boolean.TRUE);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException ex) {
throw new UnsupportedOperationException(ex);
}
return null;
}
});
JComponent glass = new JPanel(new BorderLayout()) {
private final Color backgroundColor = new Color(0x64_64_64_C8, true);
@Override protected void paintComponent(Graphics g) {
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
glass.setOpaque(false);
glass.add(makeLabel("Default: ToolTipText", Color.ORANGE), BorderLayout.WEST);
glass.add(label, BorderLayout.EAST);
glass.add(Box.createVerticalStrut(60), BorderLayout.SOUTH);
EventQueue.invokeLater(() -> {
getRootPane().setGlassPane(glass);
getRootPane().getGlassPane().setVisible(true);
});
setPreferredSize(new Dimension(320, 240));
}
private static JLabel makeLabel(String title, Color color) {
JLabel label = new JLabel(title);
label.setOpaque(true);
label.setBackground(color);
label.setToolTipText("1234567890");
return label;
}
public static void main(String[] args) {
EventQueue.invokeLater(MainPanel::createAndShowGui);
}
private static void createAndShowGui() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
Toolkit.getDefaultToolkit().beep();
}
JFrame frame = new JFrame("@title@");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
actual workaround is reflection, but this will not work in future releases
FREQUENCY : always
- duplicates
-
JDK-8147521 [macosx] Internal API Usage: setPopupType used to force creation of heavyweight popup
- Resolved