2011-03-31 58 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