当JMenu存在时,JPanel#paintChildren(Graphics)的行为不正确? [英] Incorrect behavior of JPanel#paintChildren(Graphics) when a JMenu is present?

查看:121
本文介绍了当JMenu存在时,JPanel#paintChildren(Graphics)的行为不正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做什么:

创建一个 JPanel 的子类,在包含的组件之上绘制一个简单的叠加层。

What I want to do:
Create a JPanel's subclass to draw a simple overlay on top of contained components.

为什么我不使用 JLayeredPane

参见 JComponent#isOptimizedDrawingEnabled()

JMenu 出现在 JFrame ,使用重写的 paintChildren(Graphics)方法添加 JPanel ,在传递的Graphics对象中提供了一个不正确的坐标起点,如此代码示例所示:

When a JMenu is present in a JFrame, adding a JPanel with an overridden paintChildren(Graphics) method, an incorrect coordinate starting point is provided in the passed Graphics object, as observed with this code sample:

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的高度推高了。

The first string is drawn outside of JPanel (under the JMenu), even though both coordinates are non-negative.
The second string is NOT drawn at the bottom right corner. It is pushed up by the height of the JMenu.

图片

即使:

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

When AWT invokes this method, the Graphics object parameter is pre-configured with the appropriate state for drawing on this particular component:


  • 图形对象的颜色设置为组件的前景
    属性。

  • 图形对象的字体设置为组件的字体
    属性。

  • 图形对象的翻译设置为
    坐标(0 ,0)表示组件的左上角。

  • Graphics对象的剪辑矩形设置为需要重新绘制的
    组件的区域。

  • The Graphics object's color is set to the component's foreground property.
  • The Graphics object's font is set to the component's font property.
  • The Graphics object's translation is set such that the coordinate (0,0) represents the upper left corner of the component.
  • The Graphics object's clip rectangle is set to the area of the component that is in need of repainting.

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

Programs must use this Graphics object (or one derived from it) to render output. They are free to change the state of the Graphics object as necessary.

我做错了什么?

推荐答案


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

The first string is drawn outside of JPanel (under the JMenu), even though both coordinates are non-negative. The second string is NOT drawn at the bottom right corner. It is pushed up by the height of the JMenu.

在这两种情况下,请注意 drawString()期望坐标代表字符串的awt / FontMetrics.htmlrel =nofollow noreferrer>基线。字体; s上升和下降在此上下文中很有用。可能巧合的是 mb.getHeight() fm.getHeight()具有可比性。

In both cases, note that drawString() expects the coordinates to represent the baseline of the String. The font;s ascent and descent are useful in this context. It may be a coincidence that mb.getHeight() and fm.getHeight() are of comparable magnitude.

@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());
}

这篇关于当JMenu存在时,JPanel#paintChildren(Graphics)的行为不正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆