2012-08-12 14 views
4

我想要做的事:
創建一個JPanel的子類,在包含的組件頂部繪製一個簡單的覆蓋圖。當JMenu存在時,JPanel#paintChildren(圖形)的行爲不正確?

爲什麼我不使用JLayeredPane
請參閱JComponent#isOptimizedDrawingEnabled()

JMenu存在於JFrame,加入JPanel與重寫paintChildren(Graphics)方法,一個不正確的座標出發點是在通過圖形提供的對象,與此代碼示例觀察:

import java.awt.Color; 
import java.awt.FontMetrics; 
import java.awt.Graphics; 

import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 
import javax.swing.JPanel; 
import javax.swing.JTextArea; 
import javax.swing.SwingUtilities; 

public final class Sscce { 
    public static void main(String[] args) { 
     try { 
      SwingUtilities.invokeAndWait(new Runnable() { 
       @Override 
       public void run() { 
        // a normal frame 
        JFrame f = new JFrame(); 

        // set up a simple menu 
        JMenuBar mb = new JMenuBar(); 
        JMenu m = new JMenu("Test"); 
        JMenuItem mi = new JMenu("Whatever"); 
        m.add(mi); 
        mb.add(m); 
        f.setJMenuBar(mb); 

        // a panel with a simple text overlay over components. 
        // works much faster than JLayeredPane, which doesn't have 
        // isOptimizedDrawingEnabled() 
        JPanel p = new JPanel() { 
         @Override 
         public void paint(Graphics g) { 
          // I'm not so stupid to draw stuff here 
          super.paint(g); 
          // JavaDoc: delegates to paintComponent, paintBorder, paintChildren 
          // in that order 
         } 

         @Override 
         protected void paintComponent(Graphics g) { 
          super.paintComponent(g); 

          // it is common knowledge that children are painted after parent 
          Graphics tmp = g.create(); 
          try { 
           tmp.setColor(Color.MAGENTA); 
           tmp.fillRect(0, 0, getWidth(), getHeight()); 
          } finally { 
           tmp.dispose(); 
          } 
         } 

         @Override 
         protected void paintChildren(Graphics g) { 
          super.paintChildren(g); 

          // draw some text 
          FontMetrics fm = g.getFontMetrics(); 
          // will be drawn outside panel; under menu 
          g.drawString("TEST TOP/LEFT", 0 + getX(), 0 + getY()); 
          final String s = "TEST BOTTOM/RIGHT"; 
          // will be drawn noticeably above the bottom 
          g.drawString(s, 
            getWidth() - fm.charsWidth(s.toCharArray(), 0, s.length()), 
            getHeight() - fm.getHeight()); 
         } 
        }; 
        // add something to the panel 
        p.add(new JTextArea(10, 15)); 
        f.add(p); 

        f.pack(); 
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        f.setVisible(true); 
       } 
      }); 
     } catch (Throwable t) { 
      // this is a SSCCE 
     } 
    } 
} 

的第一個字符串是在JPanel之外(在JMenu下)繪製的,儘管兩個座標都是非負的。
第二個字符串不在右下角繪製。它被JMenu的高度推高。

Image

即使:

當AWT調用此方法,該圖形對象的參數是預先配置有適當的狀態該特定組件上繪製:

  • Graphics對象的顏色設置爲組件的前景 屬性。
  • Graphics對象的字體被設置爲組件的字體 屬性。
  • 圖形對象的翻譯被設置爲使得座標(0,0)代表組件的左上角。
  • Graphics對象的剪輯矩形設置爲需要重繪的 組件的區域。

程序必須使用此Graphics對象(或從它派生的)來呈現輸出。他們可以根據需要自由更改Graphics對象的狀態。

我在做什麼錯?

+0

一個)看不到在所有的B在左上角的文本)的下角的文本是在相同的位置瓦特/輸出菜單欄c)中上述的文本textarea在打入該區域時被「塗滿」 - 總體上:簡單地不要在paintChildren中進行自定義繪畫;-)而是使用layeredPane,疊加布局或JLayer(jdk7)/ JXLayer(jdk6) – kleopatra 2012-08-13 08:19:23

+0

@kleopatra右:左上角的字符串在原點處用基線繪製;只有下行可見,但沒有特定的字符串。我已經更新了我的答案。 – trashgod 2012-08-13 10:58:55

回答

7

第一個字符串繪製在JPanel之外(在JMenu之下),即使兩個座標都是非負數。第二個字符串不在右下角繪製。它被推高了JMenu的高度。

在這兩種情況下,請注意drawString()預計座標來表示Stringbaseline。字體的上升和下降在這種情況下很有用。 mb.getHeight()fm.getHeight()的數量可能相當可能是巧合。

enter image description here

@Override 
protected void paintChildren(Graphics g) { 
    super.paintChildren(g); 

    // draw some text 
    FontMetrics fm = g.getFontMetrics(); 
    // will be drawn outside panel; under menu 
    g.drawString("TEST TOP/LEFT", 0, fm.getAscent()); 
    final String s = "TEST BOTTOM/RIGHT"; 
    // will be drawn noticeably above the bottom 
    g.drawString(s, getWidth() - fm.stringWidth(s), 
     getHeight() - fm.getDescent()); 
} 
+0

參見[*初始線程*](http://download.oracle.com/javase/tutorial/uiswing/concurrency/initial.html)。 – trashgod 2012-08-12 17:11:51

+0

我不是在'contentPane'中繪畫,我是使用JPanel。我不重寫'paint(Graphics)'。順便說一句,同樣的文檔指出'paintChildren(Graphics)'是在'paintComponent(Graphics)'之後完成的,它覆蓋了前者無用的 - 這就是我重寫'paintChildren'的原因。 – afk5min 2012-08-13 07:47:41

+0

我對內容窗格的錯誤;謝謝你更新你的sscce。我相信菜單欄是一個分心;更上面。 – trashgod 2012-08-13 10:51:17