在以下程序(取决于JOGL)中,JLabel
的工具提示隐藏在重量级GLCanvas
后面,当工具提示符合“#{1}}时。在GLCanvas
。
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import com.jogamp.opengl.awt.GLCanvas;
public class HeavyWeightTooltipTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);
try {
UIManager.setLookAndFeel(NimbusLookAndFeel.class.getName());
} catch (Exception aE) {
aE.printStackTrace();
}
showUI();
}
});
}
private static void showUI(){
JFrame frame = new JFrame("TestFrame");
JLabel label = new JLabel("Label with tooltip");
label.setToolTipText("A very long tooltip to ensure it overlaps with the heavyweight component");
frame.add(label, BorderLayout.WEST);
GLCanvas glCanvas = new GLCanvas();
frame.add(glCanvas, BorderLayout.CENTER);
frame.setVisible(true);
frame.setSize(300,300);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
观察
java.awt.Canvas
时,只有JOGL GLCanvas
(java.awt.Canvas
的扩展名GLCanvas
时,工具提示会正确呈现。一旦工具提示符合GLCanvas
(见帖子末尾的屏幕截图),问题就会开始。ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false)
并不重要。问题总是可以重现的如果它是相关的,我使用JOGL版本2.3.2和Java版本1.8.0_65
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)
编辑:我在JOGL的错误跟踪器中将其记录为bug 1306。
答案 0 :(得分:1)
似乎强制PopupFactory
使用重量级工具提示(而不是中等重量工具提示)可以解决问题。
这非常重要,需要您自己编写PopupFactory
或使用反射来调用PopupFactory#setPopupType
。
由于我不太热衷于编写自己的PopupFactory
,我使用了反思:
final class HeavyWeightTooltipEnforcerMac {
private static final Object LOCK = new Object();
private static PropertyChangeListener sUIManagerListener;
private HeavyWeightTooltipEnforcerMac() {
}
/**
* <p>
* Tooltips which overlap with the GLCanvas
* will be painted behind the heavyweight component when the bounds of the tooltip are contained
* in the bounds of the application.
* </p>
*
* <p>
* In that case, {@code javax.swing.PopupFactory#MEDIUM_WEIGHT_POPUP} instances are used, and
* they suffer from this bug.
* Always using {@code javax.swing.PopupFactory#HEAVY_WEIGHT_POPUP} instances fixes the issue.
* </p>
*
* <p>
* Note that the bug is only present when not using the Aqua look-and-feel.
* Aqua uses its own {@code PopupFactory} which does not suffer from this.
* </p>
*
*/
static void install() {
synchronized (LOCK) {
if (sUIManagerListener == null && isMacOS()) {
installCustomPopupFactoryIfNeeded();
sUIManagerListener = new LookAndFeelChangeListener();
UIManager.addPropertyChangeListener(sUIManagerListener);
}
}
}
private static void installCustomPopupFactoryIfNeeded() {
if (!isAquaLookAndFeel()) {
PopupFactory.setSharedInstance(new AlwaysUseHeavyWeightPopupsFactory());
}
}
private static final class LookAndFeelChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if ("lookAndFeel".equals(propertyName)) {
installCustomPopupFactoryIfNeeded();
}
}
}
private static class AlwaysUseHeavyWeightPopupsFactory extends PopupFactory {
private boolean couldEnforceHeavyWeightComponents = true;
@Override
public Popup getPopup(Component owner, Component contents, int x, int y) throws IllegalArgumentException {
enforceHeavyWeightComponents();
return super.getPopup(owner, contents, x, y);
}
private void enforceHeavyWeightComponents() {
if (!couldEnforceHeavyWeightComponents) {
return;
}
try {
Method setPopupTypeMethod = PopupFactory.class.getDeclaredMethod("setPopupType", int.class);
setPopupTypeMethod.setAccessible(true);
setPopupTypeMethod.invoke(this, 2);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException aE) {
//If it fails once, it will fail every time. Do not try again
//Consequence is that tooltips which overlap with a heavyweight component will be painted behind that component iso
//on top of it
couldEnforceHeavyWeightComponents = false;
}
}
}
}
可以在IntelliJ社区版中找到类似的修复:LafManagerImpl
类在fixPopupWeight
方法中设置自己的工厂,这会强制执行重量级弹出窗口。