Formatting JButtons inside JPanels - java

So, I'm making a chessboard, and whenever I try to put down the buttons, they keep reorienting and get more and more messy towards the bottom right. The first button in the top right (squareB[0][0]) looks fine, but all the other JButtons are messed up.
So my question is how do I fix this or allow me to place the button at certain coordinates?
import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.io.*;
public class Test implements ActionListener
{
private JFrame frame = new JFrame();
private JPanel[][] square = new JPanel[8][8];
private JButton[][] button = new JButton[8][8];
public static void main(String[] args)
{
new Test();
}
Test()
{
frame.setLayout(new GridLayout(8,8));
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
square[x][y] = new JPanel();
frame.add(square[x][y]);
square[x][y].setSize(100,100);
square[x][y].setLayout(new GridLayout(1,1));
if(y%2==0)
if(x%2==0)
square[x][y].setBackground(Color.white);
else
square[x][y].setBackground(Color.black);
if(y%2!=0)
if(x%2==0)
square[x][y].setBackground(Color.black);
else
square[x][y].setBackground(Color.white);
button[x][y] = new JButton();
button[x][y] = new TestMethods(x,y);
square[x][y].add(button[x][y]);
button[x][y].setOpaque(false);
button[x][y].setContentAreaFilled(true);
button[x][y].setBorderPainted(true);
button[x][y].addActionListener(this);
}
}
frame.setSize(800,800);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
}
}
class TestMethods extends JButton
{
private int x, y;
public TestMethods(int x, int y)
{
this.x = x;
this.y = y;
}
public int getX() {return x;}
public int getY() {return y;}
}

I think part of your problem is related to the getX and getY methods of your TestMethods class. These are overriding methods used by the JButton to determine it's location on it's parent and you should avoid overriding them
class TestMethods extends JButton
{
private int x, y;
public TestMethods(int x, int y)
{
this.x = x;
this.y = y;
}
public int getX() {return x;}
public int getY() {return y;}
}
I would, instead, use method names that relate better to your purpose.
class TestMethods extends JButton
{
private int gridX, gridY;
public TestMethods(int x, int y)
{
this.gridX = x;
this.gridY = y;
}
public int getGridX() {return gridX ;}
public int getGridY() {return gridY ;}
}

Well, I cannot find what is going bad with your code, so I did write a method that does the same. I know this is not an answer, but may be useful:
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(800, 800));
frame.setLayout(new GridLayout(8, 8));
boolean isWhite = true;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
final JButton button = new JButton();
if (isWhite) {
button.setBackground(Color.white);
} else {
button.setBackground(Color.black);
}
isWhite = !isWhite;
frame.add(button);
}
isWhite = !isWhite;
}
frame.pack();
frame.setVisible(true);
}

Please look at the answer given by MadProgrammer. Also I have modified your example to create the chessboard. Please look at the modified way of creating chessboard pattern.
Test()
{
frame.setLayout(new GridLayout(8,8));
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
square[x][y] = new JPanel();
frame.add(square[x][y]);
square[x][y].setSize(100,100);
square[x][y].setLayout(new GridLayout(1,1));
button[x][y] = new TestMethods(x,y);
button[x][y].setOpaque(true);
button[x][y].setContentAreaFilled(true);
button[x][y].setBorderPainted(true);
button[x][y].addActionListener(this);
if((y + x)%2==0)
{
button[x][y].setBackground(Color.WHITE);
}
else
{
button[x][y].setBackground(Color.BLACK);
}
square[x][y].add(button[x][y]);
}
}
frame.setSize(800,800);
frame.setVisible(true);
}

Related

Why does this JButton extension cause visual problems in the frame?

I'm trying to create a JPanel that shows buttons forming a square of X size. I want to have the coordinates in a class that extends JButton, but when doing the extension some serious visual problems appear in the frame. If I remove it and use a normal JButton it doesn't happen.
I didn't find another public question with a similar problem. Can someone help me please?
Edit: Thanks to the comments noticed that I accidentally overridden the 'getX' and 'getY' methods of the Container superclass with my extension, that caused problems when it came to locating the JButtons and displaying them in the frame. Thanks.
import java.awt.GridLayout;
import javax.swing.*;
public class mainclass extends JFrame{
private int size= 10;
private class Button extends JButton{
private int x;
private int y;
public Button(int x, int y) {
super();
this.x= x;
this.y= y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
public mainclass(){
GridLayout gl= new GridLayout(size,size);
JPanel buttonsPane= new JPanel(gl);
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
Button temp= new Button(row,col);
temp.setVisible(true);
buttonsPane.add(temp);
buttonsPane.revalidate();
buttonsPane.repaint();
}
}
buttonsPane.setVisible(true);
getContentPane().add(buttonsPane);
setSize(700,700);
setLocationRelativeTo(null);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle("Buscaminas");
this.setVisible(true);
}
public static void main(String[] args) {
mainclass mc = new mainclass();
mc.setVisible(true);
}
}

Extended JButton fails to appear until Mouse Over

So the situation is that I'm making a panel filled with 8*8 buttons, like a matrix, and I'm gonna have to change specific button texts depending on the position of the clicked button. It seemd like a good idea to make my own JButton where I can assign x and y indexes to the button, so I can check easily wich button was clicked by indexes.
Here is the code for that:
import javax.swing.JButton;
public class MatrixButton extends JButton {
private int x;
private int y;
public MatrixButton(int x, int y, String text){
super(text);
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
And it does solve the task, but these Matrix buttons doesn't want to appear until I mouse over them. What could be the problem?
here is the code for the panel wich contains these buttons and handles their actions:
public class PlayField extends JPanel implements ActionListener {
private MatrixButton[][] button = new MatrixButton[8][8];
public PlayField(){
Random rand = new Random();
setLayout(new GridLayout(8, 8));
for (int i = 0; i < 8; ++i){
for (int j = 0; j < 8; ++j){
button[i][j] = new MatrixButton(j, i, "" + rand.nextInt(80));
button[i][j].addActionListener(this);
add(button[i][j]);
}
}
}
private String incrementText(MatrixButton mb){
return "" + (Integer.parseInt(mb.getText()) + 1);
}
#Override
public void actionPerformed(ActionEvent e){
MatrixButton mb = (MatrixButton)e.getSource();
for (int i = mb.getY(); i >= 0; --i){
button[i][mb.getX()].setText(incrementText(button[i][mb.getX()]));
}
for (int i = 0; i < 8; ++i){
if (i != mb.getX())
button[mb.getY()][i].setText(incrementText(button[mb.getY()][i]));
}
}
}
PS: if I fill with ordinary JButtons they appear as they should be. Thats why I'm confused, cuz I didn't change much on the JButton extension just added 2 more variables to it.
This is dangerous code:
public int getX() {
return x;
}
public int getY() {
return y;
}
You do realize that this overrides two of JButton's critical methods (actually, the methods are from JButton's parent, JComponent) that help set the placement of the button on the GUI (add #Override above the methods to see that this is so). I strongly suggest that you either change the signature of these methods, perhaps getGridX() and getGridY(), or even better, use composition and not inheritance, since you run into risk of these types of problems -- unwittingly overriding a key method -- when you extend complex classes such as Swing component classes. For this reason I try to avoid extending these classes unless absolutely necessary.
For example:
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PlayField {
private static final int ROWS = 8;
private static final int COLS = ROWS;
private static final int MAX_RAND = 80;
private JPanel mainPanel = new JPanel();
private MatrixButton[][] button = new MatrixButton[ROWS][COLS];
public PlayField(){
Random rand = new Random();
mainPanel.setLayout(new GridLayout(ROWS, COLS));
for (int i = 0; i < ROWS; ++i){
for (int j = 0; j < COLS; ++j){
button[i][j] = new MatrixButton(j, i, rand.nextInt(MAX_RAND));
button[i][j].addActionListener(new MyMatrixListener(i, j));
mainPanel.add(button[i][j].getButton());
}
}
}
private class MyMatrixListener implements ActionListener {
private int i;
private int j;
public MyMatrixListener(int i, int j) {
this.i = i;
this.j = j;
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i2 = 0; i2 < button.length; i2++) {
if (i2 != i) {
int value = button[i2][j].getValue();
value++;
button[i2][j].setValue(value);
}
}
for (int j2 = 0; j2 < button[i].length; j2++) {
if (j2 != j) {
int value = button[i][j2].getValue();
value++;
button[i][j2].setValue(value);
}
}
}
}
public JPanel getMainPanel() {
return mainPanel;
}
private static void createAndShowGui() {
JFrame
frame = new JFrame("PlayField");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new PlayField().getMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MatrixButton {
private int column;
private int row;
private JButton button = new JButton();
private int value;
public MatrixButton(int column, int row, int value) {
this.column = column;
this.row = row;
setValue(value);
}
public void addActionListener(ActionListener listener) {
button.addActionListener(listener);
}
public int getColumn() {
return column;
}
public int getRow() {
return row;
}
public JButton getButton() {
return button;
}
public int getValue() {
return value;
}
public final void setValue(int value) {
this.value = value;
button.setText("" + value);
}
}
Better to just use ints and not Strings

JTextFields don't show up, but they're still there. (the first one is "bugily" visible)

It worked an hour ago, but I must have done something to the code and I have no idea what. My JTextFields don't show up, but if I set them to editable, they're still there. The first JTextField does show up, but looks weird. Any ideas what's wrong? (I call my JTextFields "Square"). Size = 10
package gui;
import javax.swing.*;
import engine.GameEngine;
import java.awt.*;
import java.util.*;
public class MineFieldGUI extends JFrame {
private GameEngine engine;
Square[][] field;
int size = 10;
public MineFieldGUI(GameEngine minefield) {
super("MineField");
this.engine = minefield;
this.size = minefield.getSize();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(300, 350);
Locale.setDefault(new Locale("en"));
setLayout(new BorderLayout());
JMenuBar menubar = new JMenuBar();
setJMenuBar(menubar);
JMenu helpMenu = new JMenu("Help");
menubar.add(helpMenu);
helpMenu.add(new HelpMenu(this));
//***THE MINE-FIELD***
JPanel panel = new JPanel(new GridLayout(size,size));
field = new Square[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
field[i][j] = new Square(i, j);
panel.add(field[i][j]);
}
}
add(panel, BorderLayout.CENTER);
setVisible(true);
}
public void setColor(int x, int y){
field[x][y].setBackground(Color.lightGray);
}
public void setText(int x, int y, String text){
field[x][y].setText(text);
}
public String getText(int x, int y){
return field[x][y].getText();
}
}
My textFields:
package gui;
import java.awt.Color;
import javax.swing.JTextField;
public class Square extends JTextField {
int posX;
int posY;
public Square(int x, int y) {
super("");
posX = x;
posY = y;
this.setEditable(false);
this.setBackground(Color.lightGray);
}
public int getX(){
return posX;
}
public int getY(){
return posY;
}
}
Remove the methods getX and getY which are being used by the layout manager to position the Square components. This will let the layout manager correctly position the buttons.

Java keeps giving me my coordinates multiplied by 93

When I set X and Y values for my array of JButtons, I get back the correct values only multiplied by 93. I can solve the problem by dividing the value by 93 but I would rather find out where the bug was in the first place.
I have two classes in the code, one for the actual program, and one for the button object along with the coordinates.
Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridLayout;
import java.io.*;
public class ConnectFour implements ActionListener
{
JFrame frame = new JFrame();
Button [][] buttons = new Button[6][7];
public ConnectFour()
{
frame.setSize(700,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(6,7));
frame.setLocationRelativeTo(null);
frame.setTitle("Connect Four");
for(int filler = 0; filler <= 5; filler++)
{
for(int filler2 = 0; filler2 <= 6; filler2++)
{
buttons[filler][filler2] = new Button();
buttons[filler][filler2].setX(filler2);
buttons[filler][filler2].setY(filler);
//System.out.println(buttons[filler][filler2].getX());
//System.out.print(buttons[filler][filler2].getY());
frame.add(buttons[filler][filler2].button);
buttons[filler][filler2].button.addActionListener(this);
}
}
frame.setVisible(true);
}
public void actionPerformed(ActionEvent a)
{
JButton pressedButton = (JButton)a.getSource();
System.out.print(pressedButton.getY() / 93);
System.out.print(pressedButton.getX() / 93);
}
public static void main(String args[])
{
ConnectFour gameplay = new ConnectFour();
}
}
Here's the Button class:
import javax.swing.JButton;
public class Button
{
JButton button;
private int x = 0;
private int y = 0;
public Button()
{
button = new JButton();
}
public int getX() {return x;}
public int getY() {return y;}
public void setX(int xIndex)
{
x = xIndex;
}
public void setY(int yIndex)
{
y = yIndex;
}
}
You're mixing your two Button classes.
In this line, you're adding an actionListener to Button.button:
buttons[filler][filler2].button.addActionListener(this);
because JButton also has methods getX and getY, you can call them. When you do:
pressedButton.getX()
you're getting the x position of the JButton, not of your Button.
What I think would be the easiest way to solve this problem is making your button extend JButton and rename x and y to row and column, for instance:
public class Button extends JButton {
private int row = 0;
private int column = 0;
public Button(int row, int column) {
super();
this.row = row;
this.column = column;
}
public int getRow() {return row;}
public int getColumn() {return column;}
}
You can create you buttons as
for(int filler = 0; filler <= 5; filler++) {
for(int filler2 = 0; filler2 <= 6; filler2++) {
buttons[filler][filler2] = new Button(filler2, filler);
frame.add(buttons[filler][filler2]);
buttons[filler][filler2].addActionListener(this);
}
}
And use them in the ActionListener as
public void actionPerformed(ActionEvent a) {
Button pressedButton = (Button)a.getSource();
System.out.print(pressedButton.getColumn());
System.out.print(pressedButton.getRow());
}
I could not figure how to do it using your composition example, but this one works as you might want.
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridLayout;
import java.io.*;
public class ConnectFour implements ActionListener
{
JFrame frame = new JFrame();
CustomButton [][] buttons = new CustomButton[6][7];
public ConnectFour()
{
frame.setSize(700,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(6,7));
frame.setLocationRelativeTo(null);
frame.setTitle("Connect Four");
for(int filler = 0; filler <= 5; filler++)
{
for(int filler2 = 0; filler2 <= 6; filler2++)
{
buttons[filler][filler2] = new CustomButton(filler,filler2);
frame.add(buttons[filler][filler2]);
buttons[filler][filler2].addActionListener(this);
}
}
frame.setVisible(true);
}
public void actionPerformed(ActionEvent a)
{
CustomButton pressedButton = (CustomButton)a.getSource();
System.out.println(pressedButton.getRow() + "/" + pressedButton.getCol());
}
public static void main(String args[])
{
ConnectFour gameplay = new ConnectFour();
}
}
class CustomButton extends JButton
{
private int row = 0;
private int col = 0;
public CustomButton(int row, int col)
{
this.row = row;
this.col = col;
}
public int getRow() {return row;}
public int getCol() {return col;}
public void setRow(int row)
{
this.row = row;
}
public void setCol(int col)
{
this.col = col;
}
}
I think x and y are defined in the superclass, try changing the variable names to something else. e.g.
private int myX = 0;
private int myY = 0;

Java, Grid of Objects

I need help with drawing the grids to the GUI as well as the program later letting me change the colour of the boxes drawn. I know i will have to use paintComponent(Graphics g), but i have no idea how or where.
So here is a copy of the code i have got so far ( even though i have been told it can be quite daunting just being given code i think it is the best way for people to help and not just do it for me). From the top it sets values, creates the GUI, calls the GUI, fills a 2d array with boxes( i think). Then in the Boxes class setting values the boxes class will need, then the start of how to draw them (didn't know how to work it out), then some seta methods for the x and y coordinates.
what i would like you to do is show how to have the boxes be drawn to the Jpanel, to make a grid and then to show me how to change the colour to different shades of blue, depending on a external value.
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
Boxes[][] Boxs;
int BoxesX;
int BoxesY;
NewGrid() {
buildtheGUI();
}
JFrame frame = new JFrame();
JPanel panel = new JPanel();
public void buildtheGUI() {
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
new NewGrid();
}
public void addboxes() {
Boxs = new Boxes[panel.getWidth() / 10][panel.getHeight() / 10];
for (int i = 0; i < panel.getWidth() / 10; i++) {
for (int j = 0; j < panel.getHeight() / 10; j++) {
Boxs[i][j] = new Boxes();
Boxs[i][j].setx(i * (panel.getWidth() / 10));
Boxs[i][j].sety(j * (panel.getHeight() / 10));
Boxs[i][j].draw(null);
}
}
}
}
public class Boxes extends JPanel {
int x;
int y;
int width = 10;
int hieight = 10;
Color colour = Color.BLACK;
public void draw(Graphics g) {
g.setColor(colour);
g.fillRect(x, y, width, hieight);
}
public void setx(int i ){
x = i;
}
public void sety(int i ){
y = i;
}
}
I can't comment something, to try to make things easier,
I code there box.putClientProperty(unique_identifier, value_for_identifier), you can to multiple this method as you want
from every Swing Listener you can to get this and proper coordinated defined in putClientProperty
.
JComponent comp = event.getComponent();
String strRow = (String) comp.getClientProperty("row");
String strColumn = (String) comp.getClientProperty("column");
simple code
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
private int row = 10;
private int column = 10;
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
private NewGrid() {
addboxes();
panel.setLayout(new GridLayout(row, column));
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private void addboxes() {
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
Boxes box = new Boxes();
box.putClientProperty("row", row);
box.putClientProperty("column", column);
panel.add(box);
}
}
}
public static void main(String[] args) {
Runnable doRun = new Runnable() {
#Override
public void run() {
new NewGrid();
}
};
SwingUtilities.invokeLater(doRun);
}
}
class Boxes extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(20, 20);
}
#Override
public void paintComponent(Graphics g) {
int margin = 2;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2,
dim.height - margin * 2);
}
}

Categories

Resources