4

我想要做的:
创建一个JPanel的子类以在包含的组件之上绘制一个简单的叠加层。

为什么我不用JLayeredPane
JComponent#isOptimizedDrawingEnabled()

当 aJMenu出现在 a 中时,使用重写的方法JFrame添加 a时,在传递的 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 下),即使两个坐标都是非负数。
第二个字符串不在右下角绘制。它被 JMenu 的高度向上推。

图片

虽然:

当 AWT 调用此方法时,Graphics 对象参数会预先配置适当的状态以在此特定组件上绘图:

  • Graphics 对象的颜色设置为组件的前景属性。
  • Graphics 对象的字体设置为组件的字体属性。
  • Graphics 对象的平移设置为坐标 (0,0) 表示组件的左上角。
  • Graphics 对象的剪辑矩形设置为需要重新绘制的组件区域。

程序必须使用此 Graphics 对象(或从它派生的对象)来呈现输出。他们可以根据需要自由更改 Graphics 对象的状态。

我究竟做错了什么?

4

1 回答 1

7

第一个字符串绘制在外部JPanel(在 下JMenu),即使两个坐标都是非负的。第二个字符串不在右下角绘制。它被JMenu.

在这两种情况下,请注意drawString()期望坐标代表. String字体的上升和下降在这种情况下很有用。这可能是一个巧合,mb.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 回答