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

标签 java swing awt graphics2d

好吧,这可能是一个愚蠢的问题,也许我错过了一些东西。我对 Java 并不陌生,但也算不上专家。长话短说,我写了一个空气压缩火箭弹道模拟(不,这不是作业)。这是我的“嘿,我想学习 Java,所以让我试试这个”程序。它以图形方式模拟距离、最大高度等。现在我尝试添加第二个面板(JFrame)来显示火箭在战斗中的稳定性。

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

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

/*
* 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 对象,因此它们没有什么可用来绘制的。

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

一些一般规则

  • 切勿处置 JVM 提供给您的 Graphics 对象。
  • 在使用完创建的 Graphics 对象后,请务必对其进行处置,但仅在完全使用完毕后才进行处置。您将在每个方法结束时处理它们,并在下一个方法中完全清除它们。在这里,您应该只在 g2 上和 PaintComponent 方法的末尾调用一次 dispose。
  • 您应该在 paintComponent 方法末尾一次处理创建的 g2 变量。

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

关于java - 无法在同一 JPanel 上绘制 Rectangle2D 和 Path2D,可能重叠?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29438770/

相关文章:

Java - 卸载类

java - 无法创建数据库jdbc

java - JPA 2/Hibernate 孤儿删除仍然无法与@OneToMany 一起使用?

java - 如何在 FlowLayout 或 GridLayout 中手动放置组件?

java - 重绘导致 mouseListener 注册未发生的点击

java - 如何检查 EDT(事件调度线程)是否已完成 Java 中的事件调度

java - LibGDX 路径 (CatmullRomSpline) 恒速

java - 我从 MySql 收到异常,它不会更新表?

java - 更改 JPanel 默认图形

java - 如何在策略文件中设置java.awt.awtpermission?