How to make buttons change on different click amounts java - java

I am trying to make a game in java where if you click on a button once it turns red, and if you click on it twice it turns blue, but I'm running into an issue where when I click one square once and it becomes red, if I click another once it turns blue, when I want the effect isolated to each square at a time(e.g. if I click one square once its red, click another twice its blue, and another square once its red). I also want it to reset after 3 clicks.
Here is my actions listener so far
JFrame frame = new JFrame(); //creates frame
JButton[][] grid; //names the grid of buttons
int clicked = 0;
public ButtonGrid(int width, int length) { //constructor
frame.setLayout(new GridLayout(width, length)); //set layout
grid = new JButton[width][length]; //allocate the size of grid
for(int y = 0; y < length; y++) {
for(int x = 0; x < width; x++) {
grid[x][y] = new JButton(); //creates a button
grid[x][y].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(clicked == 0) {
((JButton)e.getSource()).setBackground(Color.red);
clicked++;
} else if(clicked == 1) {
((JButton)e.getSource()).setBackground(Color.blue);
clicked++;
}
}
});
frame.add(grid[x][y]); //adds new button to grid
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack(); //sets appropriate size for frame
frame.setVisible(true); //makes frame visible
// ...
}

In your current implementation, clicked is a instance field of the parent class, which all your buttons/ActionListeners are using.
Instead, you need to isolate the property so that it can be better associated with a single button.
Now, you could create a custom class which extends from JButton, but IMHO, that's a little heavy handed and locks you into a single use case. Personally, I'd look towards implementating a concrete implementation of the ActionListener to provide this side effect.
For example...
public class CounterActionListener implements ActionListener {
private int counter;
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof JButton) {
JButton button = (JButton)source;
clicked++;
if(clicked == 0) {
button.setBackground(Color.red);
} else if(clicked == 1){
button.setBackground(Color.blue);
}
}
}
}
Then in your code, you just apply the listener to the button, for example...
grid[x][y] = new JButton(new CounterActionListener());
You could also follow this by making use of a "delegate", which actually performed the required operations, based on the number of clicks, which could be held in a model, but that's beyond the scope of the question ;)

You have one global clicked for all of them. Because of that actions are not isolated.
int clicked = 0;
Shouldnt be in class.

Your problem is that clicked is attached to the frame, not to the button. That means that there is only a single value of clicked for your entire application.
The easiest thing to do here would be to write a new class GregoryWeigelButton (or whatever) which extends JButton and has a int clicked=0 inside it (and probably a getter and setter). Then just check what the clicked value for that particular button is.

Related

Convert an incrementing/changing String value to existing incremental variable name of JButtons to modify their properties in java

Simplified: How to make String value to call specific existed JButton variable name in java?
I'm trying to make a non-ordinary Tic-Tac-Toe game...
Anyway, what I will post here is not really the whole concept of that. I just want to make it simple: I have 9 square jButtons named (3 by 3) (and maybe allow user to make 4x4, 5x5, 10x10 etc. via settings in future):
[markbox_00_00] / [markbox_00_01] / [markbox_00_02]
[markbox_01_00] / [markbox_01_01] / [markbox_01_02]
[markbox_02_00] / [markbox_02_01] / [markbox_02_02]
[btnSave] / [btnUndoActions]
where the first two digit represent the row and the next two is the column; and a save button (btnSave) and undo button(btnUndoActions).
Each markbox have default spring value of "0", when I click it turns "1"; and when I click "1" it turns "0". When you press undo button it will reset to last save.
Here is some of my simplified line of codes:
private byte markboxColLimit = 3, markboxRowLimit = 3, row, col;
private byte[][] saveNumber = new byte[markboxRowLimit][markboxColLimit];
private String buttonName;
public Astral_TicTacToe() {
initComponents();
/* I want something like this, but using a for loop based on markboxColLimit and
markboxRowLimit as limits */
markbox_00_00.setText("0");
markbox_00_01.setText("0");
markbox_00_02.setText("0");
markbox_01_00.setText("0");
markbox_01_01.setText("0");
markbox_01_02.setText("0");
markbox_02_00.setText("0");
markbox_02_01.setText("0");
markbox_02_02.setText("0");
/* I know the line below is wrong... what I'm trying is to avoid
* repetitiveness by looping and dynamically calling the variable
* name of JButtons, or in other ways...
*/
/* Attempting to make an alternative code from above (trying to make a loop instead) */
for(row = 0; row < markboxRowLimit; row++){
for(col = 0; col < markboxColLimit; col++){
buttonName = "markbox_0" + Byte.toString(row) + "_0" + Byte.toString(col);
buttonName.setText("0");
}
}
}
private void btnUndoActionsActionPerformed(java.awt.event.ActionEvent evt) {
markbox_00_00.setText(Byte.toString(saveNumber[0][0]));
markbox_00_01.setText(Byte.toString(saveNumber[0][1]));
markbox_00_02.setText(Byte.toString(saveNumber[0][2]));
markbox_01_00.setText(Byte.toString(saveNumber[1][0]));
markbox_01_01.setText(Byte.toString(saveNumber[1][1]));
markbox_01_02.setText(Byte.toString(saveNumber[1][2]));
markbox_02_00.setText(Byte.toString(saveNumber[2][0]));
markbox_02_01.setText(Byte.toString(saveNumber[2][1]));
markbox_02_02.setText(Byte.toString(saveNumber[2][2]));
}
private void btnSaveActionPerformed(java.awt.event.ActionEvent evt) {
saveNumber[0][0] = Byte.parseByte(markbox_00_00.getText());
saveNumber[0][1] = Byte.parseByte(markbox_00_01.getText());
saveNumber[0][2] = Byte.parseByte(markbox_00_02.getText());
saveNumber[1][0] = Byte.parseByte(markbox_01_00.getText());
saveNumber[1][1] = Byte.parseByte(markbox_01_01.getText());
saveNumber[1][2] = Byte.parseByte(markbox_01_00.getText());
saveNumber[2][0] = Byte.parseByte(markbox_02_00.getText());
saveNumber[2][1] = Byte.parseByte(markbox_02_01.getText());
saveNumber[2][2] = Byte.parseByte(markbox_02_02.getText());
}
private void markbox_00_00ActionPerformed(java.awt.event.ActionEvent evt) {
if("0".equals(markbox_00_00.getText()))
markbox_00_00.setText("1");
else
markbox_00_00.setText("0");
}
private void markbox_00_01ActionPerformed(java.awt.event.ActionEvent evt) {
if("0".equals(markbox_00_01.getText()))
markbox_00_00.setText("1");
else
markbox_00_00.setText("0");
}
....
private void markbox_02_02ActionPerformed(java.awt.event.ActionEvent evt) {
if("0".equals(markbox_00_00.getText()))
markbox_02_02.setText("1");
else
markbox_02_02.setText("0");
}
In short: how can I make String a specific variable name of JButton for calling/accessing/editing for their properties?
Example:
buttonName = markbox_01_02;
buttonName.setText("2");
is equavalent to markbox_01_02.getText("2");
I really appreciate the help, thank you...
P.S. I use to make JFrame in NetBeans Design (just click and drag the objects in palette window like JPanel, JButton, etc., so I don't type the code manually except making my own logical Method).
You probably need to redo your program and rephrase your question because it's kind of unclear where you're stuck that's why I wrote this answer as a Community Wiki.
The following program creates a GridLayout for the board and add 2 JButtons below it which contain "Save" and "Undo" buttons.
Whenever you press a button it will change it's text to 0 or 1 depending on the previous state of the button, and "Undo" button will undo last clic the same way, if it was 0 it will become 1 and viceversa.
I guess you should read How to write an ActionListener before copy-pasting this example, understand what it says and try to understand how this program works.
The logic to "Save" button is up to you 'cause I'm not sure what you wanna do there and I'm not gonna write all the code for you. This is made only for you to get an idea on how to handle events.
Also, the logic to end the game is left to you for the same reasons as the "Save" button.
I wish I knew how to record my screen in Ubuntu and save as GIF but here's a screenshot on how this program looks like:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class TicTacToe implements ActionListener {
JFrame frame;
JButton buttons[];
JPanel pane, buttonPane;
boolean pressed[];
JButton save, undo;
int n = -1;
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < buttons.length; i++) {
if(e.getSource() == buttons[i]) {
pressed[i] = !pressed[i];
buttons[i].setText(pressed[i] ? "1" : "0");
n = i;
break;
}
}
}
public TicTacToe () {
frame = new JFrame("Tic Tac Toe Game");
buttons = new JButton[9];
pane = new JPanel(new GridLayout(3, 3));
pressed = new boolean[9];
buttonPane = new JPanel(new FlowLayout());
save = new JButton("Save");
undo = new JButton("Undo");
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton("0");
pressed[i] = false;
}
for (JButton b : buttons) {
b.addActionListener(this);
pane.add(b);
}
undo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (n == -1) {
return;
}
pressed[n] = !pressed[n];
buttons[n].setText(pressed[n] ? "1" : "0");
}
});
buttonPane.add(save);
buttonPane.add(undo);
frame.add(pane, BorderLayout.PAGE_START);
frame.add(buttonPane, BorderLayout.CENTER);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main (String args[]) {
new TicTacToe();
}
}

Icon images not loading fast enough

I have an array of JPanel with JLabel with icons that represent a seat at a theater, all of them are generated using loop.
Upon loading the seats, those that are already booked need to have a different image icon. So if(){} check is performed on all the seats to change the label icon if the seat is booked, after they are generated.
But the image icon I have on my disk is not loading fast enough so sometimes the panel adds only to the last one booked or not at all.
Every of those panels that represent the chairs has also MouseListener interfaces added to them. So also on mouse hover or click ImageIcon objects added to the panels are changed, there is too much delay when this happens. I'm thinking that has to do with the images being on the disk!.
How can I load and store those icon images 2,78 KB in size in memory and refer to it in memory, so it wont be delayed reading them?
When a seat is clicked I need to change the label image of that seat and remove mouse listener from that seat. Is there a way to remove the mouse listener to that particular seat without referring to a specific mouse listener. I needed to do that outside of the mouse listener itself!
panel.removeAll();
Does not remove the mouse listener added upon generating the panels.
public void drawSeats(int ammountSeat, int localLength, int localWidth) {
pnlSeatsHolder = new JPanel();
pnlSeatsHolder.setPreferredSize(new Dimension(localLength * 40,localLength * 45));
pnlSeatsHolder.setLayout(new FlowLayout());
for (int d = 0; d <= (ammountSeat); d++) {
imgIconYellow = new ImageIcon("seatYellow.png");
imgIconBlue = new ImageIcon("seatBlue.png");
imgIconRed = new ImageIcon("seatRed.png");
JButton chairs = new JButton();
chairs.setPreferredSize(new Dimension(30, 40));
pnlSeatsHolder.add(chairs);
chairs.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
for (int i = 0; i < listSeatsObjects.size(); i++) {
if (listSeatsObjects.get(i).equals(e.getSource())) {
/*I need to do this also outside of this method! how can i refer to this MouseListener
* to forexample do the equivalent of chairs.removeMouseListener(this);*/
chairs.removeAll();
chairs.setIcon(imgIconRed);
chairs.repaint();
chairs.removeMouseListener(this);
// send information of the chair somewhere else
}
}
}
public void mouseEntered(MouseEvent e) {
// chairs.setBackground(Color.blue);
chairs.removeAll();
chairs.setIcon(imgIconBlue);
chairs.repaint();
}
public void mouseExited(MouseEvent e) {
// chairs.setBackground(Color.BLACK);
chairs.removeAll();
chairs.setIcon(imgIconYellow);
chairs.repaint();
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
});
}
}
so this is the method it self that draws the seats when called. I did some modification as #AndrewThompson suggested, instead of JPanels i use now JButtons, but what happens is that the images are not loaded at all on to the buttons.. what am i missing? neither on mouse hover either.. tho it does work if i had for example charis.setBackgroundColor(); on hover or click.. so i now i need to rather change the buttons images when clicked and on hover, i've tried chairs.chairs.setRolloverIcon(); and .setIcon(); both not working as well. what is wrong. my images are in the same directory as the class files.. so that cant be the issue..
int localLength, int localWidth is the size of the the rooms that seats will be drawn in. about 1m^2/seat
For three images, load them when the class is initialized and store them as attributes of the class. Of course, each of the 3 images can be used in as many icons as needed.

give JButton multiple options for mouse clicks (Blackjack Game)

I am writing a Blackjack program using JFrame and trying to keep it as simple as possible. My JButton, jbHit works with a single click, however it overwrites the playersHand and playerSide slot with every click. I would like it to work with multiple clicks (3 clicks - since that is the max number of cards you can get after the first two are dealt) options It should count them so to speak so that the array index can record the card image. Here is my ActionListener code that I have so far. I am afraid I am stuck. Should I use some sort of for loop with an int i++?
//Hit Button ActionListener
jbHit.addActionListener( new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ( playerValue < 21 ) {
//Draw a card
Card c = deck.drawCard();
playersHand.add(c);
playerSide[2].setIcon( new ImageIcon( c.getFilename() ) );
}
//If playerValue > 21, bust
else if ( playerValue > 21 ) {
//Toggle Buttons
jbDeal.setEnabled(true);
jbHit.setEnabled(false);
jbStand.setEnabled(false);
jbDoubleDown.setEnabled(false);
message = "You bust.";
}
}
});
You could create an array of "action commands" and every time you click the button, the action command changes to the next. If you reach the end, set the index back to zero. Perhaps something like this:
public static void main(String[] args)
{
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("Action");
String[] commands = {"command1", "command2", "command3"};
button.setActionCommand(commands[0]);
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
JButton btn = (JButton)e.getSource();
String cmd = btn.getActionCommand();
System.out.println("Command: " + cmd);
if(cmd.equals("command1"))
{
btn.setActionCommand(commands[1]);
System.out.println("Command 1 was pressed");
}
else if(cmd.equals("command2"))
{
btn.setActionCommand(commands[2]);
System.out.println("Command 2 was pressed");
}
else if(cmd.equals("command3"))
{
btn.setActionCommand(commands[0]);
System.out.println("Command 3 was pressed");
}
else
System.out.println("Something went wrong!");
}
});
panel.add(button);
frame.add(panel);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
If you are using Java 7 or later, you can replace the if/else with a Switch statement.
I believe you're looking for a logical flag based on an integer, for example:
if(cardsDealt < 3) {
// DoThings();
} else {
return;
}
Which would require you to do
cardsDealt++;
at the bottom of your button click handle.
If this is not what you're asking, please re-explain the question.
It sounds like you might be a little confused about how jbHit will be called. Realize that it will be called one complete time every time the mouse is clicked. It's not like it inherently knows that it is on the second or third click. Add a class member like int clickCount; that you increment at the appropriate point inside of jbHit. Then you can alter your method's response depending on the value of clickCount.

JButton doesn't appear until clicked

For this program, the JButton doesn't seem to show up unless you click the area where the JButton should be; the JFrame starts up blank. The moment you click the button, the respective code runs and the button finally shows up.
How do I get the buttons to show up upon starting the program?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/*
The Amazing BlackJack Advisory Tool by JoshK,HieuV, and AlvinC.
Prepare to be amazed :O
*/
public class BlckJackUI {
//main class, will contain the JFrame of the program, as well as all the buttons.
public static void main(String args[])
{
//Creating the JFrame
JFrame GUI = new JFrame("Blackjack Advisor");
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.setSize(1300, 900);
GUI.setContentPane(new JLabel(new ImageIcon("C:\\Users\\Hieu Vo\\Desktop\\Green Background.png")));
GUI.setVisible(true);
// Because each button needs to run through the Math class.
final Math math = new Math();
// The Ace Button:
ImageIcon Ace = new ImageIcon("/Users/computerscience2/Downloads/Ace.jpg");
JButton ace = new JButton(Ace);
ace.setSize(300, 100);
ace.setLocation(100, 100);
ace.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//Automatically default the the Ace to 11, and if Bust, Ace becomes 1.
if (math.array.playerhandtotal <= 21)
{
math.cardvalue = math.cardvalue + 11;
}
else
{
math.cardvalue = math.cardvalue + 1;
}
math.array.clicktracker++;
math.calcResult();
JOptionPane.showMessageDialog(null,math.array.result);
}
});
GUI.add(ace);
ImageIcon Two = new ImageIcon("/Users/computerscience2/Downloads/2.jpg");
JButton two = new JButton(Two);
two.setSize(300, 100);
two.setLocation(100, 200);
two.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
/*
This generally repeats throughout the whole class, and the only
thing different is the changing cardvalue. When a button is pressed,
respective cardvalues are added into the playerhand ArrayList, and
totaled up to form playerhandtotal, which is a major factor in
bringing up the advice.
*/
math.cardvalue = math.cardvalue + 2;
math.array.clicktracker++;
math.calcResult();
JOptionPane.showMessageDialog(null,math.array.result);
}
});
GUI.add(two);
Et cetera, Et cetera... Just a bunch of the same stuff, more buttons coded the same exact way as JButton two, but with different value associated to them.
JButton start = new JButton("Start/Reset");
start.setSize(300, 100);
start.setLocation(500,500);
start.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
/*
The start button also acts like a reset button, and the concept is fairly
simple. If we reset all the important values to 0 or "null," then the
program acts as if it was just opened.
*/
Arrays array = new Arrays();
array.playerhand.clear();
array.dealer = 0;
math.array.starttracker++;
math.array.clicktracker = 0;
array.playerhandtotal = 0;
math.cardvalue = 0;
array.result = null;
JOptionPane.showMessageDialog(null,"Please select the card \nthat the dealer is showing :)");
}
});
GUI.add(start);
GUI.setLayout(null);
This is all in the same class, and I understand a layout would be nicer, but perhaps there's a way to fix this issue using what I have now?
The program starts blank because you are calling setVisible before you add components. Call setVisible after you add components (in the end of contructor) and it should work fine.
Also, avoid absolute positioning and call of set|Preferred|Minimum|MaximumSize methods for your components. Learn how to use layout managers.
Write GUI.validate(); after you add all the components to your frame. Any time you add something to a frame you have to validate it like this. Otherwise, you will get the behavior that you have described.
No. The problem is caused by the layout. Before adding anything to a JFrame or a JPanel which you want it to have an absolute position, you have to setLayout(null). Otherwise, you'll have unexpected behaviours all the time. I just figured it out by myself after three hours of experimenting; suddenly, I connected your post with other different subject, and it worked, but this isn't well explained on the Internet yet.

GUI action listeners for each tab in a tabbed pane

I am fairly new to java so bear with me please, basically, below I have a tabbed pane for each of the four rooms in the rooms Arraylist, and I am creating buttons in each tab depending how many lights each room has, How can I associate the buttons in each tab with a specified the rooms?. So like when I click the light button in the Room 1 tab, the event listener knows that the button belongs to the room1?
Any help is appreciated, thanks.
import java.util.ArrayList;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class MasterGUI extends JFrame implements ActionListener{
public MasterGUI(){
}
public void DisplayFrame(){
ArrayList<Rooms> rooms;
rooms = Building.getRoomList();
JFrame master = new JFrame("Solar Master Control Panel");
master.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = master.getContentPane();
content.setBackground(Color.lightGray);
JTabbedPane tabbedPane = new JTabbedPane();
JPanel tmpPanel;
for(int x = 0; x < rooms.size(); x++){
tmpPanel = new JPanel();
String roomName = rooms.get(x).getName();
int id = rooms.get(x).getId();
tabbedPane.addTab(roomName + " Room " + id, tmpPanel);
}
for(int x = 0; x < rooms.size(); x++){
for(int i = 0; i < rooms.get(x).roomLights.size(); i++){
int num = i + 1;
((JPanel) tabbedPane.getComponentAt(x)).add(new JButton("Light" + num));
}
}
master.add(tabbedPane, BorderLayout.CENTER);
master.setSize(800, 600);
content.add(tabbedPane);
master.setVisible(true);
}
public void actionPerformed(ActionEvent e){
}
First of, you need to add the ActionListener to the button so it will be called when the button is clicked.
...
JButton button = new JButton("Light" + num);
button.addActionListener(this);
((JPanel) tabbedPane.getComponentAt(x)).add(button);
...
As far as differentiating between which button was clicked, there are two main ways to address this. The first is to use getSource() on the ActionEvent to get a reference to the object that triggered the event. You can use this to decide how you want to proceed further. The other option is to have MasterGUI not implement ActionListener. Instead, make a unique ActionListener for each button that immediately know what action needs to occur when it was called. The first option makes it easier to register listeners, but requires more work in the handler to determine the source. I prefer the second method.
ActionEvent in actionPerformed() will tell you the source of the button pressed. So you can do one of two things, you can name the button (which is not the same as the button text) something indicative of the room, or you can provide a command string that the button invokes, which is also available from the ActionEvent.
Check out the JButton JavaDoc, it has links to dealing with Actions and specifically button Actions supported.
It will focus your question a little better as well, since you'll have a better idea of how you're looking to achieve your goal.

Categories

Resources