无法在同一个 JPanel 上绘制 Rectangle2D 和 Path2D,可能重叠吗?

Unable to draw a Rectangle2D and a Path2D on same JPanel, possible overlapping?

好吧,这可能是个愚蠢的问题,也许我遗漏了什么。我对 Java 并不陌生,但我算不上专家。长话短说,我写了一个空气压缩火箭轨迹模拟(不,这不是家庭作业)。这是我的 "hey I want to learn Java so let me try this" 程序。它以图形方式模拟距离、最大高度等。现在我正在尝试添加第二个面板 (JFrame) 以显示火箭在战斗中的稳定性。

我在 JFrame 中有一个 JPanel。在其中我有 DrawPanel class 进行绘图。我正在尝试绘制火箭。所以我需要一个矩形 body、鳍、鼻锥等。现在我已经编写了使用 Rectangle2D object 绘制 body 的方法,以及使用Path2D object。现在,当我在我的绘画方法中同时使用这两种方法时,它只绘制第一个。我已经翻转了它们,它只会绘制第一个。现在有没有 graphics2D objects 的东西,它们的空白占据了整个面板,或者我完全遗漏了什么。

我用与主程序相同的设计模式编写了一个测试程序,以便更好地尝试在不启动主程序的情况下修复此问题。它比你们通常想要的要长一点,但如果问题不在 DrawPanel class 中,我将包含它并且它会编译并 运行。另外,我确信我这样做并不是最有效的方法,因此也欢迎任何提示或指示。谢谢大家

/*
* Test program to replicate issue with main program
* Trying to draw multiple shapes, one ends up overlapping the other
*/
package shapetest;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ShapeTest extends JFrame {
    private static final long serialVersionUID = 1L;

    JPanel panel = new JPanel();
    DrawPanel drawPanel = new DrawPanel();
    Rectangle2D rocket = new Rectangle2D.Double();
    Path2D.Double topFin = new Path2D.Double();
    Path2D.Double bottomFin = new Path2D.Double();

    int scaler = 20;
    double rocketX = 0;
    double rocketY = 0;

    class DrawPanel extends JPanel {
        private static final long serialVersionUID = 1L;
        double rocketLength = 36;
        double rocketWidth = 1.5;

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

            g2.dispose();
        }

        protected void paint2D(Graphics2D g2) {

            setBackground(Color.WHITE); // Set graph background color
            g2.setColor(Color.BLACK);
            g2.setStroke(new BasicStroke(1.0f));
            g2.setFont(new Font("SansSerif", Font.BOLD, 18));
            //If I reverse the order of these two methods, it will draw
            //the rocket tube and not the fin
            drawTwoFins(g2);
            drawRocketTube(g2, rocketLength, rocketWidth);
        }

        private void drawRocketTube(Graphics2D g, double rL, double rW) {            
            double rocketL = rL * scaler;
            double rocketW = rW * scaler;
            rocketX = ((drawPanel.getWidth() / 2) - ((rocketLength * scaler) / 2));
            rocketY = ((drawPanel.getHeight() / 2) - ((rocketWidth * scaler) / 2));

            rocket.setRect(rocketX, rocketY, rocketL, rocketW);
            g.draw(rocket);

            g.dispose();
        }

        private void drawTwoFins(Graphics2D g) {
            BasicStroke stroke = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
            g.setStroke(stroke);

            rocketX = ((drawPanel.getWidth() / 2) - ((rocketLength * scaler) / 2));
            rocketY = ((drawPanel.getHeight() / 2) - ((rocketWidth * scaler) / 2));

            double topStartX = (rocketX + (4 * scaler));
            double topStartY = rocketY;
            double bottomStartX = (rocketX + (4 * scaler));
            double bottomStartY = (rocketY + (rocketWidth * scaler));

            double xTopFin[] = {topStartX, (topStartX - (2 * scaler)), (topStartX - (5 * scaler)), (topStartX - (3 * scaler))};
            double yTopFin[] = {topStartY, (topStartY - (2 * scaler)), (topStartY - (2 * scaler)), topStartY};
            double xBottomFin[] = {bottomStartX, (bottomStartX - (2 * scaler)), (bottomStartX - (5 * scaler)), 
                               (bottomStartX - (3 * scaler))};
            double yBottomFin[] = {bottomStartY, (bottomStartY + (2 * scaler)), (bottomStartY + (2 * scaler)), bottomStartY};

            topFin.moveTo(xTopFin[0], yTopFin[0]);
            bottomFin.moveTo(xBottomFin[0], yBottomFin[0]);

            for (int i = 1; i < xTopFin.length; i++) {
                topFin.lineTo(xTopFin[i], yTopFin[i]);
                bottomFin.lineTo(xBottomFin[i], yBottomFin[i]);
            }

            g.draw(topFin);
            g.draw(bottomFin);
            g.dispose();
        }    
    }    

    private void initComponents() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(panel);
        panel.setPreferredSize(new Dimension(850, 300));
        panel.setLayout(new BorderLayout());
        panel.add(drawPanel, BorderLayout.CENTER);
        pack();
        setLocationRelativeTo(null);
    }

    public ShapeTest() {
        initComponents();
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ShapeTest().setVisible(true);
            }
        });
    }  
}

你所有的绘图方法都以 g.dispose() 结尾,但是当你这样做时,下一个绘图方法就完全不走运了,因为你已经有效地抹杀了 图形对象,所以他们没有什么可以画的。

解决方案:不要继续处置您的 Graphics 对象。

一些通用规则

  • 切勿处置 JVM 提供给您的 Graphics 对象。
  • 使用完创建的 Graphics 对象后,一定要处理掉它们,但只有在完全用完后才处理。您在每个方法的末尾处理它们,为下一个方法完全清除它们。在这里,您应该只在 g2 上和 paintComponent 方法的末尾调用一次 dispose。
  • 您应该在 paintComponent 方法结束时 处理一次 创建的 g2 变量。

就此而言,我不确定您是否需要复制 Graphics 对象,如果您不通过 create() 方法复制它,那么您根本不应该处理它.