【问题标题】:Possible to stop flickering java tooltip in heavyweight mode?可以在重量级模式下停止闪烁的 java 工具提示吗?
【发布时间】:2014-07-07 01:31:35
【问题描述】:

类似于ToolTip flicker in Java if outside JFrame?的Q

不断更新的轻量级工具提示可以正常工作,但一旦它移出窗口边界或成为重量级(通过禁用轻量级弹出窗口),它就会变成闪烁城市。

尝试了在窗口内工作的“-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);
            }
        }
    );
}
}

【问题讨论】:

    标签: java tooltip flicker


    【解决方案1】:

    不知何故,javax.swing.RepaintManager 类可以帮助解决工具提示重绘问题。下面扩展RepaintManager的类取自第11章,重绘管理器中的示例:http://www.java.net/external?url=http://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()被禁用时,整个tooltip会在边缘边界两侧闪烁(与OP原代码中的效果相同)。

    启用installRepaintManager() 时,工具提示区域的一部分不会在边缘边界内闪烁。相反,它的另一部分在边缘边界之外闪烁。但是,与禁用installRepaintManager() 时相比,闪烁并没有那么严重。

    我知道,这是一个微妙的差异,我想它没有什么不足之处。至少,启用installRepaintManager() 时,工具提示区域中的文字有点清晰。

    即使禁用双缓冲代码,installRepaintManager() 也能按预期工作;即快速重绘重量级组件以减少闪烁。

    //panel.setDoubleBuffered(true);
    //panel.createToolTip().setDoubleBuffered(true);
    

    【讨论】:

    • 嗯...我没有看到任何区别。我发现工具提示和弹出窗口设置为不是真正的双缓冲,即硬件双缓冲 - 类的设置方式意味着这不能通过子类化等来改变
    • @mgraham:启用installRepaintManager()时,与面板重叠的工具提示区域不闪烁;另一部分闪烁。当installRepaintManager() 被禁用时,整个工具提示会闪烁。这是一个微妙的差异,我想它没有任何不足之处。至少,启用installRepaintManager() 时,工具提示区域中的文字有点清晰。
    • 是的,我现在可以看到了。我可以使用未装饰的 JFrame 制作一个虚假的工具提示,其中包含一个 JTooltip,我在整个屏幕上移动时闪烁可忽略不计,所以它似乎是工具提示使用的 HeavyWeightPopup 类特有的......对真正的双缓冲警告的怀疑......这对我来说更糟,因为我使用多行 HTML 工具提示,所以闪烁非常糟糕...... + 我想为工具提示使用半透明的重量级窗口,这样即使在组件中也会发生闪烁。我会给你一个赞成票或任何尝试,但由于缺少以前的帖子,我不允许...
    • @mgraham:我已经测试了它的半透明重量级虚假工具提示。结果?它的行为仍然与我所描述的完全一样。但是,如果我希望它位于任何窗口的顶部,我就无法获得令人满意的结果。如果我有时间,我会更新我的帖子……别担心:我并不真正关心投票系统。重要的是我们可以学习和分享我们的知识;)
    • @mgraham:抱歉,情况正好相反。它适用于setAlwaysOnTop(true)PopupFactory。但是,当setOpaque(false)
    猜你喜欢
    • 2011-10-15
    • 2012-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    相关资源
    最近更新 更多