如果在 JFrame 之外,类似于 Java 中的 ToolTip 闪烁问题?
不断更新的轻量级工具提示效果很好,但一旦它移出窗口范围或变得重量级(通过禁用轻量级弹出窗口),它就会闪烁。
尝试了“-Dsun.awt.noerasebackground = true”提示,该提示在窗口内工作,但以牺牲其他组件上的一些绘画工件为代价(此示例只是一个空白面板)。在窗口边界之外它没有帮助,仍然有可怕的闪烁量。
有人知道如何解决这个问题吗?还是目前还不可能?
示例在此代码中 -->
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
public class JTooltipFlickerTest extends JFrame {
JPanel panel;
static public void main (final String[] args) {
new JTooltipFlickerTest ();
}
public JTooltipFlickerTest () {
super ();
//ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);
//ToolTipManager.sharedInstance().setReshowDelay(0);
setTitle (this.getClass().toString());
setSize (1024, 768);
this.getContentPane().setLayout (new BorderLayout());
SwingUtilities.invokeLater (
new Runnable () {
@Override
public void run() {
panel = new JPanel ();
final MouseAdapter ma = new MouseAdapter () {
public void mouseMoved (final MouseEvent e) {
panel.setToolTipText ("x: "+e.getX()+", y: "+e.getY());
}
};
panel.addMouseMotionListener(ma);
//panel.setDoubleBuffered(true);
//panel.createToolTip().setDoubleBuffered(true);
JTooltipFlickerTest.this.getContentPane().add (panel, "Center");
JTooltipFlickerTest.this.setVisible (true);
}
}
);
}
}
不知何故,
javax.swing.RepaintManager
类可以帮助解决工具提示重绘问题。下面扩展 RepaintManager
的类取自 Filthy Rich Client 书中的示例(关于 Swing),第 11 章,重绘管理器:https://web.archive.org/web/20130105122825/www .curious-creature.org/2007/07/22/repaint-manager-demos-chapter-11/
它被修改为重新绘制
JTooltipFlickerTest
的内容面板...
尝试注释掉构造函数中的
installRepaintManager()
调用,你会看到差异...
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
public class JTooltipFlickerTest extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
JPanel panel;
static public void main (final String[] args) {
new JTooltipFlickerTest ();
}
public JTooltipFlickerTest () {
super ();
panel = new JPanel ();
setTitle (this.getClass().toString());
setSize (1024, 768);
this.getContentPane().setLayout (new BorderLayout());
SwingUtilities.invokeLater (
new Runnable () {
@Override
public void run() {
final MouseAdapter ma = new MouseAdapter () {
public void mouseMoved (final MouseEvent e) {
panel.setToolTipText ("x: "+e.getX()+", y: "+e.getY());
}
};
panel.addMouseMotionListener(ma);
panel.setDoubleBuffered(true);
panel.createToolTip().setDoubleBuffered(true);
JTooltipFlickerTest.this.getContentPane().add (panel, "Center");
JTooltipFlickerTest.this.setVisible (true);
}
}
);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
installRepaintManager();
}
private void installRepaintManager() {
ReflectionRepaintManager manager = new ReflectionRepaintManager();
RepaintManager.setCurrentManager(manager);
}
private class ReflectionRepaintManager extends RepaintManager {
public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
int lastDeltaX = c.getX();
int lastDeltaY = c.getY();
Container parent = c.getParent();
while (parent instanceof JComponent) {
if (!parent.isVisible()) {
return;
}
if (parent instanceof JTooltipFlickerTest) {
x += lastDeltaX;
y += lastDeltaY;
int gap = getContentPane().getHeight() - h - y;
h += 2 * gap + h;
lastDeltaX = lastDeltaY = 0;
c = (JComponent) parent;
}
lastDeltaX += parent.getX();
lastDeltaY += parent.getY();
parent = parent.getParent();
}
super.addDirtyRegion(c, x, y, w, h);
}
}
}
已编辑
当
installRepaintManager()
禁用时,整个工具提示在边缘边界两侧闪烁(与OP原始代码中的效果相同)。
启用
installRepaintManager()
时,工具提示区域的一部分不会在边缘边界内部闪烁。相反,它的另一部分在边缘边界之外闪烁。但是,与禁用 installRepaintManager()
时相比,闪烁并没有那么严重。
我知道,这是一个微妙的差异,我想它没有什么值得期待的。至少,当启用
installRepaintManager()
时,工具提示区域中的文字有点清晰。
即使双缓冲代码被禁用,
installRepaintManager()
也能按预期工作;也就是说,快速重新绘制重量级组件以减少闪烁。
//panel.setDoubleBuffered(true);
//panel.createToolTip().setDoubleBuffered(true);