I am trying to make a method that disables JButtons.
The JButtons are in an array in the form of a grid, JButton [int][int] and the integers are supposed to be coordinates.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.*;
public class BS {
public static JFrame f = new JFrame("BS");
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
initializeGui();
}
});
}
static void initializeGui() {
JPanel gui = new JPanel(new BorderLayout(3,1));
//This is the array of the JButtons in the form of a grid
final JButton[][] coordinates = new JButton[15][15];
JPanel field;
// set up the main GUI
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
field = new JPanel(new GridLayout(0, 15));
field.setBorder(new CompoundBorder(new EmptyBorder(15,15,15,15),new LineBorder(Color.BLACK)));
JPanel boardConstrain = new JPanel(new GridBagLayout());
boardConstrain.add(field);
gui.add(boardConstrain);
//The making of the grid
for (int ii = 0; ii < coordinates.length; ii++) {
for (int jj = 0; jj < coordinates[ii].length; jj++) {
JButton b = new JButton();
ImageIcon icon = new ImageIcon(
new BufferedImage(30, 30, BufferedImage.TYPE_INT_ARGB));
b.setIcon(icon);
coordinates[jj][ii] = b;
field.add(coordinates[jj][ii]);
}
}
f.add(gui);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
}
I did some changes in your code:
public static JFrame f = new JFrame("BS"); JFrame shouldn't be static and should have a more meaningful name (like frame for example).
final JButton[][] coordinates = new JButton[15][15]; moved this array as a class member and made it non final and also changed the name to buttons as it's easier to know what it is (coordinates to me, sounds more like an array of Point or int)
After that I added an ActionListener, see How to use Actions tutorial.
private ActionListener listener = e -> {
//Loops through the whole array in both dimensions
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (e.getSource().equals(buttons[i][j])) { //Find the JButton that was clicked
if (isStartButton) { //startButton is a boolean variable that tells us if this is the first button clicked or not
startXCoord = i;
startYCoord = j;
} else {
endXCoord = i;
endYCoord = j;
disableButtons(); //Only when we have clicked twice we disable all the buttons in between
}
isStartButton = !isStartButton; //In every button click we change the value of this variable
break; //No need to keep looking if we found our clicked button. Add another one with a condition to skip the outer loop.
}
}
}
};
And a method called disableButtons() which disables all the buttons between the 2 clicked buttons:
private void disableButtons() {
compareCoords(); //This method checks if first button clicked is after 2nd one.
for (int i = startXCoord; i <= endXCoord; i++) {
for (int j = startYCoord; j <= endYCoord; j++) {
buttons[i][j].setEnabled(false); //We disable all buttons in between
}
}
}
At the end our code ends like this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class DisableButtonsInBetween {
private JFrame frame = new JFrame(getClass().getSimpleName());
private JButton[][] buttons;
private int startXCoord = -1;
private int startYCoord = -1;
private int endXCoord = -1;
private int endYCoord = -1;
private boolean isStartButton = true;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DisableButtonsInBetween().initializeGui();
}
});
}
void initializeGui() {
JPanel gui = new JPanel(new BorderLayout(3, 1));
// This is the array of the JButtons in the form of a grid
JPanel pane;
buttons = new JButton[15][15];
// set up the main GUI
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
pane = new JPanel(new GridLayout(0, 15));
pane.setBorder(new CompoundBorder(new EmptyBorder(15, 15, 15, 15), new LineBorder(Color.BLACK)));
JPanel boardConstrain = new JPanel(new GridBagLayout());
boardConstrain.add(pane);
gui.add(boardConstrain);
// The making of the grid
for (int ii = 0; ii < buttons.length; ii++) {
for (int jj = 0; jj < buttons[ii].length; jj++) {
buttons[jj][ii] = new JButton();
ImageIcon icon = new ImageIcon(new BufferedImage(30, 30, BufferedImage.TYPE_INT_ARGB));
buttons[jj][ii].setIcon(icon);
buttons[jj][ii].addActionListener(listener);
pane.add(buttons[jj][ii]);
}
}
frame.add(gui);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
}
//The ActionListener is what gets called when you click a JButton
private ActionListener listener = e -> {
//These for loops are done to identify which button was clicked.
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (e.getSource().equals(buttons[i][j])) {
if (isStartButton) {
//We save the coords of the 1st button clicked
startXCoord = i;
startYCoord = j;
} else {
//We save the coords of the 2nd button clicked and call the disableButtons method
endXCoord = i;
endYCoord = j;
disableButtons();
}
isStartButton = !isStartButton;
break;
}
}
}
};
//This method disables all the buttons between the 2 that were clicked
private void disableButtons() {
compareCoords();
for (int i = startXCoord; i <= endXCoord; i++) {
for (int j = startYCoord; j <= endYCoord; j++) {
buttons[i][j].setEnabled(false);
}
}
}
//This method compares the coords if the 2nd button was before (in its coords) than the 1st one it switched their coords
private void compareCoords() {
if (endXCoord < startXCoord) {
int aux = startXCoord;
startXCoord = endXCoord;
endXCoord = aux;
}
if (endYCoord < startYCoord) {
int aux = startYCoord;
startYCoord = endYCoord;
endYCoord = aux;
}
}
}
I hope this is what you were trying to do... if not please clarify.
I do not have the arrow operator, " -> ". I think it requires a higher Java. Is there a way to replace this?
For Java 7 and lower use this for the ActionListener:
private ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (e.getSource().equals(buttons[i][j])) {
if (isStartButton) {
startXCoord = i;
startYCoord = j;
} else {
endXCoord = i;
endYCoord = j;
disableButtons();
}
isStartButton = !isStartButton;
break;
}
}
}
}
};
Related
I am new to java and am very confused about errors in my code. I have the error at line 48 "local variables referenced from an inner class must be final or effectively final". here is my code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MemoryGame extends JFrame
{
private JButton[][] buttons = new JButton[4][4];
private Color[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW};
private List<Color> colorList = new ArrayList<>();
private int score = 0;
public MemoryGame()
{
setTitle("Memory Game");
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(4, 4));
// populate colorList with two copies of each color
for (int i = 0; i < 2; i++)
{
for (Color color : colors)
{
colorList.add(color);
}
}
// shuffle colorList
Collections.shuffle(colorList);
int index = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
JButton button = new JButton();
button.setBackground(Color.GRAY);
buttons[i][j] = button;
add(button);
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
final int currentIndex = index;
JButton clickedButton = (JButton) e.getSource();
Color color = colorList.get(currentIndex);
clickedButton.setBackground(color);
clickedButton.setEnabled(false);
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 4; y++)
{
if (buttons[x][y].getBackground() == color && buttons[x][y] != clickedButton)
{
buttons[x][y].setEnabled(false);
score++;
if (score == 8)
{
JOptionPane.showMessageDialog(MemoryGame.this, "You won!");
System.exit(0);
}
}
}
}
}
});
index++;
}
}
setVisible(true);
}
public static void main(String[] args)
{
new MemoryGame();
}
}
I've tried different things to solve the error and they just result in more errors. the program is meant to have a grid of different squares that can be clicked on to display their colors and matched by the user. when the user matches all of the colors on the grid they win.
The problem is with final int currentIndex = index; as the compiler was telling you in the error message. actionPerformed will run at some unspecified future time and the compiler has no idea what value of index you expect to find there at that time.
What do you want to do? Assign colors to buttons. You can do that more directly with
JButton button = new JButton();
button.setBackground(Color.GRAY);
buttons[i][j] = button;
// let's store the color for later
button.putClientProperty("color", colorList.get(index));
add(button);
outside the handler.
And then retrieving it inside:
public void actionPerformed(ActionEvent e)
{
JButton clickedButton = (JButton) e.getSource();
Color color = (Color)clickedButton.getClientProperty("color");
my code is tic tac toe and i have problem with show winner.
i get winner but not when X or O in correct direction.
and show winner after click on button.
code :
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.border.EtchedBorder;
public class TicTocToe extends JFrame implements ActionListener {
private static final long serialVersionUID = -7730552764304282715L;
private static final Font BT_FONT = new Font("Segoe UI", 0, 30);
private static final Font LB_FONT = new Font("Consolas", 0, 20);
private JButton[][] board;
private JLabel statusBar;
private JPanel centerPanel, southPanel;
private int turn = 0, count = 0;
private String name;
public static void main(String[] args) {
EventQueue.invokeLater(() -> new TicTocToe().setVisible(true));
}
public TicTocToe() {
super("Tic Toc Toe");
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
initUI();
} catch (Exception e) {
e.printStackTrace();
}
}
private void initUI() {
initCenterPanel();
initSouthPanel();
add(centerPanel);
add(southPanel, BorderLayout.SOUTH);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
}
private void initCenterPanel() {
centerPanel = new JPanel();
board = new JButton[3][3];
for (int i = 0; i < board[0].length; i++) {
for (int j = 0; j < board[i].length; j++) {
board[i][j] = new JButton("-");
board[i][j].setFont(BT_FONT);
board[i][j].setFocusPainted(false);
board[i][j].setPreferredSize(new Dimension(80, 80));
board[i][j].addActionListener(this);
centerPanel.add(board[i][j]);
}
}
}
private void initSouthPanel() {
southPanel = new JPanel();
southPanel.setLayout(new BorderLayout());
statusBar = new JLabel();
statusBar.setFont(LB_FONT);
statusBar.setText("Click On Button To Start");
statusBar.setHorizontalAlignment(JLabel.CENTER);
statusBar.setBorder(new EtchedBorder());
southPanel.add(statusBar);
}
private void play(JButton button) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (button.equals(board[i][j])) {
count++;
if (turn < 1) {
statusBar.setText("Player " + "O" + " Turn");
button.setText("X");
button.setEnabled(false);
turn++;
} else {
statusBar.setText("Player " + "X" + " Turn");
button.setText("O");
button.setEnabled(false);
turn--;
}
}
}
}
}
private String getPlayerName() {
return (turn < 1) ? "X" : "O";
}
private boolean findWinner() {
name = getPlayerName();
for (int i = 0; i < board.length; i++) {
if (board[i][0].getText().equals(name) && board[i][1].getText().equals(name)
&& board[i][2].getText().equals(name))
return true;
for (int j = 0; j < board[i].length; j++) {
if (board[0][j].getText().equals(name) && board[1][j].getText().equals(name)
&& board[2][j].getText().equals(name))
return true;
if (board[0][0].getText().equals(name) && board[1][1].getText().equals(name)
&& board[2][2].getText().equals(name))
return true;
if (board[0][2].getText().equals(name) && board[1][1].getText().equals(name)
&& board[2][0].getText().equals(name))
return true;
}
}
return false;
}
private void showWinner() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
if (findWinner()) {
if (getPlayerName().equalsIgnoreCase("x")) {
statusBar.setText("Winner is Player X");
board[i][j].removeActionListener(this);
}
else if (getPlayerName().equalsIgnoreCase("o")) {
statusBar.setText("Winner is Player O");
board[i][j].removeActionListener(this);
}
} else if (!findWinner() && count == 9) {
statusBar.setText("It was a draw, no wone.");
board[i][j].removeActionListener(this);
}
}
}
}
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
play(button);
showWinner();
}
public Dimension getPreferredSize() {
return new Dimension(300, 320);
}
public Dimension getMinimumSize() {
return getPreferredSize();
}
}
in this image Winner is X but wait for Player O
and after click on other button show Winner.
i need show winner when X or O in correct Direction
and no wait for click on other button
I think I see it.
When a button is pressed, you do stuff in this order:
change the status bar to say it's the next player's turn
set the relevant button text to show the player who just picked that button
disable the button
change the turn value to reflect the next player
check for a winner, based on the current player's name but you have already changed this to the next player, not the player who just made the move.
When X makes a winning move, the current player name is changed to O before the game checks for a winner, so it checks to see if O has won. You need to reorder stuff:
change the button text
disable the button
check for a winner based on the current player name, end the game if the current player has won or if there is a draw
if the game is still going, now is the time to change the turn value and update the status bar to show that it's the next player's turn.
We are learning in school java graphic and now we have to build a game called Kakurasu (https://www.brainbashers.com/showkakurasu.asp)
I'm so stuck and I don't know how to do it.
As far as I came. I've done a frame with a panel inside a panel which has 7x7 buttons that change from 0 to 1 and from white to green when pressed. The idea is that I make the first raw on the top and on the left to be the numbers 1-5 and then on the bottom and right side the random generated numbers.
This is my first code:
import javax.swing.*;
import java.awt.*;
public class Start {
public static JButton[][] gumbi;
public static void main(String[] args) {
buttons = new JButton[7][7];
JFrame window = new JFrame("Kakurasu");
JPanel panel = new JPanel(new BorderLayout());
JPanel playingField = new JPanel(new GridLayout(7, 7));
Listner1 p = new Listner1(buttons);
panel.add(playingField, BorderLayout.CENTER);
window.add(panel);
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
buttons[i][j] = new JButton("0");
playingField.add(buttons[i][j], BorderLayout.CENTER);
buttons[i][j].addActionListener(p);
buttons[i][j].setBackground(Color.WHITE);
}
}
window.setVisible(true);
window.setSize(500, 500);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
This is my second code:
import javax.swing.*;
import java.awt.*;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Poslusalec1 implements ActionListener {
public JButton[][] buttons;
public Listner1(JButton[][] gumbi) {
this.buttons = buttons;
}
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
String tmp = button.getText();
int n = Integer.parseInt(tmp);
n += 1;
if (n == 2) {
n = 0;
}
button.setText("" + n);
if (button.getBackground() == Color.WHITE) {
button.setBackground(Color.GREEN);
} else {
button.setBackground(Color.WHITE);
}
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (button == buttons[i][j]) {
System.out.println(i + ", " + j);
}
}
}
}
}
Is it possible to assign different actionlisteners to different buttons inside a gridlayout?
Thanks for any help.
I'm so stuck and I don't know how to do it.
To solve any computer problem, you break the problem down into smaller and smaller problems, until you're comfortable that you can code each small problem.
Generally, when coding a GUI, you should use the model / view / controller pattern.
In Java Swing, this means:
The view may read values from the model.
The view may not update the model.
The controller updates the model.
The controller repaints / revalidates the view.
So, let's create a model for a JButton. The model will hold the across value of the JButton, the down value of the JButton, and the background color of the JButton.
package com.ggl.testing;
import java.awt.Color;
public class KakurasuCell {
private final int acrossValue;
private final int downValue;
private Color backgroundColor;
public KakurasuCell(int acrossValue, int downValue, Color backgroundColor) {
this.acrossValue = acrossValue;
this.downValue = downValue;
this.backgroundColor = backgroundColor;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(Color backgroundColor) {
this.backgroundColor = backgroundColor;
}
public int getAcrossValue() {
return acrossValue;
}
public int getDownValue() {
return downValue;
}
}
This is a Java object. It holds multiple types of values.
Now, we create another model for a grid of JButtons. You should recognize this from your code.
package com.ggl.testing;
import java.awt.Color;
public class KakurasuGrid {
private int gridWidth;
private KakurasuCell[][] cells;
public KakurasuGrid(int gridWidth) {
setGridWidth(gridWidth);
}
public int getGridWidth() {
return gridWidth;
}
public void setGridWidth(int gridWidth) {
this.gridWidth = gridWidth;
this.cells = new KakurasuCell[gridWidth][gridWidth];
setCells();
}
public KakurasuCell[][] getCells() {
return cells;
}
private void setCells() {
for (int i = 0; i < gridWidth; i++) {
for (int j = 0; j < gridWidth; j++) {
KakurasuCell cell = new KakurasuCell((j + 1), (i + 1),
Color.GRAY);
cells[i][j] = cell;
}
}
}
}
This should be enough to get you started. You still need to create the answers, create the GUI, and add the controller methods.
I created a Class that extends from JFrame which has a table of buttons. In the class constructor I added the buttons to the panel but when I run the main nothing happens and I see only an empty frame. So can you hep me to find the problem?
This is the code:
public class Tita extends JFrame {
JButton ff[][] = new JButton[3][3];
int i = 0, j = 0;
public static void main(String[] args) {
Tita oo = new Tita();
}
public Tita() {
super("Newframe");
setVisible(true);
for(i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
ff[i][j].setText("sss");
this.getContentPane().add(ff[i][i]);
}
}
}
What is happening is that you haven't initialized any JButton, also, when you add the button you have getContentPane().add(ff[i][i]);, when it should be getContentPane().add(ff[i][j]);
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Tita extends JFrame {
JButton ff[][] = new JButton[3][3];
int i = 0, j = 0;
public static void main(String[] args) {
Tita oo = new Tita();
}
public Tita() {
super("Newframe");
setVisible(true);
setLocationRelativeTo(null);
setSize(new Dimension(300, 400));
setLayout(new GridLayout(3, 0));
for(i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
ff[i][j] = new JButton("SSS");
ff[i][j].setSize(30, 10);
getContentPane().add(ff[i][j],i);
}
}
}
}
I added listeners to my JButtons for the popup menu but when the popup menu appears the JButtons disappear and I would need to hover my cursor on the buttons to make them appear again. Why is it like this?
(all the methods here are in the same class)
public Inventory() {
setLayout(null);
setBounds(0, 0, 175, 210);
initPopupMenu(); // this just sets what is inside the popup menu
int x;
// 30 buttons
for(x = 0; x < 30; x++) {
button[x] = new JButton();
add(button[x]);
button[x].addMouseListener(this);
}
x = 0;
// it's a grid of buttons
for(int i = 0; i < 5; i++)
for(int j = 0; j < 6; j++) {
button[x].setBounds(i*35+1,j*35+1, 33,33);
x++;
}
}
public void mouseClicked(MouseEvent e) {
for(int j = 0; j < 30; j++) // i tried this one but it still disappears
button[j].repaint();
for(int i = 0; i < 30; i++) {
if(e.getSource() == button[i]) {
System.out.println("You pressed Button "+i);
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
}
This is what happens,
Stop using null Layout, seems like that can be one of the issues regarding this. Your JFrame appears sort of BLACK to me, is this some THEME or a new LOOK AND FEEL you are using, that can be the cause of this thing too. Here check this out, it's working flawlessly here with this code :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonPopUp
{
private static final int SIZE = 30;
private JButton[] button = new JButton[SIZE];
private JPopupMenu popup = new JPopupMenu("Hello World");
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Button POP UP Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
final JPanel contentPane = new JPanel();
contentPane.setLayout(new GridLayout(0, 5));
JMenuItem menuItem1 = new JMenuItem("Menu Item 1");
JMenuItem menuItem2 = new JMenuItem("Menu Item 2");
//popup.add(greetings);
popup.insert(menuItem1, 0);
popup.insert(menuItem2, 1);
for (int i = 0; i < SIZE; i++)
{
button[i] = new JButton();
button[i].setBorder(BorderFactory.createEtchedBorder());
button[i].addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent me)
{
System.out.println("I am WORKING!!");
popup.show((JComponent)me.getSource(), me.getX(), me.getY());
}
});
contentPane.add(button[i]);
}
frame.getContentPane().add(contentPane);
frame.setSize(175, 250);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ButtonPopUp().createAndDisplayGUI();
}
});
}
}
Here is the output :