在不继承JFrame的情况下在JFrame上绘制

3

我的应用程序不是以JFrame为导向的,它只是用于输出。我只需要能够告诉它在这里画一个矩形,现在清除屏幕,重复几百次。为了做到这一点,我在我的主函数中编写了以下代码,据我理解,应该将整个JFrame清除为漂亮的蓝色背景色。

JFrame frame = new JFrame("Maze Master Premium Super-Deluxe V199.39");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int resolution = 20;
int frameWidth = horiz * resolution;
int frameHeight = vert * resolution;
frame.setMinimumSize(new Dimension(frameWidth, frameHeight));
frame.setSize(frameWidth, frameHeight);
frame.pack();
frame.setVisible(true);
frame.toFront();

Graphics g = frame.getGraphics();
g.setPaintMode();
g.setColor(Color.BLUE);
//Clear background
g.fillRect(0, 0, frameWidth, frameHeight);
frame.update(g);

然而,当我运行这段代码时,JFrame 以其默认的浅灰色背景显示。 我必须让我的类扩展 JFrame 吗?还是仅使用 frame.update(g) 就足够了,只是我做错了什么?


1
参考资料:自定义绘图Swing中的并发 - ignis
1
  1. 不要在AWT事件分派线程之外的线程中调用AWT或Swing方法。
  2. 子类化JPanel(而不是JFrame),并覆盖paintComponent()方法以调用super.paintComponent(),然后进行自定义绘制。
- ignis
2
你可以使用 "frame.getContentPane().setBackground(Colour.BLUE)"。这样可以避免不必要的矩形。 - cworner1
更改背景颜色的给定代码仅被调用一次。如果框架被重新绘制,您的更改将消失。PaintListener 的目的是在重新绘制时得到通知。 - f4lco
@phineas PaintListener是什么?以前从未见过。 - MadProgrammer
1个回答

3
从您的问题中,很难准确地了解您想要实现什么。您只是想更改框架的背景颜色还是执行一些自定义绘画吗?
这个 Graphics g = frame.getGraphics() 不是一个好方法。除了 getGraphics 可能返回 null 之外,Java 中的图形是无状态的,这意味着您用来绘制的图形上下文可能会在绘制周期之间更改,您永远不应该依赖于它或保留对其的引用。
除了方法错误之外,JFrame 包含多个组件,这些组件在其上方呈现,因此即使此方法有效,您也看不到任何区别,因为实际上其他组件(JRootPane 和其内容窗格)覆盖了该框架。
自定义绘画应在 Component 绘画方法之一中进行。
以下示例使用多种技术更改和更新框架的内容。
首先,它将内容窗格替换为我们自己的组件。这总是必需的,但因为我正在对框架进行自定义绘画,所以这是最简单的方法。我可以简单地添加 PaintPane 到框架上以获得类似的结果。
其次,我使用 setBackground 更改我的组件的背景。
第三,我重写 paintComponent 以在我的组件上执行自定义绘画。
public class SimplePaint01 {

    public static void main(String[] args) {
        new SimplePaint01();
    }

    public SimplePaint01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.setContentPane(new PaintPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class PaintPane extends JPanel {

        private int angle = 0;
        private Rectangle shape = new Rectangle(0, 0, 100, 100);

        public PaintPane() {
            setBackground(Color.RED);
            Timer timer = new Timer(16, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    angle += 5;
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int x = ((getWidth() - shape.width) / 2);
            int y = ((getHeight() - shape.height) / 2);

            shape.x = x;
            shape.y = y;

            g2d.setColor(Color.BLUE);
            g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(angle), x + (shape.width / 2), y + (shape.height / 2)));
            g2d.fill(shape);

            g2d.dispose();
        }

    }

}

那么,JFrame会不断地重绘吗?问题在于:我需要绘制的东西保持不变,并且我需要从一个不断添加线条和圆形到框架中的应用程序中绘制可变数量的东西。有没有办法让它不要重绘? - Miles
1
简单的答案是 - 不,你不能(也不应该)阻止Swing尝试重新绘制。你应该做的是要么将你想要的内容绘制到一个后备缓冲区(如BufferedImage)中,并在每次重绘发生时绘制它,要么以某种方式重新生成视图。 - MadProgrammer
1
你应该做的是将你想要的内容绘制到一个后备缓冲区(比如BufferedImage)中,然后在一个JLabel中显示它(这是另一种策略)。 - Andrew Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接