Adding a Button array to a JPanel - java

I have another problem with my project. I have created this GameBoard made out of JButtons (it works as it's supposed to now) but I would need to add it to a JPanel. I need to display other things (in other panels) in the window. But when I tried to add the Button Array to a panel, and add that panel to the window, crazy things started happening (the buttons were very small, the grid was completely broken etc.). How could I add this Button Array to a JPanel and put that in the center of the window?
Here is my code:
package city;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameBoard extends JFrame implements ActionListener {
// The overall box count in chess board
public static final int squareCount = 64;
// The Array of buttons (the GameBoard itself)
public Button[][] button = new Button[8][8];
// Colors for all the buttons
public Color defaultColor = Color.WHITE;
public Color darkRedColor = Color.RED;
public Color darkBlueColor = Color.BLUE;
public Color lightBlueColor = Color.CYAN;
public Color lightRedColor = Color.PINK;
public GameBoard(String title) {
// Creates the buttons in the array
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
button[i][j] = new Button();
add(button[i][j]);
button[i][j].setBackground(defaultColor);
}
}
// Build the window
this.setTitle(title); // Setting the title of board
this.setLayout(new GridLayout(8, 18)); // GridLayout will arrange elements in Grid Manager 8 X 8
this.setSize(650, 650); // Size of the chess board
this.setVisible(true); // Sets the board visible
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // If you close the window, the program will terminate
this.setResizable(false); //The window is not resizable anymore ;)
// Sets some text on the buttons
button[0][3].setText("Red's");
button[0][4].setText("Gate");
button[7][3].setText("Blue's");
button[7][4].setText("Gate");
// Colors the buttons
newGame();
}
// Colors the buttons
public void newGame() {
button[0][0].setBackground(lightRedColor);
button[0][1].setBackground(lightRedColor);
button[0][2].setBackground(lightRedColor);
button[0][3].setBackground(darkRedColor);
button[0][4].setBackground(lightRedColor);
button[0][5].setBackground(lightRedColor);
button[0][6].setBackground(lightRedColor);
button[0][7].setBackground(lightRedColor);
button[1][3].setBackground(darkRedColor);
button[7][0].setBackground(lightBlueColor);
button[7][1].setBackground(lightBlueColor);
button[7][2].setBackground(lightBlueColor);
button[7][3].setBackground(lightBlueColor);
button[7][4].setBackground(darkBlueColor);
button[7][5].setBackground(lightBlueColor);
button[7][6].setBackground(lightBlueColor);
button[7][7].setBackground(lightBlueColor);
button[6][4].setBackground(darkBlueColor);
}
// The ActionListener is not yet used
public void actionPerformed(ActionEvent ae) {
String action = ae.getActionCommand();
}
public static void main(String[] args) {
String title = "City - A Two-Player Strategic Game";
GameBoard gameBoard = new GameBoard(title); // Creating the instance of gameBoard
}
}
And here is a screenshot of the bad GUI that generated:
Bad GUI
Thanks for any help, and good luck everyone with a similar problem!

Is this what you are looking for? I am not very sure what´s the problem.
This adds the buttons to a new JPanel and adds this panel to the frame.
JPanel panel = new JPanel(new GridLayout(8, 8));
panel.setSize(650,650);
getContentPane().add(panel, BorderLayout.CENTER);
// Creates the buttons in the array
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
button[i][j] = new JButton();
panel.add(button[i][j]);
button[i][j].setBackground(defaultColor);
}
}
// Build the window
this.setTitle(title); // Setting the title of board
getContentPane().setLayout(new BorderLayout());
this.setSize(650, 650); // Size of the chess board
this.setVisible(true); // Sets the board visible
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // If you close the window, the program will terminate
this.setResizable(false); //The window is not resizable anymore ;)

Related

GridLayout is showing odd behavior

I am trying to create a grid comprised of 100 squares. My code below is extremely buggy and I am not sure why.
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class snake extends JFrame
{
public static void main(String[] args)
{
Border whiteLine = BorderFactory.createLineBorder(Color.white);
//-----------FRAME
JFrame frame = new JFrame();
frame.setSize(1000,1000);
frame.setTitle("Snake");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.black);
frame.setVisible(true);
frame.setLayout(new GridLayout(10,10));
//-----------FRAME
//-----------PANELS
Dimension panelDimension = new Dimension(20,20);
int counter = 0;
JPanel[][] p = new JPanel[10][10];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
p[i][j] = new JPanel();
//p[i][j].setPreferredSize(panelDimension);
p[i][j].setBackground(Color.red);
//p[i][j].setLocation(490,490);
p[i][j].setBorder(whiteLine);
p[i][j].setVisible(true);
frame.getContentPane().add(p[i][j]);
counter+=1;
}
}
System.out.println("counter: " + counter);
}
}
When I run the code like this it shows a grid comprised of 2 columns the first column has 7 rows and the second column has 6. Sometimes it even shows other incorrect numbers of columns and rows. I am not sure why it doesn't create a grid of 10 rows 10 columns.
You've got several problems including:
Calling setVisible(true) on the JFrame before adding components, before calling pack() on the top-level window. This can lead to wonky positioned components within our GUI's or even GUI's that remain empty
Not calling pack() on the JFrame after adding components and before setting it visible
Setting the size of the JFrame. Let the layout managers, containers and components do this for you (which is what calling pack() is for)
Setting it to a bad size, a "perfect square", one that ignores the menu bar that the OS adds,
...
For example:
package foo01;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class SnakePanel extends JPanel {
private static final int CELL_WIDTH = 80;
private static final Dimension CELL_DIMENSION = new Dimension(CELL_WIDTH, CELL_WIDTH);
private static final int COLUMNS = 10;
private static final int GAP = 2;
private static final Color BG_COLOR = Color.WHITE;
private static final Color CELL_COLOR = Color.RED;
public SnakePanel() {
setBackground(BG_COLOR);
// add a white line around the grid
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
// create a grid with gaps that show the background (white) color
setLayout(new GridLayout(COLUMNS, COLUMNS, GAP, GAP));
for (int row = 0; row < COLUMNS; row++) {
for (int col = 0; col < COLUMNS; col++) {
JPanel cell = new JPanel(); // create a new cell
cell.setPreferredSize(CELL_DIMENSION); // cheating here. Better to override getPreferredSize()
cell.setBackground(CELL_COLOR);
add(cell);
// give the cell JPanel some simple behavior:
cell.addMouseListener(new MyMouse(col, row));
}
}
}
private class MyMouse extends MouseAdapter {
private int col;
private int row;
public MyMouse(int col, int row) {
this.col = col;
this.row = row;
}
#Override
public void mousePressed(MouseEvent e) {
System.out.printf("Mouse pressed row and column: [%d, %d]%n", row, col);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// create the main JPanel
SnakePanel snakePanel = new SnakePanel();
// create the JFrame
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// add the main JPanel to the JFrame
frame.add(snakePanel);
// pack the JFrame -- tells the layout managers to do their things
frame.pack();
// if we want to center the GUI:
frame.setLocationRelativeTo(null);
// only *now* do we display the GUI
frame.setVisible(true);
});
}
}
Some notes on the code:
Any code within the Runnable passed into the SwingUtilities.invokeLater(...) method is called on the Swing event thread, which is a wise thing to do when creating a Swing GUI
SwingUtilities.invokeLater(() -> {
// ....
});
First, create the main JPanel that is held by the JFrame:
SnakePanel snakePanel = new SnakePanel();
Then create the JFrame, add that JPanel and call pack(). The pack call tells the layout managers to do there thing, to lay out components within containers, to size things based on their preferred sizes and their layouts:
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(snakePanel);
frame.pack();
if we want to center the GUI:
frame.setLocationRelativeTo(null);
only now do we display the GUI
frame.setVisible(true);

placing 64 buttons randomly in a girdlaout java

The goal is to create a create a game like rubrics cube where the user has to rearrange the buttons according to the matched color. This is what I did to place the buttons randomly, but it doesn't work when the buttons are presented. The random order is taken as the ordered order if that makes sense. Any ideas on how to fix this?
while(list1.size()!=501){
int x=rand.nextInt(8);
list1.add(x);
}
while(list2.size()!=501){
int x=rand.nextInt(8);
list2.add(x);
}
for(int b=0;b<500;b++){
int l= list1.get(b);
//System.out.println(l);
int j= list2.get(b);
panel.add(buttons[l][j]);
//System.out.println(buttons[l][j].getBackground());
}
Consider:
Giving the buttons a value of some sort that represents their true order. There are several ways to do this, including putting them in an array of specified order, or extending JButton and giving your class an int value field, or using a HashMap
Place these buttons into an ArrayList<JButton>
Shuffling the ArrayList via Collections.shuffle(...)
Then adding the buttons to your GUI
Alternatively, you could use non-shuffled JButtons and instead shuffle AbstractActions which you then set into the buttons.
The details of any solution will depend on the details of your current program, something that we don't yet know enough about. If you need more detailed help, do consider creating and posting a valid MCVE in your question.
For example, compile and run this, and then read the comments:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.*;
public class RandomButtons extends JPanel {
private static final long serialVersionUID = 1L;
private static final int ROWS = 8;
private JButton[][] buttons = new JButton[ROWS][ROWS];
private List<JButton> buttonList = new ArrayList<>();
private JPanel buttonsPanel = new JPanel(new GridLayout(ROWS, ROWS));
public RandomButtons() {
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
// create new JBUtton
final JButton button = new JButton("Button");
// put into array
buttons[i][j] = button;
// put into ArrayList
buttonList.add(button);
// unique value 0 to 63 for each button
// order it has been created
final int value = i * ROWS + j;
// create one of 64 different color hues using value above
float hue = ((float) value) / (ROWS * ROWS);
float sat = 0.7f; // reduce sat so we can see text
float brightness = 1.0f;
Color color = Color.getHSBColor(hue, sat, brightness);
button.setBackground(color); // set button's color
button.addActionListener(e -> {
// display the button's order
System.out.println("Value: " + value);
});
}
}
randomizeButtons();
JButton randomizeButton = new JButton("Randomize");
randomizeButton.addActionListener(e -> { randomizeButtons(); });
JButton orderButton = new JButton("Put in Order");
orderButton.addActionListener(e -> { orderButtons(); });
JPanel bottomPanel = new JPanel(new GridLayout(1, 2));
bottomPanel.add(randomizeButton);
bottomPanel.add(orderButton);
setLayout(new BorderLayout());
add(buttonsPanel, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
public void randomizeButtons() {
buttonsPanel.removeAll(); // remove all buttons
Collections.shuffle(buttonList); // shuffle the ArrayList
// re-add the buttons **using the ArrayList**
for (JButton jButton : buttonList) {
buttonsPanel.add(jButton);
}
// tell JPanel to layout its newly added components
buttonsPanel.revalidate();
// and then paint them
buttonsPanel.repaint();
}
public void orderButtons() {
buttonsPanel.removeAll(); // remove all buttons
// re-add the buttons **using the 2D array**
for (JButton[] buttonRow : buttons) {
for (JButton jButton : buttonRow) {
buttonsPanel.add(jButton);
}
}
buttonsPanel.revalidate();
buttonsPanel.repaint();
}
private static void createAndShowGui() {
RandomButtons mainPanel = new RandomButtons();
JFrame frame = new JFrame("RandomButtons");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

Creating bold cell border lines JTable

I'm trying to create a Sudoku game and I am having trouble creating the bold lines to break it into 3 x 3 blocks. My recent attempt was to impose an image on top of the table using JLabel. The problem is the label completely covers the JTable. I goofed around with setting the opacity of the label and the table with no luck. Here are some images to show what I'm aiming for:
The current look:
The goal:
If you could advise me as to a method I can use to create these lines, it would be greatly appreciated. No direct answers needed, just a point in the right direction.
Check out Table Row Rendering.
It shows how to provide a custom Border for each cell in a row.
So you would need to modify the code to provide multiple different Borders depending on the cell being rendered.
For any board game I'd tend to use buttons in a grid layout (or a group of grid layouts) like in this mine sweeper game or this chess board.
For the borders in this GUI though, I'd use a 3 x 3 group of nine grid layouts, each of which has a LineBorder. By default the border would go around all four sides of the panel it is displayed in, but where they meet the border would be double width, thereby coming close to recreating the second image.
E.G.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
public class Soduko {
private JComponent ui = null;
Soduko() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridLayout(3,3));
ui.setBorder(new EmptyBorder(4,4,4,4));
ArrayList<Integer> values = new ArrayList<>();
for (int ii=0; ii<34; ii++) {
values.add(0);
}
Random r = new Random();
for (int ii=34; ii<81; ii++) {
values.add(r.nextInt(9)+1);
}
Collections.shuffle(values);
int count=0;
for (int ii=0; ii<9; ii++) {
JPanel p = new JPanel(new GridLayout(3, 3));
p.setBorder(new LineBorder(Color.BLACK, 2));
ui.add(p);
for (int jj=0; jj<9; jj++) {
int v = values.get(count++).intValue();
String s = v>0 ? "" + v : "";
p.add(new JButton(s));
}
}
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
Soduko o = new Soduko();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}

Changing text of JLabel in ActionEvent

OK, so I'm creating a Tic Tac Toe GUI. I currently having a working frame of 3x3 buttons that will change to either an X or O. My issue is implementing a JLabel on the top of the buttons. The label keeps track of who's turn it is and will change from either "O's turn" or "X's turn" however I can't seem to get the JLabel to update (only spouts errors). Here's a portion of my code showing how Trying to implement this. The program runs fine but as soon as I add the (turn.setText("O's turn");) I get errors.
Any feedback as to why this may not be working would be appreciated.
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TicTacToe extends JFrame {
XOButton[] xob = new XOButton[9];
private JLabel turn;
public static int state;
public TicTacToe() {
super("TicTacToe");
//add XOButtons to panel
JPanel center = new JPanel();
state = 0;
JLabel turn = new JLabel("X's turn");
center.setLayout(new GridLayout(3, 3, 2, 2));
//action listener
ButtonListener bl = new ButtonListener();
for (int i = 0; i < 9; i++) {
xob[i] = new XOButton();
xob[i].addActionListener(bl);
center.add(xob[i]);
}
//add panel to frame
setLayout(new BorderLayout());
add(center, BorderLayout.CENTER);
add(turn, BorderLayout.NORTH);
}
//inner action listener class
private class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent ae) {
for (int i = 0; i < 9; i++) {
if(ae.getSource() == xob[i] && xob[i].getState() == XOButton.NONE && state == 0) {
xob[i].setState(XOButton.X);
state = 1;
//turn.setText("O's turn");
} else if(ae.getSource() == xob[i] && xob[i].getState() == XOButton.NONE && state == 1) {
xob[i].setState(XOButton.O);
state = 0;
}
}
}
}
}
Guess: your error is a NullPointerException because turn is null. Solution: don't shadow the variable. In other words you're re-declaring the turn variable in the constructor leaving the field null.
e.g.,
public class TicTacToe extends JFrame{
XOButton[] xob = new XOButton[9];
private JLabel turn;
public static int state;
public TicTacToe() {
super("TicTacToe");
//add XOButtons to panel
JPanel center = new JPanel();
state = 0;
JLabel turn = new JLabel("X's turn"); // **** you're re-declaring turn here!
Better:
public class TicTacToe extends JFrame{
XOButton[] xob = new XOButton[9];
private JLabel turn;
public static int state;
public TicTacToe() {
super("TicTacToe");
//add XOButtons to panel
JPanel center = new JPanel();
state = 0;
turn = new JLabel("X's turn"); // **** Note the difference?
In the future, if you have similar problems, please post the entire error message and indicate which line throws the exception as it will help us immensely!

Change the color of a certain pane in gridlayout

So, what I want to happen is for every box to be white but when the user clicks on one of the boxes in the grid, it will change to a randomly generated color. I know how to write the code for the randomly generated color, but I'm not sure how to make it so that the program chooses the correct panel to change its color. Here is what i have so far:
Client
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class Prog3
{
public static void main(String[] args)
{
int rows=8;
int cols=8;
JFrame theGUI = new JFrame();
theGUI.setTitle("GUI Example");
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = theGUI.getContentPane();
pane.setLayout(new GridLayout(rows, cols,5,5));
for (int i = 1; i < rows * cols; i++)
{
Color backColor = Color.white;
Prog3_Server panel = new Prog3_Server(backColor,50,50);
pane.add(panel);
}
theGUI.pack();
theGUI.setVisible(true);
}
}
Server
import javax.swing.*;
import java.awt.*;
public class Prog3_Server extends JPanel
{
public static void main(String[] args)
{
JFrame theGUI = new JFrame();
theGUI.setTitle("GUI Example");
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Prog3_Server panel = new Prog3_Server(Color.white, 200, 200);
Container pane = theGUI.getContentPane();
pane.add(panel);
theGUI.pack();
theGUI.setVisible(true);
}
// Client provides color and preferred width and height
public Prog3_Server(Color backColor, int width, int height){
setBackground(backColor);
setPreferredSize(new Dimension(width, height));
}
// Client provides color
// Preferred width and height are 0, 0 by default
public Prog3_Server(Color backColor){
setBackground(backColor);
}
}
Any ideas on how i would use mouse events to make sure the right panel is changed from white to a random color?
You need a MouseListener/MouseAdapter
MouseListener detectClick = new MouseAdapter() {
public void mouseClicked(MouseEvent me) {
me.getSource().setBackground(createRandomBackgroundColor());
}
}
If you add this MouseListener to all of your sub-panels, you should get the result you want
You should add the MouseListener where you're creating and adding the subpanels to the parent panel, here:
//create MouseListener here
for (int i = 1; i < rows * cols; i++)
{
Color backColor = Color.white;
Prog3_Server panel = new Prog3_Server(backColor,50,50);
//add mouse listener to the panel you've created here
pane.add(panel);
}

Categories

Resources