简体   繁体   English

Java Swing 将 JPanel 添加到 JPanel

[英]Java Swing Add JPanel to JPanel

The Situation情况

I am currently trying to build a 2D game with Java's Swing.我目前正在尝试使用 Java 的 Swing 构建 2D 游戏。 For this, I have my main class Puzzle which is subclassing JFrame .为此,我有我的主类Puzzle ,它是JFrame子类。 To my frame I add my main JPanel which consists of several JPanel s added together (each of them being a new piece).我的帧添加我主要JPanel它由几个JPanel叠加在一起(它们中的每一个被新件)。

EDIT 2: PlayingField is my model which will store the current location of each piece.编辑 2: PlayingField是我的模型,它将存储每件作品的当前位置。 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.可以用鼠标选择一块(计划是突出显示它)并用箭头键移动它,只要下一步(一个完整的单元格,所以大约 100 像素)不是另一个的位置件。 As of right now, PlayingField does not store any data since the pieces are missing.截至目前, 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);
}

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.以下方法是我的主面板,它向自身添加了几个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);
}

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).每个GamingPiece或者更确切地说我的子JPanel正在绘制一个基本块(我只绘制一个并旋转其他的,因为它们都由相同的任意形状组成)。 The GamingPiece class also subclasses JPanel and invokes the JPanel#paintComponent() method to draw the piece. GamingPiece类还GamingPiece 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);
}

The Problem And My Questions问题和我的问题

Since I am pretty new to Java I really do not know how to do it properly.由于我对 Java 还很陌生,我真的不知道如何正确地做到这一点。 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).有些甚至似乎不起作用,即使它们是唯一添加的(解释我的情况:我有相同的任意形状的碎片只是旋转不同,但使用Graphics2D#rotate()似乎不起作用美好的)。

I hope I explained my situation and my problem well enough fo you guys to help me.我希望我能很好地解释我的情况和我的问题,以便你们帮助我。 Thanks in advance!提前致谢!

EDIT:编辑:

My Codes我的代码

Puzzle.java拼图.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计算机视图.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 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);
    }
}

These classes above are the only classes interacting with my GUI, no other classes take part.上面的这些类是唯一与我的 GUI 交互的类,没有其他类参与。

You are overcomplicating things by trying to add JPanel puzzle pieces to your JPanel puzzle board.通过尝试将JPanel拼图添加到您的JPanel拼图板,您使事情变得过于复杂。 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.对于非矩形拼图,问题会很快变得明显,例如TOP_LEFT形状,它从拼图的右下方切开。 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.当需要重叠拼图块时,将切掉的部分组合在一起,稍后添加的块将遮挡之前绘制的块。

For instance, if you try to nest a TOP_LEFT piece (A) and a BOTTOM_RIGHT piece (B) together.例如,如果您尝试将 TOP_LEFT 部分 (A) 和 BOTTOM_RIGHT 部分 (B) 嵌套在一起。

 AAAAAA BBB   
 AAAAAA BBB
 AAA BBBBBB
 AAA BBBBBB

You will only see:你只会看到:

+---+------+
|AAA|   BBB|
|AAA|   BBB|
|AAA|BBBBBB|
|AAA|BBBBBB|
+---+------+

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. B 块的整个区域,包括空白区域,将被绘制在第二块的区域中,在 A 块希望显示的任何内容之上。

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.您可以通过将JPanel设置为透明来解决此问题,而不是调用super.paintComponent()将整个组件绘制为背景颜色。 But then you still have to draw the shape on the JPanel , and position the JPanel properly on the parent JPanel .但是您仍然需要在JPanel上绘制形状,并将JPanel正确放置在父JPanel

Forget panels within panels!忘记面板中的面板! Just draw the pieces on the parent JPanel .只需在父JPanel绘制碎片即可。

Example:例子:

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);
    }
}

Note that this is also a Minimal, Complete and Verifiable example.请注意,这也是一个最小、完整和可验证的示例。 Minimal: No package statement;最小:无package声明; No extra HashSet and Set imports which aren't used;没有未使用的额外HashSetSet导入; doesn't try to do anything except show 3 game pieces.除了展示 3 个游戏片段外,不会尝试做任何事情。 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.它是可验证的:您可以运行它并看到它显示 3 个游戏块。

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.作为奖励,它显示Graphics2D.rotate()工作,其中一块旋转了 180°,另一块旋转的角度不适合您的拼图,但有助于证明旋转工作正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM