我想要做的:
创建一个JPanel
的子类以在包含的组件之上绘制一个简单的叠加层。
为什么我不用JLayeredPane
?
见JComponent#isOptimizedDrawingEnabled()
。
当 aJMenu
出现在 a 中时,使用重写的方法JFrame
添加 a时,在传递的 Graphics 对象中提供了不正确的坐标起点,如以下代码示例所示: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 的高度向上推。
虽然:
当 AWT 调用此方法时,Graphics 对象参数会预先配置适当的状态以在此特定组件上绘图:
- Graphics 对象的颜色设置为组件的前景属性。
- Graphics 对象的字体设置为组件的字体属性。
- Graphics 对象的平移设置为坐标 (0,0) 表示组件的左上角。
- Graphics 对象的剪辑矩形设置为需要重新绘制的组件区域。
程序必须使用此 Graphics 对象(或从它派生的对象)来呈现输出。他们可以根据需要自由更改 Graphics 对象的状态。
我究竟做错了什么?