4

やりたいこと:のサブクラスを
作成してJPanel、含まれているコンポーネントの上に単純なオーバーレイを描画します。

なぜ私は使用しないのJLayeredPaneですか?
を参照してくださいJComponent#isOptimizedDrawingEnabled()

JMenuが に存在する場合、オーバーライドされたメソッドでJFrameを追加すると、次のコード サンプルで見られるように、渡された Graphics オブジェクトで誤った座標の開始点が提供されます。JPanelpaintChildren(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 の下) に描画されます。
2 番目の文字列は右下隅に描画されません。JMenu の高さによって押し上げられます。

画像

それでも:

AWT がこのメソッドを呼び出すと、Graphics オブジェクト パラメーターは、この特定のコンポーネントで描画するための適切な状態で事前構成されます。

  • Graphics オブジェクトの色は、コンポーネントの foreground プロパティに設定されます。
  • Graphics オブジェクトのフォントは、コンポーネントの font プロパティに設定されます。
  • Graphics オブジェクトの平行移動は、座標 (0,0) がコンポーネントの左上隅を表すように設定されます。
  • Graphics オブジェクトのクリップ四角形は、再描画が必要なコンポーネントの領域に設定されます。

プログラムは、この Graphics オブジェクト (またはその派生オブジェクト) を使用して出力をレンダリングする必要があります。必要に応じて Graphics オブジェクトの状態を自由に変更できます。

私は何を間違っていますか?

4

1 に答える 1

7

最初の文字列は、両方の座標が負でない場合でも、外側JPanel(の下) に描画されます。JMenu2 番目の文字列は右下隅に描画されません。の高さで押し上げられJMenuます。

どちらの場合も、 は座標が のベースラインdrawString()表すことを期待していることに注意してください。フォントのアセントとディセントは、このコンテキストで役立ちます。とが同等の大きさであることは偶然かもしれません。Stringmb.getHeight()fm.getHeight()

ここに画像の説明を入力

@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());
}
于 2012-08-12T17:10:59.493 に答える