无法在同一个 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() 方法复制它,那么您根本不应该处理它.
好吧,这可能是个愚蠢的问题,也许我遗漏了什么。我对 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() 方法复制它,那么您根本不应该处理它.