JButton lunarButton = new JButton(new ImageIcon("assets/Buttons/moon.png"));
lunarButton.setActionCommand("switch");
c.gridwidth=1;
c.gridy = 0;
searchArea.add(lunarButton, c);
.
public void actionPerformed(ActionEvent ev)
{
int count = 1;
String action = ev.getActionCommand();
if("switch".equals(action))
{
ImageIcon sun = new ImageIcon("assets/sun.png");
ImageIcon moon = new ImageIcon("assets/moon.png");
changeLunar();
count++;
if (count % 2 == 0)
{
lunarButton.setIcon(sun);
}
else
{
lunarButton.setIcon(moon);
}
I have this code implemented, but eclipse tells me "lunarButton cannot be resolved", is it not able to see the lunarButton variable in my init() method? what am I missing here?
Your lunarButton may be declared locally, perhaps in the init method.
One solution: declare it as an instance field in the class, not in the init method.
Solution two: don't even worry about the variable. Get the JButton object from the ActionEvent parameter's getSource() method. Cast the object returned to JButton, and call whatever methods you'd like on it.
For example:
if("switch".equals(action))
{
// ImageIcon sun = new ImageIcon("assets/sun.png");
// ImageIcon moon = new ImageIcon("assets/moon.png");
JButton btn = (JButton) ae.getSource();
changeLunar();
count++;
if (count % 2 == 0)
{
btn.setIcon(sun);
}
else
{
btn.setIcon(moon);
}
As an aside: you really don't want to re-load the images from disk each time the button is pushed. Instead read the images in once, perhaps in a constructor, stuff them into an ImageIcon field, and use that field when needed.
Related
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.
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();
}
}
I have a selectpic() method to set images in the jbuttons.
public void selectpic() {
rule rule = new rule();
rule.shuffle();
for (int i = 0; i < 9; i++) {
if (rule.pic[i] == 0) {
Icon0.setImage(Icon0.getImage().getScaledInstance(WIDTH,HEIGHT,Image.SCALE_DEFAULT));
panel1.add(new JButton(Icon0));
} else if (rule.pic[i] == 1) {
Icon1.setImage(Icon1.getImage().getScaledInstance(WIDTH,HEIGHT,Image.SCALE_DEFAULT));
panel1.add(new JButton(Icon1));
} else if (rule.pic[i] == 2) {
Icon2.setImage(Icon2.getImage().getScaledInstance(WIDTH,HEIGHT,Image.SCALE_DEFAULT));
panel1.add(new JButton(Icon2));
} else if (rule.pic[i] == 3) {
Icon3.setImage(Icon3.getImage().getScaledInstance(WIDTH,HEIGHT,Image.SCALE_DEFAULT));
panel1.add(new JButton(Icon3));
} else if (rule.pic[i] == 4) {
Icon4.setImage(Icon4.getImage().getScaledInstance(WIDTH,HEIGHT,Image.SCALE_DEFAULT));
panel1.add(new JButton(Icon4));
} else if (rule.pic[i] == 5) {
Icon5.setImage(Icon5.getImage().getScaledInstance(WIDTH,HEIGHT,Image.SCALE_DEFAULT));
panel1.add(new JButton(Icon5));
}
}
}
When each round is finished i have to call the selectpic() method again to change images.
However, i can't just simply call that method again to do it.
Q1. Is it necessary to remove the images first and then call the selectpic() again, so that it can change the images?
Q2. If so, i searched in forum and found using
xxxx.setImage(null);
can remove the image(xxxx is the name of that jbutton),
but in the selectpic(), i use this to add the jbuttons.
panel1.add(new JButton(Icon0));
how can i know the name of the jbuttons so that i can use xxxx.setImage(null); to remove the images first?
Thanks!!
You're not keeping track of your JButtons, and calling selectpic() fills the JPanel with buttons, so calling it multiple times will create a lot of buttons.
I recommend you to have your JButtons in the class fields, like this:
private JButton button1;
Then, when you initialize your UI, initialize your buttons too:
// UI init here
button1 = new JButton();
panel1.add(button1);
And in the selectpic method, set your icons.
button1.setIcon(choosedIcon);
PD: Now I look more carefully to your code, an array of JButtons would be better, I think. So, the field declaration would be this:
private JButton[] buttons = new JButton[numberOfButtons];
The initalization would be something like this:
for (int i = 0; i < numberOfButtons; i++) {
buttons[i] = new JButton();
panel1.add(buttons[i]);
}
And for setting the icon,
buttons[i].setIcon(chosedIcon);
PD2: I recommend you to start your variable names with a lowercase letter, like in the Naming Convention.
please see my attached code below and then my question at the end.
class events extends JFrame{
private JLabel label;
private JButton button;
public events() {
setLayout(new FlowLayout());
button = new JButton("Click for text");
add(button);
label = new JLabel("");
add(label);
event e = new event();
button.addActionListener(e);
}
public class event implements ActionListener {
public void actionPerformed(ActionEvent e) {
int x = 0;
if (x == 0) {
label.setText("the new label");
System.out
.println("setting x to 0 and label to display a label");
x = 1;
System.out.println(x);
} else {
label.setText("newerer label");
System.out.println("i reached the else segment");
x = 0;
System.out.println(x);
}
}
}
public static void main(String args[]) {
events gui = new events();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setTitle("Events Test");
gui.setSize(300, 100);
gui.setVisible(true);
}
}
Background: I am learning java and attempting to understand a concept. With this program I was attempting to create a small gui with a button that when clicked would assign a JLabel the String value of "the new label." I wanted to use that same button however to change the label to "newerer label" if clicked a second time and back again if clicked a third. I attempted to do this using an If/ Else statement with a variable x to hold essentially a state of 1 or 0. At the end of each portion of the If/Else i change the state of x to either 1 or 0 appropriately. When attempting to run the program in eclipse however, I have run into some kind of error. I assigned a system.out.println to each portion of the If/Else in an attempt to see how the program switches between the two states but it appears that my else statement is never reached.
Questions:
Is an If/Else statement appropriate to perform such a simple 2 state switch?
Is there a more appropriate way to do this? (i know about switch statements but opted for this as it was only a two state project).
What did I do wrong and why is my Else path never achieved when the state should be 1?
Thank you for your responses,
Pano
Your variable "x" must be declared as a class member.
public class event implements ActionListener{
private int x = 0;
public void actionPerformed(ActionEvent e){
if(x == 0){
label.setText("the new label");
System.out.println("setting x to 0 and label to display a label");
x = 1;
System.out.println(x);
}
else {
label.setText("newerer label");
System.out.println("i reached the else segment");
x = 0;
System.out.println(x);
}
}
}
You are initializing x every time the action listener gets called, so x is always 0. Move x somewhere else, possibly declare it as a class member.
Yes, I personally would use an if/else statement here, although if you are likely to add more states a switch statement may be appropriate, but I think given you have more than 1 line of code in the if/else blocks I would keep it as if/else as it has better readability in my experience.
I guess my answer to 1 covers this!
The reason your else block isn't being reached is that your x variable is only in scope (only exists) inside that method. As soon as you leave the method the value is no longer in scope so as far as your code in concerned it no longer exists. The code P Lalonde posted shows the correct way: having the variable as a member variable (object scope). Read more about member variable scope here: http://docs.oracle.com/javase/tutorial/java/javaOO/variables.html
If you are just looking for a switch of state you could actually do something like:
if( label.getText().equals("the new label") ) {
label.setText("newerer label");
} else {
label.setText("the new label");
}
Here's the ActionListener portion of my code. Focus on the reset button.
public void actionPerformed( ActionEvent e) {
int i;
for (i = 0; i < 26; i++) {
if (e.getSource() == a[i]) {
consultWord(i);
}
}
if (e.getSource() == reset) {
Hangman gui = new Hangman();
System.out.print("test");
gui.go();
}
}
Obviously there is much more above it (as this is at the VERY end). Button array 1 (top if statement) works perfectly. Button 2 (bottom if statement) doesn't work at all. The test output text does not appear. Here is where I declared the variables. (They are available to all code).
JButton reset = new JButton("Reset");
private Button a[];
And if it means anything to you, here's the code for setting up the a[] buttons.
int i;
StringBuffer buffer;
a = new Button[26];
topPanel.setLayout( new GridLayout( 4,0, 10, 10) );
for (i = 0; i <26; i++) {
buffer = new StringBuffer();
buffer.append((char)(i+'a'));
a[i] = new Button(buffer.toString());
a[i].setSize(100,100);
a[i].addActionListener( this );
topPanel.add(a[i]);
}
Any ideas why my bottom button isn't doing squat? I'll paste my whole code if need be.
Maybe you simply forgot to add the ActionListener to your reset button? This is missing from your code aboveā¦
As a side note some suggestions to make your code cleaner:
The StringBuffer is not needed: Simply use String.valueOf((char)(i+'a'))
I would not use the same ActionListener for all buttons you have, as this clutters your actionPerformed method. Anonymous inner classes can be useful here.