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);
}
}
Related
I am a student in the process of making a Tic Tac Toe game, and currently have most of the UI and grid itself. I know AWT is out of data and Swing is much more informative and useful, but I am being taught and have the most resources on AWT. I currently have 5 classes:
GUI Class:
import java.awt.*;
import javax.swing.JFrame;
public class GUI{
JFrame frame1;
Board board1;
Buttons buttons;
MyMenu menu1;
public GUI() {
frame1 = new JFrame("Tic Tac Toe");
board1 = new Board(3,3 ,200);
buttons = new Buttons(this);
menu1 = new MyMenu(this);
}
public void start () {
frame1.setLayout(new FlowLayout());
board1.setBackground(Color.BLACK);
frame1.setMenuBar(menu1);
frame1.add(board1);
frame1.add(buttons);
frame1.pack();
frame1.setVisible(true);
}
public static void main (String[] args) {
GUI gui = new GUI();
gui.start();
}
public void setBackground (Color c) {
board1.setBackground(c);
}
public void closeGame() {
frame1.dispose();
}
}
Board Class:
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.*;
public class Board extends Canvas {
Cell[][] array;
int rows, cols;
public Board(int rows, int cols, int size) {
this.rows = rows;
this.cols = cols;
array = new Cell[rows][cols];
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
setSize(cols*size,rows*size);
}
public int getNumRows() {
return rows;
}
public int getNumCols () {
return cols;
}
public void draw(Graphics g) {
for (Cell[] row : array) {
for (Cell cell : row) {
cell.paint(g);
}
}
}
public void paint(Graphics g) {
draw(g);
}
}
Cell Class:
import java.awt.Color;
import java.awt.*;
public class Cell
{
private final int x;
private final int y;
private final int size;
int rows;
int cols;
Cell[][] array = new Cell[rows][cols];
public Cell(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
}
public void fillArray() {
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
}
public void paint(Graphics g) {
g.setColor(Color.YELLOW);
g.drawRect(x, y, size, size);
}
}
Button Class:
import java.awt.*;
import java.awt.event.*;
public class Buttons extends Panel implements ActionListener {
Button test;
Button giveIn;
GUI gui;
public Buttons(GUI gui) {
this.gui = gui;
giveIn = new Button("GIVE UP!");
this.add(giveIn);
giveIn.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()== giveIn) {
gui.closeGame();
}
}
}
I also have another class, implementing a Menu, but didn't feel it was necessary to include. How hard would and how would I implement it so when I click a rectangle on my grid, something is painted onto that specific rectangle? I understand I would need a mouse listener, and some sort of if statement on my paint method, as well as some methods that return the cell or rectangle clicked. How is something like this implemented?
I am trying to make a button, that upon clicked, changes the grid color of the rectangles I have drawn.
Here is my drawn grid. I would like the menu items I have under grid, when pressed, change the rectangle outline colors of the drawn grid. I have tried a couple methods, but seem to have trouble implementing it.
Here is my Menu Class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyMenu
extends MenuBar
implements ActionListener {
Menu paperMenu;
MenuItem c1, c2, c3;
GUI gui;
Cell cell;
public MyMenu(GUI gui) {
this.gui = gui;
this.cell = cell;
paperMenu = new Menu("Grid");
c1 = new MenuItem("Red");
c2 = new MenuItem("Green");
c3 = new MenuItem("Random");
paperMenu.add(c1);
paperMenu.add(c2);
paperMenu.add(c3);
this.add(paperMenu);
c1.addActionListener(this);
c2.addActionListener(this);
c3.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()==c1) {
}
}
}
Here is my Board class
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.*;
public class Board
extends Canvas {
private Cell[][] array;
public Board(int rows, int cols, int size) {
array = new Cell[rows][cols];
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
setSize(cols*size,rows*size);
}
public void draw(Graphics g) {
for (Cell[] row : array) {
for (Cell cell : row) {
cell.paint(g);
}
}
}
public Cell getCell(int r, int c) {
return array[r][c];
}
public void paint(Graphics g) {
draw(g);
}
}
And Finally, here is my Cell Class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.*;
public class Cell
{
private final int x;
private final int y;
private final int size;
int rows;
int cols;
Cell[][] array = new Cell[rows][cols];
public Color currentcolor = Color.BLACK;
public Cell(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
}
public void fillArray() {
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
}
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.drawRect(x, y, size, size);
}
}
I obviously need to make it, so when the button is pressed, the g.setColor under the Cell class and paint method is changed and then repainted, but I am unsure on how to do this?
First, you might want to understand the difference between Swing and AWT (and why you might want to prefer the latter)
Understanding the Difference Between AWT And Swing In Java
Difference between AWT and Swing in Java
What is the difference between Swing and AWT?
What is the Difference Between AWT and Swing in Java
Difference Between AWT and Swing in Java
Difference between AWT and Swing
AWT and Swing in Java
If you're just starting out, you might also consider using JavaFX instead.
You will also want to investigate things like:
Dependency Injection
Composition over inheritance
Liskov substitution principle
Single Responsibility Principle
As this will all effect the way in which you approach designing your solutions to your problems.
For example, do you really need to extend from MenuBar? What new functionality are you bringing to the class, which couldn't be achieved through a builder or factory pattern?
Each individual menu item could also have it's action handling isolating, so that you're dealing with single response for each action, rather then, what will become, a messy if-else statement in the future (ie Single Responsibility Principle)
Having said all that, your basic problem comes down to, providing some way to notify the Board that it needs to update the gridColor when a menu item is selected.
This can be solved through the use a Observer Pattern. You've already used this, ActionListener is a implementation of the observer pattern.
Now, there is no reason for MyMenu to have full control over GUI (which I'm assuming is some kind Frame), it would be better to make some kind of delegate which is responsible for coordinating messaging between the menu bar and the interested party (this can some times be referred to as a controller, but I'm not going that far).
The first thing we need is to define the functionality we're willing to expose, for example...
public interface BoardConfigurable {
public void setBoardGridColor(Color color);
}
This is a simple contract for telling the interested party that the board grid color should be changed.
(Before some jumps down my throat, we could have a interface called, I don't, MyMenuListener, which then implements BoardConfigurable and possibly a bunch of other interfaces, which further allows for decoupling of the basic code, but this is what I would consider separating the action handling into isolated units of work - but this is going way beyond what is required right now)
We then update MyMenu to accept an instance of this delegate/observer and update the actionPerformed method to call it when ever an appropriate action is triggered.
public class MyMenu
extends MenuBar
implements ActionListener {
Menu paperMenu;
MenuItem c1, c2, c3;
BoardConfigurable boardConfig;
Cell cell;
public MyMenu(BoardConfigurable boardConfig) {
this.boardConfig = boardConfig;
this.cell = cell;
paperMenu = new Menu("Grid");
c1 = new MenuItem("Red");
c2 = new MenuItem("Green");
c3 = new MenuItem("Random");
paperMenu.add(c1);
paperMenu.add(c2);
paperMenu.add(c3);
this.add(paperMenu);
c1.addActionListener(this);
c2.addActionListener(this);
c3.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == c1) {
boardConfig.setBoardGridColor(Color.RED);
} else if (e.getSource() == c2) {
boardConfig.setBoardGridColor(Color.GREEN);
} else if (e.getSource() == c3) {
boardConfig.setBoardGridColor(Color.BLUE);
}
}
}
We then need to update the Board (and Cell) to accept this change
public class Board extends Canvas {
private Cell[][] array;
private int rows;
private int cols;
private int size;
private Color gridColor = Color.BLACK;
public Board(int rows, int cols, int size) {
this.rows = rows;
this.cols = cols;
this.size = size;
array = new Cell[rows][cols];
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(cols * size, rows * size);
}
public Color getGridColor() {
return gridColor;
}
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
repaint();
}
public void draw(Graphics g) {
for (Cell[] row : array) {
for (Cell cell : row) {
cell.paint(g, getGridColor());
}
}
}
public Cell getCell(int r, int c) {
return array[r][c];
}
public void paint(Graphics g) {
super.paint(g);
draw(g);
}
}
public class Cell {
private final int x;
private final int y;
private final int size;
public Cell(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
}
public void paint(Graphics g, Color gridColor) {
g.setColor(gridColor);
g.drawRect(x, y, size, size);
}
}
note: Cell is making use of dependency injection here, as it really doesn't need to store the color AGAIN. It's also possible that the size could be passed this way, but, it might be useful for determine if a user clicked this cell or not
Then GUI needs to implement BoardConfigurable...
public class GUI extends Container implements BoardConfigurable {
private Board board;
public GUI() {
setLayout(new BorderLayout());
board = new Board(3, 3, 50);
add(board);
}
#Override
public void setBoardGridColor(Color color) {
board.setGridColor(color);
}
}
And we can update build and run the UI...
GUI gui = new GUI();
MyMenu menu = new MyMenu(gui);
Frame frame = new Frame();
frame.add(gui);
frame.setMenuBar(menu);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
An important skill to build is always questioning, "does this really need access to everything I'm passing?", "what will happen if I want to change the underlying implementation? How much will I need to change to achieve it?"
These will help you drive your designs and help build more flexible and decoupled code.
You might also want to become fairmular with the model-view-controller concept
Runnable example...
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
GUI gui = new GUI();
MyMenu menu = new MyMenu(gui);
Frame frame = new Frame();
frame.add(gui);
frame.setMenuBar(menu);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public interface BoardConfigurable {
public void setBoardGridColor(Color color);
}
public class GUI extends Container implements BoardConfigurable {
private Board board;
public GUI() {
setLayout(new BorderLayout());
board = new Board(3, 3, 50);
add(board);
}
#Override
public void setBoardGridColor(Color color) {
board.setGridColor(color);
}
}
public class MyMenu
extends MenuBar
implements ActionListener {
Menu paperMenu;
MenuItem c1, c2, c3;
BoardConfigurable boardConfig;
Cell cell;
public MyMenu(BoardConfigurable boardConfig) {
this.boardConfig = boardConfig;
this.cell = cell;
paperMenu = new Menu("Grid");
c1 = new MenuItem("Red");
c2 = new MenuItem("Green");
c3 = new MenuItem("Random");
paperMenu.add(c1);
paperMenu.add(c2);
paperMenu.add(c3);
this.add(paperMenu);
c1.addActionListener(this);
c2.addActionListener(this);
c3.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == c1) {
boardConfig.setBoardGridColor(Color.RED);
} else if (e.getSource() == c2) {
boardConfig.setBoardGridColor(Color.GREEN);
} else if (e.getSource() == c3) {
boardConfig.setBoardGridColor(Color.BLUE);
}
}
}
public class Board extends Canvas {
private Cell[][] array;
private int rows;
private int cols;
private int size;
private Color gridColor = Color.BLACK;
public Board(int rows, int cols, int size) {
this.rows = rows;
this.cols = cols;
this.size = size;
array = new Cell[rows][cols];
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(cols * size, rows * size);
}
public Color getGridColor() {
return gridColor;
}
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
repaint();
}
public void draw(Graphics g) {
for (Cell[] row : array) {
for (Cell cell : row) {
cell.paint(g, getGridColor());
}
}
}
public Cell getCell(int r, int c) {
return array[r][c];
}
public void paint(Graphics g) {
super.paint(g);
draw(g);
}
}
public class Cell {
private final int x;
private final int y;
private final int size;
public Cell(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
}
public void paint(Graphics g, Color gridColor) {
g.setColor(gridColor);
g.drawRect(x, y, size, size);
}
}
}
I was created some program for my school that should contains n*n buttons.
The buttons should be in Matrix layout with n rows and n cols.
So i created the panel, and I created a class named Position that extends JButtons - the buttons I want to add to the panel.
I added layout to the panel:
this.setLayout(new GridLayout(n,n));
And then I am creating n*n Positions buttons and adding them to the panel.
The problem is, that all the buttons are adding to the same place (top left of the screen) - even that I can click them in the places they should be! (see screen shot where n is 4)
I can click on the grey area (empty) even the button is not there:]1
The panel constructor:
public GamePanel(int n) {
super();
this.n = n;
positions = new Position[n][n];
this.setLayout(new GridLayout(n,n));
currX = new Random().nextInt(n);
currY = new Random().nextInt(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
Position p = new Position(i, j);
this.add(p);
positions[i][j] = p;
}
}
The constructor of Position class:
public class Position extends JButton {
private int x;
private int y;
private boolean visited = false;
public Position(int x, int y) {
super("");
this.x = x;
this.y = y;
this.setPreferredSize(new Dimension(50,50));
}
The Frame:
public class Game extends JFrame {
private GamePanel gamePanel;
public Game(int n){
super();
gamePanel = new GamePanel(n);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
this.add(gamePanel,BorderLayout.CENTER);
this.add(new JTextField(),BorderLayout.NORTH);
this.pack();
this.setVisible(true);
}
}
Where can be my mistake?
So, after putting your incomplete example back together, I got...
Then I noticed the x/y properties in your Position buttons, which made me thing that you've probably included getX and getY methods, something like...
public class Position extends JButton {
private int x;
private int y;
private boolean visited = false;
public Position(int x, int y) {
super("");
this.x = x;
this.y = y;
this.setPreferredSize(new Dimension(50, 50));
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Which generated...
So the answer is, include a fully runnable example which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses
And don't override getX and getY of the JButton, instead, change the methods to something like getGridX and getGridY
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.
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);
}