I am making a minesweeper program, and I need to implement a feature where the user can choose to resize the grid that the mines are on. I've finished this, but when I make a larger board the JFrame doesn't get any larger, with it.
This is the method that happens when the user wants to resize the board
public void mouseClicked(MouseEvent e) {
if(e.getSource() == quitButton && e.getButton() == 1){
System.exit(0);
}
// if I hit the reset size button this happens
if(e.getSource() == setDimension){
for (int r = 0; r < size; r++)
for (int c = 0; c < size; c++){
gameBoard.remove(board[r][c]); // removes the buttons from the board
}
inputSizeAndMines(); // lets the user choose the size and amount of mines
game = new MineSweeperGame(size, mines); // remakes the game
setBoard(); // adds new buttons based on what the user entered
displayBoard(); // makes visuals for the board
revalidate();
repaint();
}
This is the class that adds the panel to a JFrame
public class MineSweeper {
/**********************************
* Main class that does everything
**********************************/
public static void main(String[] args) {
JFrame frame = new JFrame("MineSweeper");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MineSweeperPanel panel = new MineSweeperPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
Any help would be appreciated
Call pack on the frame again once you have re-calculated the preferred size of the panel
Related
I am attempting to use Java Swing to create a Grid that allows me to access specific panels if I need to. The frame pulls up but there are no panels. I would like some advice on how to make the panels display in the frame while still allowing me to access the specific panel through the two dimensional array.
x=0;
y=0;
z=0;
JPanel[][] coordinate = new JPanel[5][5];
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.setSize(550,550);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(false);
panel.setBackground(Color.WHITE);
panel.setLayout(new GridLayout(5,5));
for(int i = 0; i<25; i++) {
if(z == 5) {
z = 0;
x = 0;
y++;
}
coordinate[x][y] = new JPanel();
coordinate[x][y].setBorder(BorderFactory.createLineBorder(Color.BLACK, 10));
panel.add(coordinate[x][y]);
z++;
x++;
}
frame.add(panel);
When using a GridLayout, it diveds its container's space evenly between its row and column elements. However when calcuating the cell width wouldn't turn out in an integer, the exceeding space is put between the container's edges and its content in a way, that the container's content is centered by the GridLayout.
In this picture you can see exceeding space (colored green):
Since the frame's size is dragged to 233x233 the LayoutManager would offer each component floor(233 / 20) = 11 pixels height and width. Thus 233 % 20 = 13 pixels exceed and are put at the edges.
That's the code to generate the frame in the picture:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GridLayout layout = new GridLayout(20, 0);
layout.setHgap(0);
layout.setVgap(0);
frame.setLayout(layout);
for (int j = 0; j < 20; j++) {
for (int i = 0; i < 20; i++) {
JPanel panel = new JPanel();
panel.setBackground((i + j) % 2 == 0 ? Color.BLACK : Color.WHITE);
frame.add(panel);
}
}
frame.pack();
frame.getContentPane().setBackground(Color.GREEN);
frame.setVisible(true);
So I wonder if there's an easy way to make the container 'clip' or align in a way, that this exceeding space doesn't show up, but instead the container is resized to fit its content perfectly.
That's right but I want to keep the advantage of a GridLayout offering every cell the same size,
Yes well you can't have it both ways.
If you want every cell to be the same size, then you will see the background. One option would be to make the panel non-opaque, so you don't see the background of the panel.
If you want to completely fill the area available with the components, then some components will need to be a different size by one pixel.
For implementing point 2, maybe this example will be easy enough for you to use:
import java.awt.*;
import javax.swing.*;
public class BoardTest
{
private static void createAndShowGUI()
{
Float constraint = new Float(1);
RelativeLayout boardLayout = new RelativeLayout(RelativeLayout.Y_AXIS);
boardLayout.setRoundingPolicy( RelativeLayout.EQUAL );
boardLayout.setFill(true);
JPanel board = new JPanel(boardLayout);
board.setBackground(Color.GREEN);
RelativeLayout rowLayout = new RelativeLayout(RelativeLayout.X_AXIS);
rowLayout.setRoundingPolicy( RelativeLayout.EQUAL );
rowLayout.setFill(true);
for (int j = 0; j < 20; j++)
{
JPanel row = new JPanel( rowLayout );
for (int i = 0; i < 20; i++)
{
JPanel square = new JPanel();
square.setBackground((i + j) % 2 == 0 ? Color.BLACK : Color.WHITE);
row.add(square, constraint);
}
board.add(row, constraint);
}
JFrame frame = new JFrame("BoardTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(board);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
It uses the Relative Layout class which allows you to control how the extra pixels are allocated to each of the components.
This question already has answers here:
Resizing issue with canvas within jscrollpane within jsplitpane
(3 answers)
Closed 8 years ago.
The program i want to make is
Divide an applet/frame(awt) into two parts using panel. The first panel contains four buttons naming ellipse, rectangle, circle and triangle. Taking one button and asking coordinates and make a figure on the other panel.
Please someone explain me the concept or working because im not good at layouts and know methods to use to convey from one panel to other..
Thank you very much
I would recommend starting out with a layout manager.. if you want 2 JPanels next to each other, you can use the GridLayout layout manager. It takes 2 arguments, and one of it's overloaded constructors takes 4 arguments.
setLayout(new GridLayout(rows, columns)); //one commonly used constructor
setLayout(new GridLayout(rows, columns, horizontalSpacePixels, verticleSpace));
GridLayout, when used will reshape to fit the largest component, and make each part of the grid an equal size-- however this isn't the case when you use a GridLayout inside of a GridLayout (the inner GridLayout might be too big to fit within the confines that the outer GridLayout puts on it.). If I simply do
JFrame jf = new JFrame("Laying the grid out");
jf.setLayout(new GridLayout(5, 5));
JPanel[] jp = new JPanel[25];
JLabel[] jl = new JLabel[25];
for(int i = 0; i < 25; i++) {
jp[i] = new JPanel();
jp[i].setBackground(Color.YELLOW);
jl[i] = new JLabel("This is label no. " + (i+1));
jp[i].add(jl[i]);
}
//now to add all 25 components in the 5x5 grid; you simply add them, and it
//automatically positions the jpanels in the order that you place them.. left to right.
for(int i = 0; i < 25; i++)
jf.add(jp[i]);
Here is an example program that involves a simple GridLayout, and an actionListener that responds to button events by changing one of the JPanel's color.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Gui {
private JPanel p2;
private JLabel side2;
private JFrame jf;
public static void main(String[] args){
new Gui();
}
public Gui(){
jf = new JFrame("Holds 2 panels side by side.");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLayout(new GridLayout(1, 2));
JPanel p1 = new JPanel();
p2 = new JPanel();
p1.setBackground(Color.BLACK);
p2.setBackground(Color.BLACK);
p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
JLabel[] space = new JLabel[20];
for(int i = 0; i < 20; i++)
space[i] = new JLabel(" ");
JButton jb1 = new JButton("Button 1");
JButton jb2 = new JButton("Button 2");
jb1.addActionListener(new BListen());
jb2.addActionListener(new BListen());
p1.add(space[0]);
p1.add(jb1);
p1.add(space[1]);
p1.add(jb2);
p1.add(space[2]);
jf.add(p1);
side2 = new JLabel("Change the color here with the buttons there.");
side2.setForeground(Color.GREEN);
p2.add(side2);
jf.add(p2);
jf.setSize(600, 200);
jf.setVisible(true);
}
private class BListen implements ActionListener {
public void actionPerformed(ActionEvent e) {
String buttonClicked = e.getActionCommand();
if(buttonClicked.equals("Button 1")) {
JOptionPane.showMessageDialog(null, "You pressed Button 1.");
p2.setBackground(Color.BLUE);
side2.setForeground(Color.MAGENTA);
jf.setVisible(true);
}
else if(buttonClicked.equals("Button 2")) {
JOptionPane.showMessageDialog(null, "You pressed Button 2.");
p2.setBackground(Color.ORANGE);
side2.setForeground(Color.DARK_GRAY);
jf.setVisible(true);
}
}
}
}
This question already has answers here:
Making a robust, resizable Swing Chess GUI [closed]
(2 answers)
Closed 8 years ago.
I have a simple Chess board in a JPanel with GridLayout(8,8) as layout manager.
I am trying to add panels for the fields' column name and row number.
Right now I've created another panel with BorderLayout as layout manager, and in this panel I add the board in BorderLayout.CENTER. Next to the board itself I've added a panels with GridLayout(0,8) in BorderLayout.SOUTH and a panel with GridLayout(8,0) in BorderLayout.WEST. The rows numbers is perfectly placed next to the board because the number of rows in the left JPanel matches the number of rows in the board, but the column names (A, B, C, D, E, F, G, H) in the JPanel under the board is not placed correctly because of the JPanel in BorderLayout.WEST.
What can I do to make a proper Chess board with side panels to show the field numbers/names?
I've tried setting the layout for the south panel to GridLayout(0,9) and have the first field empty, but the width of the left panel is not equal to each field in the board, so it's not a good workaround.
Note
The GUI seen here has been improved and moved to Making a robust, resizable Swing Chess GUI.
I will leave the animated GIF here (because it's cute) and the original, stripped down code (of just 125 code lines, the final code seen on the other thread is 218 LOC).
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.*;
public class ChessBoardWithColumnsAndRows {
private final JPanel gui = new JPanel(new BorderLayout(3, 3));
private JButton[][] chessBoardSquares = new JButton[8][8];
private JPanel chessBoard;
private final JLabel message = new JLabel(
"Chess Champ is ready to play!");
private static final String COLS = "ABCDEFGH";
ChessBoardWithColumnsAndRows() {
initializeGui();
}
public final void initializeGui() {
// set up the main GUI
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
JToolBar tools = new JToolBar();
tools.setFloatable(false);
gui.add(tools, BorderLayout.PAGE_START);
tools.add(new JButton("New")); // TODO - add functionality!
tools.add(new JButton("Save")); // TODO - add functionality!
tools.add(new JButton("Restore")); // TODO - add functionality!
tools.addSeparator();
tools.add(new JButton("Resign")); // TODO - add functionality!
tools.addSeparator();
tools.add(message);
gui.add(new JLabel("?"), BorderLayout.LINE_START);
chessBoard = new JPanel(new GridLayout(0, 9));
chessBoard.setBorder(new LineBorder(Color.BLACK));
gui.add(chessBoard);
// create the chess board squares
Insets buttonMargin = new Insets(0,0,0,0);
for (int ii = 0; ii < chessBoardSquares.length; ii++) {
for (int jj = 0; jj < chessBoardSquares[ii].length; jj++) {
JButton b = new JButton();
b.setMargin(buttonMargin);
// our chess pieces are 64x64 px in size, so we'll
// 'fill this in' using a transparent icon..
ImageIcon icon = new ImageIcon(
new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB));
b.setIcon(icon);
if ((jj % 2 == 1 && ii % 2 == 1)
//) {
|| (jj % 2 == 0 && ii % 2 == 0)) {
b.setBackground(Color.WHITE);
} else {
b.setBackground(Color.BLACK);
}
chessBoardSquares[jj][ii] = b;
}
}
//fill the chess board
chessBoard.add(new JLabel(""));
// fill the top row
for (int ii = 0; ii < 8; ii++) {
chessBoard.add(
new JLabel(COLS.substring(ii, ii + 1),
SwingConstants.CENTER));
}
// fill the black non-pawn piece row
for (int ii = 0; ii < 8; ii++) {
for (int jj = 0; jj < 8; jj++) {
switch (jj) {
case 0:
chessBoard.add(new JLabel("" + (ii + 1),
SwingConstants.CENTER));
default:
chessBoard.add(chessBoardSquares[jj][ii]);
}
}
}
}
public final JComponent getChessBoard() {
return chessBoard;
}
public final JComponent getGui() {
return gui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ChessBoardWithColumnsAndRows cb =
new ChessBoardWithColumnsAndRows();
JFrame f = new JFrame("ChessChamp");
f.add(cb.getGui());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// ensures the minimum size is enforced.
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
Notes
The chess board complete with columns on the left and a row above it is provided by a 9x9 GridLayout. The first cell of the grid layout is a label with no text.
To simplify the game logic though, we maintain a separate 8x8 array of buttons.
To allow keyboard functionality we use buttons for the chess board places. This also provides inbuilt focus indication. Remove the margin of the button to allow them to shrink to the size of the icon. Add an ActionListener to the button and it will respond to both keyboard and mouse events.
The small ? in the left hand side of the GUI is meant to imply that area is 'reserved for future use'. We might use it to show lists of captured pieces, a selector for choice of piece when promoting pawns, game statistics, ...
The chess piece images were obtained from Example images for code and mark-up Q&As, which was in turn developed out of 'Fill' Unicode characters in labels.
Using images is simpler, whereas filling Unicode characters is more versatile as well as being 'lighter'. I.E. to support 4 different colors in 3 separate sizes of 3 different chess piece styles would require 36 separate sprite sheets!
i have a Jframe which has some panels as instance variables and one of the panels is a grid board (i am implementing Lines of action game). After my game ends I have a button "Play again" which i want to reinitialize my board panel. I tried a lot of things like removing my panel from the content pane and re-initializing it, but nothing worked so far. Here are some of the things i tried (i didn't try them all at once )
public class Frame extends JFrame implements MouseListener{
JLabel l = new JLabel();
Panel1 Boards;
Panel2 newGame;
Panel3 winner;
Point lastCheckerSelected;
Board game = new Board();
public Frame() {
setResizable(false);
setTitle("Lines Of Action");
setBounds(290, 350, 1000, 700);
setLayout(null);
winner=new Panel3();
winner.playAgain.addMouseListener(this);
getContentPane().add(winner);
Boards= new Panel1();
getContentPane().add(Boards);
setDefaultCloseOperation(EXIT_ON_CLOSE);
l.setIcon(new ImageIcon(
"E:\\background0213.jpg"));
l.setBounds(0 ,0 , 1000 , 700);
getContentPane().add(l);
validate();
newGame=new Panel2();
newGame.b.addMouseListener(this);
getContentPane().add(newGame);
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
Boards.x[i][j].addMouseListener(this);
Boards.y[i][j].addMouseListener(this);
}
}
}
public void mouseClicked(MouseEvent e) {
if(e.getSource().equals(newGame.b)) {
Boards.setVisible(true);
newGame.setVisible(false);
game=new Board();
}
if(this.game.getWinner()==1) {
winner.setVisible(true);
winner.whiteWins.setVisible(true);
}
if(this.game.getWinner()==2) {
winner.setVisible(true);
winner.greywins.setVisible(true);
}
if(e.getSource().equals(winner.playAgain)) {
//this.getContentPane().remove(Boards);
// this.game= new Board();
// Boards = new Panel1();
// this.getContentPane().add(Boards);
//Boards.setVisible(true);
// validate();
// Boards.repaint();
}
}
public static void main(String[] args) {
Frame frame = new Frame();
frame.setVisible(true);
}
I still cant make my new panel appear ( removing the Boards panel from the content pane makes it disappear which is good but the new one does not appear)
here is my panel =1 that contains the board
public class Panel1 extends JPanel {
JButton[][] x = new JButton[8][8];
JButton[][] y=new JButton[8][8];
Graphics g;
public Panel1() {
setBounds(0, 30 ,400 ,400);
setLayout(new GridLayout(8, 8));
setOpaque(false);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
x[i][j] = new JButton();
x[i][j].setSize(50, 50);
if ((i % 2 == 0 && j % 2 == 0) || (i % 2 != 0 && j % 2 != 0)) {
x[i][j].setBackground(Color.DARK_GRAY.darker());
// x[i][j].setBackground(new Color(111,89,81,150));
}
else {
// Color.OPAQUE = 2;
x[i][j].setBackground(Color.red.darker().darker());
// x[i][j].setBackground(new Color(223,37,32,150));
}
x[i][j].setEnabled(false);
add(x[i][j]);
}
}
for(int i = 0; i < 8 ;i++){
for(int j=0;j < 8;j++){
y[i][j]=new JButton();
x[i][j].add(y[i][j]);
// y[i][j].setSize(100,100);
// y[i][j].setEnabled(false);
// y[i][j].setOpaque(false);
// y[i][j].setContentAreaFilled(false);
// y[i][j].setBorderPainted(false);
y[i][j].setVisible(false);
}
}
for(int i=1;i<7;i++){
// y[0][i].setOpaque(true);
y[0][i].setBackground(Color.white);
y[0][i].setEnabled(true);
y[0][i].setVisible(true);
// y[7][i].setOpaque(true);
y[7][i].setBackground(Color.white);
y[7][i].setEnabled(true);
y[7][i].setVisible(true);
}
for(int i=1;i<7;i++){
// y[i][0].setOpaque(true);
y[i][0].setEnabled(true);
y[i][0].setBackground(new Color(102,125,153));
y[i][0].setVisible(true);
// y[i][7].setOpaque(true);
y[i][7].setEnabled(true);
y[i][7].setBackground(new Color(102,125,153));
y[i][7].setVisible(true);
}
// addMouseListener(this);
setVisible(false);
}
}
You could also try this:
if(e.getSource().equals(winner.playAgain))
{
Boards.removeAll();
revalidate();
repaint();
}
I don't think you need to create a new Panel1 instance.
i have a Jframe which has some panels as instance variables and one of
the panels is a grid board (i am implementing Lines of action game).
After my game ends I have a button "Play again" which i want to
reinitialize my board panel. I tried a lot of things like removing my
panel from the content pane and re-initializing it, but nothing worked
so far.
I think that CardLayout is best of choices
Try these four together. Need to see more of your code to make sure this work.
if(e.getSource().equals(winner.playAgain)) {
this.getContentPane().remove(Boards);
Boards = new Panel1();
this.getContentPane().add(Boards);
this.invalidate();
this.validate();
this.repaint();
}
After the components are made visible in the screen, if you remove and add components, then you have to call Component.repaint() or Component.validate() to call the repainting again. Do this inside your actionPerformed() of your playAgainButton()