Java Swing 添加 JPanel 到 JPanel
Java Swing Add JPanel to JPanel
情况
我目前正在尝试使用 Java 的 Swing 构建 2D 游戏。为此,我有我的 main class Puzzle
,它是 subclassing JFrame
。在我的框架中,我添加了我的主要 JPanel
,它由几个 JPanel
加在一起组成(每个都是一个新片段)。
编辑 2: PlayingField
是我的模型,它将存储每件作品的当前位置。
可以用鼠标 select 一块(计划是突出显示它)并用箭头键移动它,只要下一步(一个完整的单元格,所以大约 100 像素)不是其他作品之一。截至目前,PlayingField
不存储任何数据,因为碎片丢失。
private void createAndShowGui() {
// The playing-field with a 4x6 grid.
PlayingField field = new PlayingField(4, 6);
JPanel mainPanel = new ComputerView(field);
setTitle("Puzzle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 600);
add(mainPanel);
setVisible(true);
}
上述方法将创建我的框架并添加主面板。以下方法是我的主面板,它向自身添加了几个 JPanel
。
public ComputerView(PlayingField field) {
this.field = field;
this.setLayout(null);
JPanel topLeft = new GamingPiece(PlayingField.TOP_LEFT);
add(topLeft);
JPanel topRight = new GamingPiece(PlayingField.TOP_RIGHT);
add(topRight);
JPanel bottomLeft = new GamingPiece(PlayingField.BOTTOM_LEFT);
add(bottomLeft);
}
每个 GamingPiece
或者我的子 JPanel
都在画一个基本的部分(我只画一个并旋转其他部分,因为它们都由相同的任意形状组成)。 GamingPiece
class 也从 class 继承 JPanel
并调用 JPanel#paintComponent()
方法来绘制棋子。
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.YELLOW);
g2.fillPolygon(pieceX, pieceY, pieceX.length);
}
问题和我的问题
由于我是 Java 的新手,所以我真的不知道如何正确操作。如果我通过创建一个新对象并将其添加到主面板来添加我的片段,它不会显示所有片段,只会显示最后添加的片段。有些甚至似乎不起作用,即使它们是唯一添加的(为了解释我的情况:我有相同任意形状的碎片只是旋转不同但使用 Graphics2D#rotate()
似乎不起作用很好)。
我希望我已经很好地解释了我的情况和我的问题,以便你们能帮助我。提前致谢!
编辑:
我的代码
Puzzle.java
package programming.schimmler;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import programming.schimmler.model.PlayingField;
import programming.schimmler.view.ComputerView;
public class Puzzle extends JFrame {
...
Invoking the createAndShowGui()
...
private void createAndShowGui() {
// The playing-field with a 4x6 grid.
PlayingField field = new PlayingField(4, 6);
JPanel mainPanel = new ComputerView(field);
setTitle("Puzzle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 600);
add(mainPanel);
setVisible(true);
}
}
ComputerView.java
package programming.schimmler.view;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
import programming.schimmler.model.PlayingField;
public class ComputerView extends JPanel {
...
Instance variables
....
public ComputerView(PlayingField field) {
this.field = field;
this.setLayout(null);
JPanel topLeft = new GamingPiece(PlayingField.TOP_LEFT);
add(topLeft);
JPanel topRight = new GamingPiece(PlayingField.TOP_RIGHT);
add(topRight);
JPanel bottomLeft = new GamingPiece(PlayingField.BOTTOM_LEFT);
add(bottomLeft);
}
}
GamingPiece.java
package programming.schimmler.view;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import programming.schimmler.model.PlayingField;
/**
*
*/
public class GamingPiece extends JPanel {
...
public GamingPiece(int type) {
switch (type) {
// Need to draw each polygon from different coordinates since rotating did not work yet.
case PlayingField.TOP_LEFT:
pieceX = new int[] { 100, 100, 300, 300, 200, 200, 100 };
pieceY = new int[] { 100, 100, 100, 200, 200, 300, 300 };
break;
case PlayingField.TOP_RIGHT:
pieceX = new int[] { 400, 400, 300, 300, 200, 200 };
pieceY = new int[] { 0, 200, 200, 100, 100, 0 };
break;
case PlayingField.BOTTOM_LEFT:
pieceX = new int[] { 0, 200, 200, 100, 100, 0 };
pieceY = new int[] { 400, 400, 300, 300, 200, 200 };
break;
case PlayingField.BOTTOM_RIGHT:
pieceX = new int[] { 400, 400, 300, 300, 200, 200 };
pieceY = new int[] { 400, 200, 200, 300, 300, 400 };
break;
case PlayingField.SQUARE:
pieceX = new int[] { 100, 300, 300, 100 };
pieceY = new int[] { 100, 100, 300, 300 };
break;
}
setLayout(null);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.YELLOW);
g2.fillPolygon(pieceX, pieceY, pieceX.length);
}
}
上面这些 classes 是 only classes 与我的 GUI 交互,没有其他 classes 参与。
你试图将 JPanel
个拼图块添加到你的 JPanel
拼图板上,这让事情变得过于复杂。对于非矩形拼图,问题会很快变得明显,例如 TOP_LEFT
形状,它的右下侧有一个切口。当需要重叠拼图块时,将切掉的部分拼在一起,后面添加的部分将遮挡前面绘制的部分。
例如,如果您尝试将 TOP_LEFT 件 (A) 和 BOTTOM_RIGHT 件 (B) 嵌套在一起。
AAAAAA BBB
AAAAAA BBB
AAA BBBBBB
AAA BBBBBB
您只会看到:
+---+------+
|AAA| BBB|
|AAA| BBB|
|AAA|BBBBBB|
|AAA|BBBBBB|
+---+------+
重叠区域将仅由一个面板绘制。 B 块的整个区域,包括空白 space,将绘制在第二块区域中,位于 A 块希望显示的任何区域之上。
您可以通过将 JPanel
设置为透明而不调用 super.paintComponent()
来解决此问题,后者将整个组件绘制为背景色。但是你仍然需要在 JPanel
上绘制形状,并将 JPanel
正确定位在父级 JPanel
.
上
忘记面板中的面板吧!只需 在父 JPanel
.
上绘制 碎片
示例:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Puzzle {
public static void main(String[] args) {
SwingUtilities.invokeLater(Puzzle::new);
}
private final static int shape_x[] = { -100, 100, 100, 0, 0, -100 };
private final static int shape_y[] = { -100, -100, 0, 0, 100, 100 };
public Puzzle() {
JFrame frame = new JFrame("Puzzle");
frame.setSize(600, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
View view = new View();
frame.setContentPane(view);
Shape l_shape = new Polygon(shape_x, shape_y, shape_x.length);
view.pieces.add(new Piece(Color.YELLOW, l_shape, 0, 100, 100));
view.pieces.add(new Piece(Color.GREEN, l_shape, 180, 300, 300));
view.pieces.add(new Piece(Color.RED, l_shape, 65, 450, 145));
frame.setVisible(true);
}
}
@SuppressWarnings("serial")
class View extends JPanel {
final List<Piece> pieces = new ArrayList<>();
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gc = (Graphics2D) g;
for (Piece piece : pieces)
piece.draw(gc);
}
}
class Piece {
final Color color;
final Shape shape;
final int angle;
int x, y; // Move pieces by by changing these
Piece(Color color, Shape shape, int angle, int x, int y) {
this.color = color;
this.shape = shape;
this.angle = angle;
this.x = x;
this.y = y;
}
void draw(Graphics2D gc) {
AffineTransform tf = gc.getTransform();
gc.translate(x, y);
gc.rotate(Math.toRadians(angle));
gc.setColor(color);
gc.fill(shape);
gc.setTransform(tf);
}
}
请注意,这也是一个最小的、完整的和可验证的示例。最小:没有 package
语句;没有未使用的额外 HashSet
和 Set
导入;除了显示 3 个游戏片段外,不会尝试做任何事情。它是完整的:您可以编译单个文件,并且 运行。它是可验证的:您可以 运行 它并看到它显示 3 个游戏棋子。
作为奖励,它显示 Graphics2D.rotate()
工作正常,其中一块旋转 180°,另一块旋转的角度不适合您的拼图,但有助于证明旋转工作正常。
情况
我目前正在尝试使用 Java 的 Swing 构建 2D 游戏。为此,我有我的 main class Puzzle
,它是 subclassing JFrame
。在我的框架中,我添加了我的主要 JPanel
,它由几个 JPanel
加在一起组成(每个都是一个新片段)。
编辑 2: PlayingField
是我的模型,它将存储每件作品的当前位置。
可以用鼠标 select 一块(计划是突出显示它)并用箭头键移动它,只要下一步(一个完整的单元格,所以大约 100 像素)不是其他作品之一。截至目前,PlayingField
不存储任何数据,因为碎片丢失。
private void createAndShowGui() {
// The playing-field with a 4x6 grid.
PlayingField field = new PlayingField(4, 6);
JPanel mainPanel = new ComputerView(field);
setTitle("Puzzle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 600);
add(mainPanel);
setVisible(true);
}
上述方法将创建我的框架并添加主面板。以下方法是我的主面板,它向自身添加了几个 JPanel
。
public ComputerView(PlayingField field) {
this.field = field;
this.setLayout(null);
JPanel topLeft = new GamingPiece(PlayingField.TOP_LEFT);
add(topLeft);
JPanel topRight = new GamingPiece(PlayingField.TOP_RIGHT);
add(topRight);
JPanel bottomLeft = new GamingPiece(PlayingField.BOTTOM_LEFT);
add(bottomLeft);
}
每个 GamingPiece
或者我的子 JPanel
都在画一个基本的部分(我只画一个并旋转其他部分,因为它们都由相同的任意形状组成)。 GamingPiece
class 也从 class 继承 JPanel
并调用 JPanel#paintComponent()
方法来绘制棋子。
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.YELLOW);
g2.fillPolygon(pieceX, pieceY, pieceX.length);
}
问题和我的问题
由于我是 Java 的新手,所以我真的不知道如何正确操作。如果我通过创建一个新对象并将其添加到主面板来添加我的片段,它不会显示所有片段,只会显示最后添加的片段。有些甚至似乎不起作用,即使它们是唯一添加的(为了解释我的情况:我有相同任意形状的碎片只是旋转不同但使用 Graphics2D#rotate()
似乎不起作用很好)。
我希望我已经很好地解释了我的情况和我的问题,以便你们能帮助我。提前致谢!
编辑:
我的代码
Puzzle.java
package programming.schimmler;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import programming.schimmler.model.PlayingField;
import programming.schimmler.view.ComputerView;
public class Puzzle extends JFrame {
...
Invoking the createAndShowGui()
...
private void createAndShowGui() {
// The playing-field with a 4x6 grid.
PlayingField field = new PlayingField(4, 6);
JPanel mainPanel = new ComputerView(field);
setTitle("Puzzle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 600);
add(mainPanel);
setVisible(true);
}
}
ComputerView.java
package programming.schimmler.view;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
import programming.schimmler.model.PlayingField;
public class ComputerView extends JPanel {
...
Instance variables
....
public ComputerView(PlayingField field) {
this.field = field;
this.setLayout(null);
JPanel topLeft = new GamingPiece(PlayingField.TOP_LEFT);
add(topLeft);
JPanel topRight = new GamingPiece(PlayingField.TOP_RIGHT);
add(topRight);
JPanel bottomLeft = new GamingPiece(PlayingField.BOTTOM_LEFT);
add(bottomLeft);
}
}
GamingPiece.java
package programming.schimmler.view;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import programming.schimmler.model.PlayingField;
/**
*
*/
public class GamingPiece extends JPanel {
...
public GamingPiece(int type) {
switch (type) {
// Need to draw each polygon from different coordinates since rotating did not work yet.
case PlayingField.TOP_LEFT:
pieceX = new int[] { 100, 100, 300, 300, 200, 200, 100 };
pieceY = new int[] { 100, 100, 100, 200, 200, 300, 300 };
break;
case PlayingField.TOP_RIGHT:
pieceX = new int[] { 400, 400, 300, 300, 200, 200 };
pieceY = new int[] { 0, 200, 200, 100, 100, 0 };
break;
case PlayingField.BOTTOM_LEFT:
pieceX = new int[] { 0, 200, 200, 100, 100, 0 };
pieceY = new int[] { 400, 400, 300, 300, 200, 200 };
break;
case PlayingField.BOTTOM_RIGHT:
pieceX = new int[] { 400, 400, 300, 300, 200, 200 };
pieceY = new int[] { 400, 200, 200, 300, 300, 400 };
break;
case PlayingField.SQUARE:
pieceX = new int[] { 100, 300, 300, 100 };
pieceY = new int[] { 100, 100, 300, 300 };
break;
}
setLayout(null);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.YELLOW);
g2.fillPolygon(pieceX, pieceY, pieceX.length);
}
}
上面这些 classes 是 only classes 与我的 GUI 交互,没有其他 classes 参与。
你试图将 JPanel
个拼图块添加到你的 JPanel
拼图板上,这让事情变得过于复杂。对于非矩形拼图,问题会很快变得明显,例如 TOP_LEFT
形状,它的右下侧有一个切口。当需要重叠拼图块时,将切掉的部分拼在一起,后面添加的部分将遮挡前面绘制的部分。
例如,如果您尝试将 TOP_LEFT 件 (A) 和 BOTTOM_RIGHT 件 (B) 嵌套在一起。
AAAAAA BBB
AAAAAA BBB
AAA BBBBBB
AAA BBBBBB
您只会看到:
+---+------+
|AAA| BBB|
|AAA| BBB|
|AAA|BBBBBB|
|AAA|BBBBBB|
+---+------+
重叠区域将仅由一个面板绘制。 B 块的整个区域,包括空白 space,将绘制在第二块区域中,位于 A 块希望显示的任何区域之上。
您可以通过将 JPanel
设置为透明而不调用 super.paintComponent()
来解决此问题,后者将整个组件绘制为背景色。但是你仍然需要在 JPanel
上绘制形状,并将 JPanel
正确定位在父级 JPanel
.
忘记面板中的面板吧!只需 在父 JPanel
.
示例:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Puzzle {
public static void main(String[] args) {
SwingUtilities.invokeLater(Puzzle::new);
}
private final static int shape_x[] = { -100, 100, 100, 0, 0, -100 };
private final static int shape_y[] = { -100, -100, 0, 0, 100, 100 };
public Puzzle() {
JFrame frame = new JFrame("Puzzle");
frame.setSize(600, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
View view = new View();
frame.setContentPane(view);
Shape l_shape = new Polygon(shape_x, shape_y, shape_x.length);
view.pieces.add(new Piece(Color.YELLOW, l_shape, 0, 100, 100));
view.pieces.add(new Piece(Color.GREEN, l_shape, 180, 300, 300));
view.pieces.add(new Piece(Color.RED, l_shape, 65, 450, 145));
frame.setVisible(true);
}
}
@SuppressWarnings("serial")
class View extends JPanel {
final List<Piece> pieces = new ArrayList<>();
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gc = (Graphics2D) g;
for (Piece piece : pieces)
piece.draw(gc);
}
}
class Piece {
final Color color;
final Shape shape;
final int angle;
int x, y; // Move pieces by by changing these
Piece(Color color, Shape shape, int angle, int x, int y) {
this.color = color;
this.shape = shape;
this.angle = angle;
this.x = x;
this.y = y;
}
void draw(Graphics2D gc) {
AffineTransform tf = gc.getTransform();
gc.translate(x, y);
gc.rotate(Math.toRadians(angle));
gc.setColor(color);
gc.fill(shape);
gc.setTransform(tf);
}
}
请注意,这也是一个最小的、完整的和可验证的示例。最小:没有 package
语句;没有未使用的额外 HashSet
和 Set
导入;除了显示 3 个游戏片段外,不会尝试做任何事情。它是完整的:您可以编译单个文件,并且 运行。它是可验证的:您可以 运行 它并看到它显示 3 个游戏棋子。
作为奖励,它显示 Graphics2D.rotate()
工作正常,其中一块旋转 180°,另一块旋转的角度不适合您的拼图,但有助于证明旋转工作正常。