2011-03-31 60 views
2

类似Q可ToolTip flicker in Java if outside JFrame?可能停止在重量级模式中​​闪烁的java工具提示?

一个不断更新的轻量级工具提示正常,但一旦它移出窗口范围或由重量级(禁用轻量级弹出窗口),这是闪烁的城市。

尝试了“-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); 
      } 
     } 
    ); 
} 
} 

回答

0

不知何故,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的contentPane中......

尝试注释掉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); 
+0

mmm ...我没有看到任何区别。我发现的是,工具提示和弹出窗口被设置为不是真正的双缓冲,即硬件双缓冲 - 类的设置方式意味着这不能通过子类化等改变。 – mgraham 2011-04-06 10:03:11

+1

@mgraham:当启用installRepaintManager()时,与面板重叠的工具提示区域的部分不会闪烁;另一部分闪烁。当'installRepaintManager()'被禁用时,整个工具提示会闪烁。这是一个微妙的差异,我猜它没有什么值得期待的。至少,当启用'installRepaintManager()'时,工具提示区域中的单词有点清晰。 – eee 2011-04-06 16:48:03

+0

是的,我现在可以看到。我可以用一个包含JTooltip的未修饰JFrame制作一个假的工具提示,我可以忽略闪烁在整个屏幕上移动,所以它似乎特别针对工具提示使用的HeavyWeightPopup类......怀疑真正的双缓冲警告...... 这对我来说更糟,因为我使用多行HTML工具提示,因此闪烁非常糟糕...... +我想为工具提示使用半透明的重量级窗口,以便即使在组件中也会出现闪烁。 我会给你一个upvote或任何尝试,但我不允许缺乏以前的帖子... – mgraham 2011-04-06 21:43:00