Can you add JButtons inside a JPanel

拟墨画扇 提交于 2021-02-11 06:16:06

问题


I'm making a Battleship game using one board. The picture below shows how the board GUI should look. My current code sets up a board without the 'menu-layer'. (see picture) I tried doing this using Swing GUI designer in Intellij and got the following form (see picture), but can't find a way to insert these buttons inside the panel. Currently, I have got the following code.

package BattleshipGUI;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;



public class BoardFrame extends JFrame {

//variables

Ships ship = new Ships();
static final Color colorHit = Color.red;
static final Color colorNormal = Color.gray;
static final Color colorWater = Color.blue;
static final Color colorCarrier = Color.yellow;
static final Color colorBattleship = Color.BLACK;
static final Color colorSubmarine = Color.magenta;
static final Color colorDestroyer = Color.white;
int[][] map;
private Container contents;
int cols;
int rows;
boolean equalPoints;

Player p1 = new Player();
Player p2 = new Player();
private JPanel mainPanel; // I tried using the GUI swing designer, but I cant manage to create 
                                //a menu-layer on top of the buttons
private JButton buttonHighScores;
private JButton quitGame;
private JLabel player1Points;
private JLabel player2Points;
private JLabel playerTurn;
JButton[][] tiles = new JButton[100][100]; // I create 100*100 buttons, but only assign the right   
                                            // number to them


public void setMap(int[][] map) {
    this.map = map;
}
public void SetFrame(int r, int c) {
    this.rows = r;
    this.cols = c;

}




public BoardFrame(int r, int c) {

    super("Battleship");
    setSize(400,450); // I create a frame
    this.setLayout(new GridLayout(r, c)); // I set the layout depending on the number of rows and 
                                         //columns
    AttackHandler attackHandler = new AttackHandler(); // action event class
    p1.turn = true; // player 1's turn is true, he commences
    p2.turn= false; //player 2's turn is false




    for (int i =0; i<r; i++) {
        for (int j =0; j <c; j++) {
            tiles[i][j] = new JButton();       // this is where all the buttons are declared
            tiles[i][j].setBackground(colorNormal);
            add(tiles[i][j]);
            tiles[i][j].addActionListener(attackHandler);
        }
    }


    setResizable(true);
    setLocationRelativeTo(null);
    setVisible(true);
    setDefaultCloseOperation(this.DISPOSE_ON_CLOSE);
    setSize(400,450);               //the size of my frame


}





public class AttackHandler implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (source == tiles[i][j]) {
                    isHit(i, j);
                    return;
                }
            }
        }
    }
}
public void isHit(int row, int col) { 
       // the map consists of an 2D array 
      //where 0's represent the water, 1's represent the tiles that are 
      //already hit, and the other represent the ships

    if (AllHit()) {
        JOptionPane.showMessageDialog(null, "All Ships Destructed!");
        setWinner();
        String winner =DecideWinner();
        JOptionPane.showMessageDialog(null, winner+" has won!", "Winner", 
 JOptionPane.PLAIN_MESSAGE);
        int again = JOptionPane.showConfirmDialog(null, "Play Again", "Play 
 Again",JOptionPane.YES_NO_OPTION);
        if (again==0){
            Main.main(null);
        }
        dispose();
    }
    else if (map[row][col] == 5) {
        AddPoint(p1.turn, 5); // this should add points to the player that 
                              //has the turn
        tiles[row][col].setBackground(colorCarrier);
        map[row][col] = 1;
    } else if (map[row][col] == 4) {
        AddPoint(p1.turn, 4);
        tiles[row][col].setBackground(colorBattleship);
        map[row][col] = 1;

    } else if (map[row][col] == 3) {
        AddPoint(p1.turn, 3);
        tiles[row][col].setBackground(colorSubmarine);
        map[row][col] = 1;
    } else if (map[row][col] == 2) {
        AddPoint(p1.turn, 2);
        tiles[row][col].setBackground(colorDestroyer);
        map[row][col] = 1;
    } else if (map[row][col] == 1) {
        System.out.println("Already Hit!");
    } else if (map[row][col] == 0 || map[row][col] == 9) {
        tiles[row][col].setBackground(colorWater);
        map[row][col] = 1;
    }
    p1.changeTurn(p1.turn); // every click, the turn of each player should 
                           //switch from true to false, p1 starts with value 
                           //true, and p2 with false
    p2.changeTurn(p2.turn);
    System.out.println("Points Player 1: "+p1.points);
    System.out.println("Points Player 2: "+p2.points);
}


public boolean AllHit() { // if all ships are hit, a message pops up
    boolean allHit = true;
    for (int i = 0; i<rows;i++) {
        for (int j = 0; j < cols; j++) {
            if (map[i][j] != 1 && map[i][j] != 0) {
                allHit = false;
                break;
            }
        }
    }
    return allHit;
}

public void AddRandomShips(int rows, int cols) {      
    int[][] map = ship.setRandomShips(rows, cols);
    setMap(map);
}
public void AddShipsNotRandom(int size, int[][] coordinates){   
    int[][] map = ship.PlaceShips(size, coordinates);
    setMap(map);
}

public void ScoreMethod(boolean scoreMethod){ 
    if(scoreMethod){
        equalPoints = true;
    }
    else if(!scoreMethod){    // the second method adjusts the score 
                             //for the second player because the first player 
                              //is more likely to hit a ship
        equalPoints = false;
    }
}

public void AddPoint(boolean turn,int amount){
    if (turn){
        p1.points = p1.points+ amount;
    }
    else p2.points = p2.points+amount;
}

public void setWinner(){
    if(p1.points>p2.points){
        p1.setWon();
    }
    else p2.setWon();
}

public String DecideWinner(){
    if (p1.won == true){
        return "Player 1";
    }
    else return "Player 2";
}

}

This is how the GUI should look like:

This is what my code generates:

this is the for that I designed using Intellij's Swing Designer (the panel with 'buttons' should be filled with the JButtons I created in the code):

UPDATE :

Thanks to mr. Kroukamp, I was able to add a menu-overlay. The code looks like this:

package BattleshipGUI;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import java.awt.Dimension;


public class BoardFrame extends JFrame {

//variables
Ships ship = new Ships();
static final Color colorNormal = Color.gray;
static final Color colorWater = Color.blue;
static final Color colorCarrier = Color.yellow;
static final Color colorBattleship = Color.BLACK;
static final Color colorSubmarine = Color.magenta;
static final Color colorDestroyer = Color.white;
int[][] map;
int cols;
int rows;
boolean equalPoints;
Player p1 = new Player();
Player p2 = new Player();
JButton[][] tiles = new JButton[100][100];

public void setMap(int[][] map) {
    this.map = map;
}
public void SetFrame(int r, int c) {
    this.rows = r;
    this.cols = c;

}

JButton highScoresButton = new JButton("High Scores");
JLabel player1ScoreTitleLabel = new JLabel(String.valueOf(p1.points));
JLabel turnTitleLabel = new JLabel(Turn());
JLabel player2ScoreTitleLabel = new JLabel(String.valueOf(p1.points));
JButton quitGameButton = new JButton("Quite Game");
JFrame frame = new JFrame("Battleship");




public  BoardFrame(int r, int c) {

    super("Battleship");
    AttackHandler attackHandler = new AttackHandler(); // action event class

    p1.turn = true; // player 1's turn is true, he commences
    p2.turn= false; //player 2's turn is false


    JFrame frame = new JFrame("Battleship");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    // panel 1 (yellow border)
    JPanel panel1 = new JPanel(new GridBagLayout());
    JButton highScoresButton = new JButton("High Scores");
    JLabel player1ScoreTitleLabel = new JLabel(String.valueOf(p1.points));
    JLabel turnTitleLabel = new JLabel(Turn());
    JLabel player2ScoreTitleLabel = new JLabel(String.valueOf(p1.points));
    JButton quitGameButton = new JButton("Quite Game");
    GridBagConstraints s = new GridBagConstraints();
    s.weightx = 1;
    s.gridx = 0;
    s.gridy = 0;
    panel1.add(highScoresButton, s);
    s.weightx = 1;
    s.gridx = 1;
    s.gridy = 0;
    panel1.add(player1ScoreTitleLabel, s);
    s.weightx = 1;
    s.gridx = 2;
    s.gridy = 0;
    panel1.add(turnTitleLabel);
    s.weightx = 1;
    s.gridx = 3;
    s.gridy = 0;
    panel1.add(player2ScoreTitleLabel, s);
    s.weightx = 1;
    s.gridx = 4;
    s.gridy = 0;
    panel1.add(quitGameButton, s);

    // panel 2 (red border)
    JPanel panel2 = new JPanel();
    GridLayout layout = new GridLayout(r, c);
    layout.setHgap(0);
    layout.setVgap(0);
    panel2.setLayout(layout);
    panel2.setBorder(new LineBorder(Color.blue, 4));
    for (int i =0; i<r; i++) {
        for (int j =0; j < c; j++) {
            tiles[i][j] = new JButton(){
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(100,100);
                    }
                };
            tiles[i][j].setBackground(colorNormal);
            panel2.add(tiles[i][j]);
            tiles[i][j].addActionListener(attackHandler);
            }
        }

    frame.add(panel1, BorderLayout.NORTH);
    frame.add(panel2, BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);

}

public class AttackHandler implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (source == tiles[i][j]) {
                    isHit(i, j);
                    return;
                }
            }
        }
    }
}


public void isHit(int row, int col) { 

    if (AllHit()) {
        JOptionPane.showMessageDialog(null, "All Ships Destructed!");
        setWinner();
        String winner =DecideWinner();
        if(p1.won){
            p1.checkHighScore();
        }
        else if (p2.won){
            p2.checkHighScore();
        }

        JOptionPane.showMessageDialog(null, winner, "Winner", 
JOptionPane.PLAIN_MESSAGE);
        int again = JOptionPane.showConfirmDialog(null, "Play Again", "Play 
Again",JOptionPane.YES_NO_OPTION);
        if (again==0){
            Main.main(null);
        }
        frame.dispose();
    }
    else if (map[row][col] == 5) {
        AddPoint(p1.turn, 5); 
        tiles[row][col].setBackground(colorCarrier);
        map[row][col] = 1;
    } else if (map[row][col] == 4) {
        AddPoint(p1.turn, 4);
        tiles[row][col].setBackground(colorBattleship);
        map[row][col] = 1;

    } else if (map[row][col] == 3) {
        AddPoint(p1.turn, 3);
        tiles[row][col].setBackground(colorSubmarine);
        map[row][col] = 1;
    } else if (map[row][col] == 2) {
        AddPoint(p1.turn, 2);
        tiles[row][col].setBackground(colorDestroyer);
        map[row][col] = 1;
    } else if (map[row][col] == 1) {
        System.out.println("Already Hit!");
    } else if (map[row][col] == 0 || map[row][col] == 9) {
        tiles[row][col].setBackground(colorWater);
        map[row][col] = 1;
    }
    p1.changeTurn(p1.turn); 
    p2.changeTurn(p2.turn);
    
    // I cannot find a way to change the labels....
    player1ScoreTitleLabel.setText(String.valueOf(p1.points)); 
    player2ScoreTitleLabel.setText(String.valueOf(p2.points)); 
    turnTitleLabel.setText(Turn());
    System.out.println("Points Player 1: "+p1.points);
    System.out.println("Points Player 2: "+p2.points);
}


public boolean AllHit() {
    boolean allHit = true;
    for (int i = 0; i<rows;i++) {
        for (int j = 0; j < cols; j++) {
            if (map[i][j] != 1 && map[i][j] != 0) {
                allHit = false;
                break;
            }
        }
    }
    return allHit;
}

public void AddRandomShips(int rows, int cols) {        
    int[][] map = ship.setRandomShips(rows, cols);
    setMap(map);
}
public void AddShipsNotRandom(int size, int[][] coordinates){   
    int[][] map = ship.PlaceShips(size, coordinates);
    setMap(map);
}

public void ScoreMethod(boolean scoreMethod){   
    if(scoreMethod){
        equalPoints = true;
    }
    else {          
        equalPoints = false;
    }
}

public void AddPoint(boolean turn,int amount){
    if (turn){
        p1.points = p1.points+ amount;
    }
    else p2.points = p2.points+amount;
}

public void setWinner(){
    if(p1.points>p2.points){
        p1.setWon();
    }
    else if (p2.points>p1.points){
        p2.setWon();
    }
}

public String DecideWinner(){
    if (p1.won){
        return "Player 1 won the game!";
    }
    else if (p2.won){
        return "Player 2 won the game!";
    }
    else return "It's a tie!";
}

public String Turn(){
    if (p1.turn){
        return "Player 1";
    }else return "Player 2";
 }

This generates the following GUI:

However, I am still struggling finding a way to change the values of the text of the score JLabels, the following code did not work for me:

    player1ScoreTitleLabel.setText(String.valueOf(p1.points));
    player2ScoreTitleLabel.setText(String.valueOf(p2.points));
    turnTitleLabel.setText(Turn())

回答1:


Adding to my comment here is a small example to help get you started without the burden of an IDE for building your UI incorporating as much of Swing best practices as possible:

  • I opted to use JLabels as it just makes more sense
  • The yellow border represents panel1 which makes use of a GridBagLayout.
  • The red panel represents panel2 which makes use of a GridLayout.
  • Finally the 2 JPanels are added to a JFrame which by default uses BorderLayout.

TestApp.java:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

public class TestApp {

    public TestApp() {
        createAndShowGui();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(TestApp::new);
    }

    private void createAndShowGui() {
        JFrame frame = new JFrame("TestApp");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // panel 1 (yellow border)
        JPanel panel1 = new JPanel(new GridBagLayout());
        JButton highScoresButton = new JButton("High Scores");
        JLabel player1ScoreLabel = new JLabel("<html>Player 1 Score:<br><h2>950</h2>");
        JLabel turnLabel = new JLabel("<html>Turn:<br><h1>Player 1</h1>");
        JLabel player2ScoreLabel = new JLabel("<html>Player 2 Score:<br><h2>925</h2>");
        JButton quitGameButton = new JButton("Quit Game");
        GridBagConstraints c = new GridBagConstraints();
        c.weightx = 1;
        c.gridx = 0;
        c.gridy = 0;
        panel1.add(highScoresButton, c);
        c.weightx = 1;
        c.gridx = 1;
        c.gridy = 0;
        panel1.add(player1ScoreLabel, c);
        c.weightx = 1;
        c.gridx = 2;
        c.gridy = 0;
        panel1.add(turnLabel);
        c.weightx = 1;
        c.gridx = 3;
        c.gridy = 0;
        panel1.add(player2ScoreLabel, c);
        c.weightx = 1;
        c.gridx = 4;
        c.gridy = 0;
        panel1.add(quitGameButton, c);
        panel1.setBorder(new LineBorder(Color.YELLOW, 4)); // just for visual purposes of the answer

        // panel 2 (red border)
        JPanel panel2 = new JPanel();
        GridLayout layout = new GridLayout(8, 8);
        layout.setHgap(5);
        layout.setVgap(5);
        panel2.setLayout(layout);
        panel2.setBorder(new LineBorder(Color.RED, 4)); // just for visual purposes of the answer

        for (int i = 0; i < 64; i++) {
            JLabel label = new JLabel() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(100, 100);
                }
            };
            label.setOpaque(true);
            label.setBackground(Color.DARK_GRAY);
            panel2.add(label);
        }

        frame.add(panel1, BorderLayout.NORTH);
        frame.add(panel2, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}


来源:https://stackoverflow.com/questions/65380197/can-you-add-jbuttons-inside-a-jpanel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!