Java Swing将JPanel添加到JPanel [英] Java Swing Add JPanel to JPanel
问题描述
我目前正在尝试使用Java的Swing构建2D游戏.为此,我有主类Puzzle
,它是子类JFrame
的子类.在我的框架中添加主要的JPanel
,它由几个添加在一起的JPanel
组成(每个都是新的).
I am currently trying to build a 2D game with Java's Swing. For this, I have my main class Puzzle
which is subclassing JFrame
. To my frame I add my main JPanel
which consists of several JPanel
s added together (each of them being a new piece).
PlayingField
是我的模型,它将存储每块的当前位置.
只要下一步(一个完整的单元格,大约100个像素)不是另一个的位置,就可以用鼠标选择一块(计划将其突出显示)并用方向键移动它.件.截至目前,由于缺少片段,PlayingField
不会存储任何数据.
EDIT 2: PlayingField
is my model which will store the current location of each piece.
One can select a piece with the mouse (the plan is to highlight it) and move it with the arrow keys as long as the next step (a full cell, so approx. 100 pixel) isn't the location of one of the other pieces. As of right now, PlayingField
does not store any data since the pieces are missing.
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
.
The method above will create my frame and adds the main panel. The following method is my main panel which adds several JPanel
s to itself.
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
或更确切地说是我的sub- JPanel
都在绘制一个基本零件(我只绘制一个零件,然后旋转其他零件,因为所有零件都由相同的任意形状组成). GamingPiece
类也是JPanel
的子类,并调用JPanel#paintComponent()
方法绘制图块.
Each GamingPiece
or rather my sub-JPanel
s are drawing a basic piece (I only drawing one and rotating the others, since all consists of the same arbitrary shape). The GamingPiece
class also subclasses JPanel
and invokes the JPanel#paintComponent()
method to draw the piece.
@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()
似乎效果不佳)
The Problem And My Questions
Since I am pretty new to Java I really do not know how to do it properly. If I add my pieces by creating a new object and adding it to the main panel, it won't show all of them, only the last one added. Some don't even seem to work, even if they're the only ones added (to explain my situation: I have for pieces which are the same arbitrary shape just rotated differently but using Graphics2D#rotate()
doesn't seem to work fine).
我希望我向大家解释了我的情况和问题,足以帮助我.预先感谢!
I hope I explained my situation and my problem well enough fo you guys to help me. Thanks in advance!
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);
}
}
以上这些类是与我的GUI交互的 only 类,没有其他类参与.
These classes above are the only classes interacting with my GUI, no other classes take part.
推荐答案
您正在尝试通过将JPanel
拼图块添加到您的JPanel
拼图板上来使事情变得过于复杂.对于非矩形拼图,问题会迅速变得明显,例如TOP_LEFT
形状,该形状从拼图的右下侧切出.当需要重叠拼图块以将切掉的部分放在一起时,稍后添加的拼图将遮盖较早绘制的拼图.
You are overcomplicating things by trying to add JPanel
puzzle pieces to your JPanel
puzzle board. Problems will rapidly become apparent with your non-rectangular puzzle pieces, like the TOP_LEFT
shape, which has a cut-out from the lower right side of the piece. When it comes time to overlap the puzzle pieces, to fit the cut-away portions together, the piece added later will occlude pieces drawn earlier.
例如,如果您尝试将TOP_LEFT件(A)和BOTTOM_RIGHT件(B)嵌套在一起.
For instance, if you try to nest a TOP_LEFT piece (A) and a BOTTOM_RIGHT piece (B) together.
AAAAAA BBB
AAAAAA BBB
AAA BBBBBB
AAA BBBBBB
您只会看到:
+---+------+
|AAA| BBB|
|AAA| BBB|
|AAA|BBBBBB|
|AAA|BBBBBB|
+---+------+
重叠区域将仅由一个面板绘制. B片的整个区域(包括空白)将被绘制在第二个片的区域中,位于A片希望显示的任何内容的上方.
The overlapping area will be drawn by only one of the panels. The entire area of the B piece, including the blank space, will be drawn in the area of the second piece, on top of whatever the A piece hoped to display.
通过将JPanel
设置为透明,而不调用super.paintComponent()
可以将整个组件涂成背景色,您也许可以解决此问题.但是随后您仍然必须在JPanel
上绘制形状,并将JPanel
正确地放置在父级JPanel
上.
You might be able to get around this by setting the JPanel
to be transparent, and not calling super.paintComponent()
which paints the entire component the background colour. But then you still have to draw the shape on the JPanel
, and position the JPanel
properly on the parent JPanel
.
忘记面板内的面板!只需绘制在父级JPanel
上的作品.
Forget panels within panels! Just draw the pieces on the parent 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个游戏片段.
Note that this is also a Minimal, Complete and Verifiable example. Minimal: No package
statement; No extra HashSet
and Set
imports which aren't used; doesn't try to do anything except show 3 game pieces. It is complete: a single file you can compile, and run. It is verifiable: you can run it and see it shows 3 game pieces.
作为奖励,它显示了Graphics2D.rotate()
的工作原理,其中一件旋转了180°,另一件旋转了一个不适合您的难题的角度,但对证明旋转的效果非常有用.
As a bonus, it shows Graphics2D.rotate()
working, with one piece rotated 180°, and another rotated at an angle that is not appropriate for your puzzle but useful in demonstrating the that rotate works just fine.
这篇关于Java Swing将JPanel添加到JPanel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!