Можно ли перестать мерцать всплывающей подсказкой Java в тяжелом режиме?

Подобный Q для мерцание всплывающей подсказки в Java, если вне JFrame?

Постоянно обновляемая легкая всплывающая подсказка работает нормально, но как только она выходит за границы окна или становится тяжелой (путем отключения легких всплывающих окон), это мерцающий город.

Пробовал подсказку «-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);
            }
        }
    );
}
}

person mgraham    schedule 31.03.2011    source источник


Ответы (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() отключен, вся всплывающая подсказка мерцает с обеих сторон границы края (это тот же эффект, что и в исходном коде OP).

Когда installRepaintManager() включен, одна часть области всплывающей подсказки не мерцает внутри границы края. Напротив, другая его часть мерцает за пределами границы края. Но мерцание не такое уж плохое по сравнению с отключенным installRepaintManager().

Я знаю, это тонкая разница, которая, я думаю, не оставляет желать лучшего. По крайней мере, слова в области всплывающей подсказки немного разборчивы, когда installRepaintManager() включен.

Даже когда коды с двойной буферизацией отключены, installRepaintManager() работает как положено; то есть тяжеловесный компонент быстро перекрашивается, чтобы уменьшить мерцание.

//panel.setDoubleBuffered(true);
//panel.createToolTip().setDoubleBuffered(true);
person eee    schedule 31.03.2011
comment
ммм... разницы не вижу. Я обнаружил, что всплывающие подсказки и всплывающие окна настроены не на двойную буферизацию, т.е. на аппаратную двойную буферизацию, а то, как настроены классы, означает, что это нельзя изменить с помощью подклассов и т. д. - person mgraham; 06.04.2011
comment
@mgraham: когда installRepaintManager() включен, часть области всплывающей подсказки, которая перекрывает панель, не мерцает; другая часть мерцает. Когда installRepaintManager() отключен, вся всплывающая подсказка мерцает. Это тонкая разница, которая, я думаю, не оставляет желать лучшего. По крайней мере, слова в области всплывающей подсказки немного разборчивы, когда installRepaintManager() включен. - person eee; 06.04.2011
comment
да, теперь я это вижу. Я могу сделать поддельную всплывающую подсказку с неукрашенным JFrame, содержащим JTooltip, который я перемещаю по всему экрану с незначительным мерцанием, поэтому кажется, что это относится к классу HeavyWeightPopup, который использует всплывающая подсказка... подозрения на истинное предостережение о двойной буферизации... Для меня это хуже, так как я использую многострочные всплывающие подсказки HTML, поэтому мерцание действительно плохое... + Я хочу использовать полупрозрачное тяжелое окно для всплывающей подсказки, чтобы мерцание возникало даже в компоненте. Я бы дал вам голос или что-то еще за попытку, но мне это не разрешено из-за отсутствия предыдущих сообщений... - person mgraham; 07.04.2011
comment
@mgraham: я проверил его на полупрозрачную поддельную всплывающую подсказку. Результат? Он по-прежнему ведет себя именно так, как я описал. Но я не мог бы добиться удовлетворительного результата, если бы я хотел, чтобы он был поверх любого окна. Я обновлю свой пост, если у меня будет время... Не волнуйтесь: меня не волнует система голосования. Важно то, что мы можем учиться и делиться своими знаниями ;) - person eee; 08.04.2011
comment
@mgraham: Извините, но все наоборот.. Это хорошо работает для setAlwaysOnTop(true) до PopupFactory. Но это праздник мерцания, когда setOpaque(false) - person eee; 09.04.2011