可以在重量级模式下停止闪烁java工具提示吗?

问题描述 投票:0回答:1

如果在 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);
            }
        }
    );
}
}
java tooltip flicker
1个回答
1
投票

不知何故,

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);
© www.soinside.com 2019 - 2024. All rights reserved.