Checking vertically and horizontally for a specific JButton? - java

So, im working on my slide puzzel game, which have 16 JButtons in a gridlayout. 15 of them have a number 1-15 and the last one is empty. I have now written the code for the gui and everything except the public void actionPerformed(ActionEvent e). This is how it looks:(the gui)
http://i.stack.imgur.com/rbTt6.jpg
(Sorry for not posting picture here, I cannot do that since I dont have enough reputation)
For example, when i click the "4" button, it should change like it did in the picture to the right. To change this, I know how to, but to check horizontally and vertically if the "empty button" is next to it I have no idea how to. Ive tried to google it, but I havnt found anything to help me. How should I do this? I am not asking for you guys to write code for me, no, I am asking how should I tackle this problem?
THank you

Steps to follow:
Find the index of empty cell
Find the index of current clicked cell
Get left, right, top and bottom index of current clicked cell
Put a logic to validate a logical move
if (emptyIndex == left || emptyIndex == right || emptyIndex == top
|| emptyIndex == bottom) {
JButton emptyBtn = btns.get(emptyIndex);
emptyBtn.setText(btn.getText());
btn.setText("");
}
Swap the text of empty and current clicked cell if its a valid move
That' all
Here is a code for you.
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Puzzle {
private static List<JButton> btns = new ArrayList<JButton>();
static class MyButtonActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
int emptyIndex = -1;
int currentInex = -1;
for (int i = 0; i < btns.size(); i++) {
if (btns.get(i).getText().equals("")) {
emptyIndex = i;
} else if (btns.get(i).getText().equals(btn.getText())) {
currentInex = i;
}
}
int left = currentInex - 1;
int right = currentInex + 1;
int top = currentInex - 4;
int bottom = currentInex + 4;
if (emptyIndex == left || emptyIndex == right || emptyIndex == top
|| emptyIndex == bottom) {
JButton emptyBtn = btns.get(emptyIndex);
emptyBtn.setText(btn.getText());
btn.setText("");
}
}
}
public static void main(String[] a) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(4, 4));
for (int i = 0; i < 15; i++) {
JButton btn = new JButton(String.valueOf(i));
btn.addActionListener(new MyButtonActionListener());
btns.add(btn);
}
JButton empty = new JButton("");
empty.addActionListener(new MyButtonActionListener());
btns.add(empty);
Collections.shuffle(btns);
for (JButton btn : btns) {
panel.add(btn);
}
frame.setTitle("The 15 game");
frame.getContentPane().add(panel);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

Related

ordering image and text in jbutton

I am attempting to overlay the text on a JButton over an ImageIcon that is behind it. However, when the imageIcon is added, the text dissapears. Is there any way to specify the order in which it displays?
Below, i have tried to separately add the images and text to see if that would affect it, but no luck.
Can anyone help me out?
private void initButtons() {
int locationX = 0, locationY = 525;
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
boardArray[x][y] = new ChessButton();
boardArray[x][y].setSize(75, 75);
boardArray[x][y].setLocation(locationX, locationY);
boardArray[x][y].setXAndY(x, y);
if ((x % 2 == 0 && y % 2 == 1) || (x % 2 == 1 && y % 2 == 0)) {
boardArray[x][y].setColour("white");
boardArray[x][y].setIcon(new ImageIcon("Assets/white_null_null.png"));
} else {
boardArray[x][y].setColour("black");
boardArray[x][y].setIcon(new ImageIcon("Assets/black_null_null.png"));
}
//this adds the images in an alternating pattern
chessFrame.add(boardArray[x][y]);
locationX = locationX + 75;
}
locationX = 0;
locationY = locationY - 75;
}
}
void initPieces() {
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
if ((x % 2 == 0 && y % 2 == 1) || (x % 2 == 1 && y % 2 == 0)) {
boardArray[x][y].setFont(new Font("Arial Unicode MS", Font.PLAIN, 40));
boardArray[x][y].setText("\u2654");//sets a particular chess piece as text, just testing it now.
} else {
boardArray[x][y].setFont(new Font("Arial Unicode MS", Font.PLAIN, 40));
boardArray[x][y].setText("\u2654");//sets a particular chess piece as text, just testing it now.
//this is suposed to overlay the image over the text, but it is not.
}
}
}
}
First of all, I see you're calling this method: boardArray[x][y].setLocation(locationX, locationY);
.setLocation(...) indicates you're using a null layout, please read Null layout is evil and Why is it frowned upon to use a null layout in Swing? to know why you should avoid its use.
For creating a Chess board, I'd be using GridLayout, please read how to use the different layout managers
Now, to overlay text over the icon, you only need to call JButton#setHorizontalAlignment(...) method and pass SwingConstants.CENTER as the parameter.
For example:
import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class ButtonWithImageAndText {
private JFrame frame;
private JButton button;
private Icon icon;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new ButtonWithImageAndText().createAndShowGui());
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
try {
icon = new ImageIcon(ImageIO.read(getClass().getResource("up.jpg")));
} catch (IOException e) {
e.printStackTrace();
}
button = new JButton();
button.setIcon(icon);
button.setText("Click me!");
button.setHorizontalTextPosition(SwingConstants.CENTER);
button.setFont(new Font("Arial", Font.PLAIN, 40));
button.setForeground(Color.RED);
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
Which gives the following output:
For your future questions, please read how to make a valid Minimal, Complete and Verifiable Example (MCVE) that demonstrates your issue and your best try to solve it yourself, the code I posted is a good example of it, as you can copy-paste it and see the same result as I
Use the setComponentZOrder(...) method of the Container class. This will enable you to set the Z-index of the components to set them in what ever order you like. Look also this

Building my first GUI(JPanel) for my program and having such a hard time. GUI works but not with my Program

Ok. So I'm supposed to build a GUI for my connect 4 program. (Please excuse the chunks of code here and there) I have shortened this program for your reading and I have excluded some code that doesn't have issues. I'm trying to get my JPanel down to the Connect4(). How can I access public TestPane() so I can update the GUI from Connect4().
I am not allowed to use anything Static.
LINE 153 WAS WHERE I WAS GOING TO ATTEMPT TO UPDATE THE GUI
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;
import java.awt.event.ActionEvent;
import javax.swing.*;
import java.awt.GridLayout;
public class Connect4 extends JPanel{
public boolean col1 = false;
public int buttonPressed = 10;
public class TestPane extends JPanel{
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
for (int row = 0; row < 7; row++) {
for (int col = 0; col < 8; col++) {
//setBackground(Color.BLUE);
gbc.gridx = col;
gbc.gridy = row;
CellPane cellPane = new CellPane();
Border border = null;
if (row < 7) {
if (col < 8) {
border = new MatteBorder(1, 1, 1, 1, Color.BLACK);
} else {
border = new MatteBorder(1, 1, 1, 1, Color.BLACK);
}
} else {
if (col < 8) {
border = new MatteBorder(1, 1, 1, 1, Color.BLACK);
} else {
border = new MatteBorder(1, 1, 1, 1, Color.BLACK);
}
}
cellPane.setBorder(border);
add(cellPane, gbc);
}
//JUST TO TEST THAT THE SQUARES ARE WORKING. THEY ARE BUT NOT WITH MY PROGRAM
gbc.gridx = 3;
gbc.gridy = 2;
CellPane cellPaneP1 = new CellPane();
cellPaneP1.setBackground(Color.BLUE);
add(cellPaneP1,gbc);
gbc.gridx = 5;
gbc.gridy = 4;
CellPane cellPaneP2 = new CellPane();
cellPaneP2.setBackground(Color.RED);
add(cellPaneP2,gbc);
}
}
}
public Connect4(){
JOptionPane.showMessageDialog(null, "Welcome to Connect Four\nThis game will require 2 players\nPlease Enter your names");
Player p1 = new Player();
Player p2 = new Player();
String p1Name = JOptionPane.showInputDialog("Enter your name Player 1");
p1.setName(p1Name);
String p2Name = JOptionPane.showInputDialog("Enter your name Player 2");
p2.setName(p2Name);
JOptionPane.showMessageDialog(null,p1.getName()+ " vs " + p2.getName()+". \nThis is going to be EPIC!!!");
System.out.println(p1.getName()+ " vs " + p2.getName()+". \nThis is going to be EPIC!!!");
int winner =0;
//Create Our board
Board con4Bor= new Board();
//con4Bor.setSize(7,8);]
//Fill our board with '_' to represent empty spaces
con4Bor.fillBoard();
//Randomly Select Player to go first
int i = 0;
int p1p2 = (int)(Math.random()*2+1);
if(p1p2 == 1)
System.out.println(p1.getName() + " was selected at random to go first");
else
System.out.println(p2.getName() + " was selected at random to go first");
JButton column1 = new JButton(new AbstractAction("Column 1"){
#Override
public void actionPerformed(ActionEvent a){
buttonPressed = 1;
}
});
while(winner == 0){
if(p1p2 == 3){
p1p2--;
}
con4Bor.printOutBoard();
//printDiag(c4b);
int playerSelection = 10;
//System.out.println(p1p2);
if(p1p2 == 1){
System.out.println(p1.getName()+": it is now your turn\nplease choose a column");
}
else{
System.out.println(p2.getName()+": it is now your turn\nplease choose a column");
}
System.out.println("Which Column do you want to insert? Column 1, 2, 3, 4, 5, 6, 7 or 8?");
playerSelection = 1;
while(playerSelection != 1 && buttonPressed != 2 && buttonPressed != 3 && buttonPressed != 4 && buttonPressed != 5 && buttonPressed != 6 && buttonPressed != 7 && buttonPressed != 8){
System.out.println(buttonPressed);
playerSelection = 1;//buttonPressed;
}
if(playerSelection == 1){
********************************************************************************
********************************************************************************
***This is where I was poorly attempting to update my GUI if someone selected column 1 ***
********************************************************************************
********************************************************************************
i = 0;
con4Bor.insertCol(i, playerSelection-1, p1p2);
}
//WINNER DETECTION
if(p1p2 == 1){
if(con4Bor.weHaveAHorizontalWinner() == true || con4Bor.weHaveAVeritcalWinner() == true || con4Bor.weHaveADiagonalWinner()==true){
con4Bor.printOutBoard();
System.out.println(p1.getName()+" Wins!!!");
winner++;
}else{
p1p2 =3;
}
}
if(p1p2 == 2){
if(con4Bor.weHaveAHorizontalWinner() == true || con4Bor.weHaveAVeritcalWinner() == true || con4Bor.weHaveADiagonalWinner()==true){
con4Bor.printOutBoard();
System.out.println(p2.getName()+" Wins!!!");
winner++;
}else{
p1p2--;
}
}
}
}
public class CellPane extends JPanel {
private Color defaultBackground;
public CellPane() {
defaultBackground = getBackground();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
}
public static void main (String [] args){
new tester();
}
}
Try repaint() + revalidate() on JPanel after you added/removed/changed any element on it. Also read about MVC and best practices when creating desktop JAVA app.

Java checkerboard, odd/even % 2 panel

I have successfully got a checkerboard to be put together using colored panels, but only when the user will input odd numbers for the rows and columns. Otherwise when inputing even numbers it just shows alternating colored columns. I'm struggling to figure out how to write a short segment that checks to see if it's odd or even by using the %2=0, with the result of even changing the color. Below is my code. Thanks, and take it easy on me I'm very new to programming! :-)
Also, I've created a separate ColorPanel class to build the colored panel, and then pull into into my main program. I didn't bother putting that code below.
import javax.swing.*;
import java.awt.*;
public class Checkerboard extends JPanel{
public static void main(String[] args) {
JFrame chBoard = new JFrame();
chBoard.setTitle("Checkerboard");
chBoard.setSize(800,800);
chBoard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String inputStr = JOptionPane.showInputDialog("Number of rows", "5");
if (inputStr == null) return;
int row = Integer.parseInt(inputStr);
inputStr = JOptionPane.showInputDialog("Number of columns", "5");
if (inputStr == null) return;
int col = Integer.parseInt(inputStr);
Container pane = chBoard.getContentPane();
pane.setLayout(new GridLayout(row, col));
Color BoxColor = Color.red;
for ( int counter = 1; counter <= row * col; counter++ )
{
if (BoxColor == Color.red)
BoxColor = Color.black;
else
BoxColor = Color.red;
ColorPanel panel = new ColorPanel(BoxColor);
pane.add(panel);
}
chBoard.setVisible(true);
}
}
Change your loop to:
for ( int x = 0; x < row; x++ ) {
for(int y = 0; y < col; y++) {
if((x + y)%2 == 0) {
BoxColor = Color.red;
} else {
BoxColor = Color.black;
}
...
}
}
Like I said, I'm new to programming but I'm really enjoying the learning experience. I hope this helps other people in their learning experience.
Anyways, I suppose I created more work for myself with the separate ColorPanel class. So instead of creating a separate ColorPanel class to build the colored panel, I just changed it to use the preexisting JPanel class to create the panel inside the main program. So instead of:
ColorPanel panel = new ColorPanel(BoxColor);
+ the ColorPanel class...
I put:
JPanel panel = new JPanel();
panel.setBackground(BoxColor);
within the main program and deleted the additional ColorPanel class.
Sorry for the redundancy, just wanting to explain myself clearly.
Also, thanks to Jason he really helped me figure out the idea of using the two
int x & y
to count the
row & col
and then add them together which enabled me to use the
%2=0
to figure out whether I was on the odd or even panel.
Hope this helps someone! :-)
Final code looks like this:
import javax.swing.*;
import java.awt.*;
public class Checkerboard extends JPanel{
public static void main(String[] args) {
JFrame chBoard = new JFrame();
chBoard.setTitle("Checkerboard");
chBoard.setSize(800,800);
chBoard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String inputStr = JOptionPane.showInputDialog("Number of rows", "5");
if (inputStr == null) return;
int row = Integer.parseInt(inputStr);
inputStr = JOptionPane.showInputDialog("Number of columns", "5");
if (inputStr == null) return;
int col = Integer.parseInt(inputStr);
Container pane = chBoard.getContentPane();
pane.setLayout(new GridLayout(row, col));
Color BoxColor = Color.red;
for ( int x = 0; x < row; x++ ) {
for(int y = 0; y < col; y++) {
if((x + y)%2 == 0) {
BoxColor = Color.red;}
else{
BoxColor = Color.black;}
JPanel panel = new JPanel();
panel.setBackground(BoxColor);
pane.add(panel);
}
chBoard.setVisible(true);
}
}
}

Changing colors of GridLayout elements

Note: this question may look a bit like another I've posted a few weeks ago. Back then I was not working with adding the buttons as arrays, thats what makes it more difficult for me this time.
I'm working with a chessgame, and I have been able to set up a board of 64 squares on my own. However it seems to be a little too complicated for me to manage adding the colors to the squares.
My code looks like this:
Chess.java
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Chess implements config {
public static void main(String[] args) {
int[] squareArray;
squareArray = new int[65];
int i = 1;
JFrame frame = new JFrame("Chessboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(ROWS, COLS, 2, 2));
for (i = 1; i < 65; i++) {
squareArray[i] = i;
frame.add(new JButton("" + squareArray[i]));
}
frame.setSize(800, 800);
frame.setVisible(true);
}
}
Piece.java
import java.awt.Color;
import javax.swing.JFrame;
public class Piece extends JFrame implements config {
public Piece (int n) {
setBackground(calcColor(n));
}
public void Pieces() {
new Pieces();
//This class contains nothing at the moment.
}
Color calcColor(int n) {
boolean everysecondSquare = (n % 2 == 0);
boolean everysecondRow = ((n / ROWS) % 2 == 0);
return (everysecondSquare != everysecondRow ? P1Color : P2Color);
}
}
config.java
import java.awt.Color;
public interface config {
public int ROWS = 8;
public int COLS = 8;
Color P1Color = (new Color(245,222,179));
Color P2Color = (new Color(244,164,96));
}
I'm very aware that this probably is pretty bad coded as I am very new to Java. I would be very happy and thankful if someone could help me out with the colors here as I have been stuck for several days now without getting any further. I don't expect someone to finish the code for me, but merely help me on the way to get there. :)
What about this?
for (i = 1; i < 65; i++) {
squareArray[i] = i;
JButton b=new JButton("" + squareArray[i]);
b.setBackground(desiredColorHere);
frame.add(b);
}

Points not being properly read by MouseListener

I'm having a problem where I can't properly access my instance Point data.
I create an multi-dimensional array of GridPanels, and instantiate each with a Point.
When first created, everything works as expected.
pic1 http://img.skitch.com/20100218-fciwr7t73ci2gajafmfxa2yf9q.jpg
When I click on a GridPanel however, the Listener class always receives the Point from the last GridPanel that was created ( (3, 3) in this case.)
When I pass an int instead of a Point however, the int for the GridPanel that was clicked is shown (like you'd expect).
Anyone know what's going on here?
Thanks
import javax.swing.JFrame;
/**
* Driver class.
*/
public class Test {
/**
* The main method.
* #param args Command line arguments.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("TEST");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel panel = new TestPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
import java.awt.GridLayout;
import java.awt.Point;
import javax.swing.JPanel;
/**
* Creates a 4 by 4 grid of GridPanels.
*/
public class TestPanel extends JPanel {
static final int ROW_SIZE = 4;
static final int COL_SIZE = 4;
private GridPanel[][] g = new GridPanel[ROW_SIZE][COL_SIZE];
public TestPanel() {
Point coords = new Point();
setLayout(new GridLayout(ROW_SIZE, COL_SIZE));
for (int i = 0; i < ROW_SIZE; i++) {
for (int j = 0; j < COL_SIZE; j++) {
coords.setLocation(i, j);
g[i][j] = new GridPanel(coords);
add(g[i][j]);
}
}
}
}
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* Contains the MouseListener.
*/
public class GridPanel extends JPanel {
private JLabel label;
private Point p;
public GridPanel(Point p) {
this.p = p;
label = new JLabel("" + p);
add(label);
setBackground(Color.WHITE);
setPreferredSize(new Dimension(200, 50));
addMouseListener(new SelectListener());
}
private class SelectListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
label.setText("" + p);
}
}
}
The problem is that you are re-using the same point, stored in coords. You need to create a new point for each grid element. It looks to you as if each panel has a different point value stored in it because each panel has a different label. But in the line
label = new JLabel("" + p);
you are creating a String that contains the current value of p. But p can change later, and the label won't change with it.
So the easiest fix for your problem is to change the line
this.p = p;
to
this.p = new Point(p); // Create a defensive copy.
It looks like you may be currently somewhat confused about the difference between objects and fields. For example,
Point p = new Point(3, 4);
Point p2 = p;
p.x = 7;
System.out.println(p2.x);
will yield 7, as there is only one point being manipulated, though it's pointed to by two fields. Using = doesn't create a copy of the point.
(Apologies if I'm explaining things you already know!)
The point is and object so it is passed by reference. This means all your panels reference the same Point. Since you are changing the location on it all the time - the last will be shown.
You have to create new Point every time in the loop:
public TestPanel() {
setLayout(new GridLayout(ROW_SIZE, COL_SIZE));
for (int i = 0; i < ROW_SIZE; i++) {
for (int j = 0; j < COL_SIZE; j++) {
g[i][j] = new GridPanel(new Point(i, j));
add(g[i][j]);
}
}
}
i change setPreferredSize(new Dimension(w, h)); this is done.
but in my program i need change my frame size every time. so how can fit gridpanel in that case.... if frame size (1200,800) or (1170,920) i am not using JLabel here.
thankyou for answering
in place of this frame.pack(); i use frame.setSize(W,H);
in a gridpanel add
setPreferredSize(new Dimension(x,y));
setBorder(BorderFactory.createLineBorder(Color.red));
i remove JLabel
where x = w / col_size; y = h / row_size;
now when i run Test.java grid are not fitted in my frame;

Categories

Resources