I'm making a small game involving a grid of JButtons (MxN) and the main premise is to click on buttonA and then on buttonB, coloring buttonB and adjacent buttons of the same color as buttonB with the color of buttonA. I have made it so you are able to choose 3 possible difficulties. The colors are randomly generated. The main problem is getting the colors to change.
This is the method that I call after selecting the difficulty of the game:
public static void gameMechanics(int m, int n) {
final String[] pickedColour = {""};
final String[] placedColour = {""};
JButton[][] picked = new JButton[m][n];
JButton[][] placed = new JButton[m][n];
picked[m][n].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pickedColour[0] = picked[m][n].getText();
}
});
placed[m][n].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
placedColour[0] = placed[m][n].getText();
}
});
if (pickedColour[0] == "R" && placedColour[0] != "R") {
placed[m][n].setBackground(Color.RED);
placed[m][n].setText("R");
}
else if (pickedColour[0] == "G" && placedColour[0] != "G") {
placed[m][n].setBackground(Color.GREEN);
placed[m][n].setText("G");
}
else if (pickedColour[0] == "B" && placedColour[0] != "B") {
placed[m][n].setBackground(Color.BLUE);
placed[m][n].setText("B");
}
}
I would consider using JPanels and painting them, using a MouseListener instead.
However, if you're set on using JButtons, try this:
button.setBackground(Color.GREEN);
button.setOpaque(true);
Note that this might not work if you're setting the look and feel using UIManager.
Also, you're doing a ton of extra work to map the color to the button - it could get confusing and cause errors down the road. Instead, you might try creating your own class:
class ColoredButton extends JButton {
private static final long serialVersionUID = 3040767030924461426L;
private Color color;
public ColoredButton(Color c) {
this.color = c;
this.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
changeColor();
}
});
}
public void changeColor() {
this.setBackground(this.color);
this.setOpaque(true);
}
}
Now, you can construct a new ColoredButton:
// Now, this button will turn green when clicked
ColoredButton temp = new ColoredButton(Color.GREEN);
Related
I am currently trying to set up a Tic Tac Toe GUI grid with 3x3 buttons, which change the button icon to a nought or cross whenever pressed.
I have set up an array of JButtons and have added a listener to check whenever the button is pressed.
My problem is getting access to the Button object inside the array, I have had to add a parameter to my custom listener constructor to save the button object reference for when I want to change it. It works as is, but doesn't feel very elegant. Is there a way to find the correct JButton object in buttons while inside actionPerformed, or is there a better way to do this altogether?
Thanks in advance
class BigPanel
{
public JPanel bigPanel= new JPanel(new GridLayout(3,3));
public JButton[][] buttons = new JButton[3][3];
public BigPanel()
{
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
buttons[i][j] = new JButton();
buttons[i][j].setPreferredSize(new Dimension(75,75));
// Line of interest, adding the listener
buttons[i][j].addActionListener(new CustomActionListener(buttons[i][j]));
bigPanel.add(buttons[i][j]);
}
}
}
}
class CustomActionListener implements ActionListener
{
public int a;
public int b;
public JButton button;
CustomActionListener(JButton a)
{
button = a;
}
public void actionPerformed(ActionEvent e)
{
changeButton(a, b, CurrPlayer.CROSSES);
}
public void changeButton(int a, int b, CurrPlayer player)
{
if (player == CurrPlayer.NOUGHTS)
{
Icon icon = new ImageIcon("Nought.jpg");
button.setIcon(icon);
}
else
{
Icon icon = new ImageIcon("Cross.jpg");
button.setIcon(icon);
}
}
}
Change your CustomActionListener to following will solve this problem
class CustomActionListener implements ActionListener {
public int a;
public int b;
CustomActionListener()
{
}
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton) e.getSource();
changeButton(a, b, CurrPlayer.CROSSES, button);
}
public void changeButton(int a, int b, CurrPlayer player, JButton button)
{
if (player == CurrPlayer.NOUGHTS)
{
Icon icon = new ImageIcon("Nought.jpg");
button.setIcon(icon);
}
else
{
Icon icon = new ImageIcon("Cross.jpg");
button.setIcon(icon);
}
}
}
You can get JButton reference using actionEvent.getSource() method.
And add action listener to buttons as below
buttons[i][j].addActionListener(new CustomActionListener());
Hope this'll help you.
I've this class:
public class Gemme extends JButton implements ActionListener{
private static int indicateur=0;
private Gemme gemme1;
private Gemme gemme2;
#Override
public void actionPerformed(ActionEvent e) {
indicateur = 1-indicateur;
if(this.indicateur==1)//first click
{
this.gemme1 = (Gemme) e.getSource();
}
else
{
this.gemme2 = (Gemme) e.getSource();
switchColor();
}
}
private void switchColor()
{
Color c = gemme1.getBackground();
gemme1.setBackground(gemme2.getBackground());
gemme1.setBackground(c);
System.out.println("color switched");
}
Basically i'm creating a game:
A grid of Colored JButtons, when the player try to click on two JBs in order to switch color between them.
The problem that i get NPE at this line:
Color c = gemme1.getBackground();
But when i put the Color c = gemme1.getBackground(); in the actionPerformed like that:
public void actionPerformed(ActionEvent e) {
indicateur = 1-indicateur;
if(this.indicateur==1)//first click
{
this.gemme1 = (Gemme) e.getSource();
Color c = gemme1.getBackground();
}
else
{
this.gemme2 = (Gemme) e.getSource();
//switchColor();
}
}
It works, i didn't understand, is the JB is losing his properties when the action is not matching to it?
Any explanation please?
EDIT
I changed switchColor() to :
private void switchColor()
{
System.out.println(gemme1);
System.out.println(gemme2);
}
Output:
null
mini.projet.dev.game.components.Gemme[btn42,104,216,51x53,alignmentX=0.0,alignmentY=0.5,b...........
How gemme1 becomes null ?
I solved the problem, it was just changing gemme1/gemme2 to static in order to becomes shared between other instances of Gemme:
private static Gemme gemme1;
private static Gemme gemme2;
if(this.indicateur==1)//first click
{
this.gemme1 = (Gemme) e.getSource();
}
else
{
this.gemme2 = (Gemme) e.getSource();
switchColor();
}
In this code, you are initializing the gemme2 member only. When you call switchColor() in the else block, the gemme1 remains undefined, e.g. null. That's why you get NPE during the gemme1.getBackground(); call.
I am trying to get a group of JRadioButtons to be navigable using the arrow keys. I was going to implement this manually with KeyListeners, but apparently this behavior is already supposed to work for at least the last 8 years (http://bugs.sun.com/view_bug.do?bug_id=4104452). However, it's not working for me: pressing the arrow keys does nothing. Java version is 7u45 on Windows.
A standalone test case to see what I'm talking about:
import java.awt.*;
import javax.swing.*;
public class Test {
public static void main(final String[] args) {
if (!EventQueue.isDispatchThread()) {
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
main(args);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
return;
}
try {
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
//UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Throwable t) {
throw new RuntimeException(t);
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ButtonGroup group = new ButtonGroup();
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
JRadioButton rb;
rb = new JRadioButton("Option A");
panel.add(rb);
group.add(rb);
rb = new JRadioButton("Option B");
panel.add(rb);
group.add(rb);
rb = new JRadioButton("Option C");
panel.add(rb);
group.add(rb);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
I have tried using different look & feels, different containers, and different layout managers, but it still does not work.
You need to add the right/left (up/down?) keys to the focus traversal policy of each radio button. For example to add the right/left arrow keys:
Set set = new HashSet( rb.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "RIGHT" ) );
rb.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set );
set = new HashSet( rb.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "LEFT" ) );
rb.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set );
Read the section from the Swing tutorial on How to Use the Focus Subsystem for more information.
I believe you can achieve your goal using KeyBindings instead of KeyListeners. In many cases bindings are actually recommended over KeyListeners, as the second ones can generate many problems (frame catching the key activity must be active one etc.)
Thank you everyone for the answers.
I discovered the reason for my confusion. Apparently, when the Sun bug report system says that a bug's status is "Closed" and its "Resolved Date" is "2005-07-19", that doesn't mean the bug is fixed at all. Apparently, it's just logged as a duplicate of some other (newer?) bug. Nearly 16 years since it was first reported it still isn't fixed. Whatever.
The needed behavior is much more subtle than I realized. I experimented in native Windows dialogs in various programs:
Most button-like components: buttons, checkboxes, and radio buttons, implement the arrow keys for focus navigation. In Java this corresponds to the AbstractButton class. (JMenuItem is also a subclass of that, but that has its own distinct arrow key behavior.)
Only radio buttons get selected/checked during this navigation.
Unfocusable (including disabled or invisible) components must be skipped.
Attempting to navigate before the first button in a group or after the last one is inconsistent: on some dialogs it loops from end to end; on others it moves irreversibly onto non-button components; and on yet others it does nothing. I experimented with all these different behaviors and none of them was particularly better than the others.
I implemented a looping behavior below as it felt slightly more fluent. The navigation silently skips past non-AbstractButton components, forming a sort-of separate focus cycle private to buttons. This is dubious but sometimes needed when a set of related checkboxes or radio buttons are mixed with other components. Testing for a common parent component to identify groups would also be a reasonable behavior, but that didn't work in one dialog where I'd used separate components purely for layout reasons (to implement a line break in a FlowLayout).
As suggested I studied up on InputMaps and ActionMaps instead of using a KeyListener. I've always avoided the maps as they seem overcomplicated but I guess I see the advantage of being able to easily override the binding.
This code uses an auxialiary look and feel to install the desired behavior for all AbstractButton components application-wide (which is a nice technique I found out about here). I've tested it with several different dialog boxes and windows and it seems to be okay. If it causes issues I'll update this post.
Call:
ButtonArrowKeyNavigation.install();
once at application startup to install it.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonArrowKeyNavigation {
private ButtonArrowKeyNavigation() {}
public static void install() {
UIManager.addAuxiliaryLookAndFeel(lookAndFeel);
}
private static final LookAndFeel lookAndFeel = new LookAndFeel() {
private final UIDefaults defaults = new UIDefaults() {
#Override
public javax.swing.plaf.ComponentUI getUI(JComponent c) {
if (c instanceof AbstractButton && !(c instanceof JMenuItem)) {
if (c.getClientProperty(this) == null) {
c.putClientProperty(this, Boolean.TRUE);
configure(c);
}
}
return null;
}
};
#Override public UIDefaults getDefaults() { return defaults; };
#Override public String getID() { return "ButtonArrowKeyNavigation"; }
#Override public String getName() { return getID(); }
#Override public String getDescription() { return getID(); }
#Override public boolean isNativeLookAndFeel() { return false; }
#Override public boolean isSupportedLookAndFeel() { return true; }
};
private static void configure(JComponent c) {
InputMap im = c.getInputMap(JComponent.WHEN_FOCUSED);
ActionMap am = c.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "focusPreviousButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "focusPreviousButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "focusNextButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "focusNextButton");
am.put("focusPreviousButton", focusPreviousButton);
am.put("focusNextButton", focusNextButton);
}
private static final Action focusPreviousButton = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
move((AbstractButton)e.getSource(), -1);
}
};
private static final Action focusNextButton = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
move((AbstractButton)e.getSource(), +1);
}
};
private static void move(AbstractButton ab, int direction) {
Container focusRoot = ab.getFocusCycleRootAncestor();
FocusTraversalPolicy focusPolicy = focusRoot.getFocusTraversalPolicy();
Component toFocus = ab, loop = null;
for (;;) {
toFocus = direction > 0
? focusPolicy.getComponentAfter(focusRoot, toFocus)
: focusPolicy.getComponentBefore(focusRoot, toFocus);
if (toFocus instanceof AbstractButton) break;
if (toFocus == null) return;
// infinite loop protection; should not be necessary, but just in
// case all buttons are somehow unfocusable at the moment this
// method is called:
if (loop == null) loop = toFocus; else if (loop == toFocus) return;
}
if (toFocus.requestFocusInWindow()) {
if (toFocus instanceof JRadioButton) {
((JRadioButton)toFocus).setSelected(true);
}
}
}
}
Here is my example of JRadioButtons can be navigable using the arrow keys(UP and Down) and modified few codes for you.
public class JRadioButton extends JPanel {
private JRadioButton[] buttons;
public JRadioButtonTest(int row) {
ButtonGroup group = new ButtonGroup();
buttons = new JRadioButton[row];
for (int i = 0; i < buttons.length; i++) {
final int curRow = i;
buttons[i] = new JRadioButton("Option " + i);
buttons[i].addKeyListener(enter);
buttons[i].addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
if (curRow > 0)
buttons[curRow - 1].requestFocus();
break;
case KeyEvent.VK_DOWN:
if (curRow < buttons.length - 1)
buttons[curRow + 1].requestFocus();
break;
default:
break;
}
}
});
group.add(buttons[i]);
add(buttons[i]);
}
}
private KeyListener enter = new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
((JButton) e.getComponent()).doClick();
}
}
};
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JRadioButton(3));
frame.pack();
frame.setVisible(true);
}
}
The core implement method is calling requestFocus() on the correct JRadioButton when an arrow key is called. Extra KeyListener for when the Enter key is pressed.
You can use this KeyListener to your program and add more key.
Good luck!
Well its weird. I am not good with radiobuttons by the way. But I made a JPanel program in netbeans which includes a RadioButton. You enter all this information with JTextFields(no problem) and then lastly I had a JButton which you click the choice you want. Then I have a JButton that takes all the information and outputs this. For the RadioButton, I first entered the usual:
family = new JRadioButton("Family", true);
friend = new JRadioButton("Friend");
relative = new JRadioButton("Relative");
friendFriend = new JRadioButton("Friend of Friend");
ButtonGroup group = new ButtonGroup();
group.add (friend);
group.add (family);
group.add (relative);
group.add (friendFriend);
(I'm not sure if I needed a listner for the RadioButtons or not but my program still seems to "crash" no matter what).
then I had one action listner for the JButton which included all the textfields and radio buttons. But the RadioButton is the issue.
In the action listner I had:
Object source = event.getSource();
if (source == family)
relation1 = true;
else
if (source == friend)
relation2 = true;
else
if(source == relative)
relation3 = true;
else
if(source == friendFriend)
relation4 = true;
Then I made a relation class:
public class Relation {
private boolean arrayFamily, arrayFriend, arrayRelative, arrayFriendFriend;
public Relation(boolean relation1, boolean relation2, boolean relation3,
boolean relation4)
{
this.arrayFamily = relation1;
this.arrayFriend = relation2;
this.arrayRelative = relation3;
this.arrayFriendFriend = relation4;
}
public String relations ()
{
String relationship = null;
if(arrayFamily && !arrayFriend && !arrayRelative && !arrayFriendFriend == true)
{
relationship = "Family";
}
else
if(arrayFriend && !arrayFamily && !arrayRelative &&
!arrayFriendFriend == true)
{
relationship = "Friend";
}
else
if(arrayRelative && !arrayFamily && !arrayFriend &&
!arrayFriendFriend == true)
{
relationship = "Relative";
}
else
if(arrayFriendFriend && !arrayFamily && !arrayFriend &&
!arrayRelative == true)
{
relationship = "Friend of a Friend";
}
return relationship;
}
}
LASTLY back in the action listner, I implementer this class:
Relation relationship = new Relation(relation1, relation2, relation3
, relation4);
String arrayRelation = relationship.relations();
I lastly included arrayRelation in an array but the array worked fine.
My problem is that the output of the array for my RadioButtons keeps reading "null" (most likey because this code: String relationship = null;). I assume this means that none of my if else statements were satisfied and I really dont know why.
Also important to point out is that if I click submit without clicking any radio button (the button stays on "family"), it reads null. If I click a button once it works perfectly reading the string I intended. But if I click another button afterwards and click submit again, the string goes back to "null".
I know its lengthy but I would really appreciate any help because I am lost.
P.S. some parts of my code are repetitive because I was playing around trying to fix the problem.
I suggest you handle your action events separately, for example:
family.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
familyActionPerformed(evt);
}
});
Then implement familyActionPerformed(evt):
private void familyActionPerformed(java.awt.event.ActionEvent evt) {
// every click on family radio button causes the code here to be executed
relation1 = true;
}
Also write an event handler for the button you click, like this:
submitButtonActionPerformed(java.awt.event.ActionEvent evt) {
// Here test the state of each radio button
relation1 = family.isSelected();
relation2 = friend.isSelected();
relation3 = relative.isSelected();
relation4 = friendFriend.isSelected();
}
MORE EDIT:
Doing what you're doing with NetBeans should be very easy. Here are tutorials that will clear it all up for you:
Tutorial 1
Tutorial 2
I explain the solution again:
Using 'family' button as an example, in your constructor where you have created and initialised your GUI components do this:
JRadioButton family = new JRadioButton();
// do any other thing you want to do to this button and finally..
family.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
familyActionPerformed(evt);
}
});
JButton submit = new JButton("Submit");
submit.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
submitActionPerformed(evt);
}
});
Then somewhere create these methods:
private void familyActionPerformed(java.awt.event.ActionEvent evt){
// each time family is selected, you code processes the lines below:
...
}
private void submiteActionPerformed(java.awt.event.ActionEvent evt){
relation1 = family.isSelected();
relation2 = friend.isSelected();
relation3 = relative.isSelected();
relation4 = friendFriend.isSelected();
}
Do something similar for the rest of the RadioButtons.
I think that you're making things way too complex for yourself. If all you want is the String of the JRadioButton pressed, then use the ButtonGroup to get it for you. It can return the ButtonModel of the selected JRadioButton (if any one was selected), and from that you can extract the actionCommand String, although you'll have to remember to set this when you create your JRadioButton.
For example:
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class JRadioExample extends JPanel {
private static final String[] RADIO_TITLES = { "Family", "Friend",
"Relative", "Friend or Relative" };
private ButtonGroup btnGrp = new ButtonGroup();
public JRadioExample() {
for (int i = 0; i < RADIO_TITLES.length; i++) {
JRadioButton rBtn = new JRadioButton(RADIO_TITLES[i]);
rBtn.setActionCommand(RADIO_TITLES[i]); // ***** this is what needs to
// be set
btnGrp.add(rBtn);
add(rBtn);
}
add(new JButton(new BtnAction("Get Chosen Selection")));
}
private class BtnAction extends AbstractAction {
public BtnAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent evt) {
ButtonModel model = btnGrp.getSelection();
if (model != null) {
String actionCommand = model.getActionCommand();
System.out.println("Selected Button: " + actionCommand);
} else {
System.out.println("No Button Selected");
}
}
}
private static void createAndShowGui() {
JRadioExample mainPanel = new JRadioExample();
JFrame frame = new JFrame("JRadioExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I have a problem with the code I am currently trying to run - I am trying to make 3 buttons, put them on a GUI, and then have the first buttons colour be changed to orange, and the buttons next to that colour change to white and green. Every click thereafter will result in the colours moving one button to the right. My code thus far is as follows, it is skipping colours in places and is not behaving at all as I expected. Can anyone offer some help/guidance please ?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ButtonJava extends JButton implements ActionListener {
private int currentColor=-1;
private int clicks=0;
private static final Color[] COLORS = {
Color.ORANGE,
Color.WHITE,
Color.GREEN };
private static ButtonJava[] buttons;
public ButtonJava( ){
setBackground( Color.YELLOW );
setText( "Pick ME" );
this.addActionListener( this );
}
public static void main(String[] args) {
JFrame frame = new JFrame ("JFrame");
JPanel panel = new JPanel( );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
buttons = new ButtonJava[3];
for(int i = 0;i<buttons.length ; i++){
buttons[i] = new ButtonJava();
panel.add(buttons[i]);
}
frame.getContentPane( ).add( panel );
frame.setSize( 500, 500);
frame.setVisible( true );
}
private void updateButton() {
clicks++;
changeColors();
// setText( );
}
private void changeColors( ) {
for (int i=buttons.length-1;i>=0;i--){
buttons[i].currentColor = nextColor(currentColor);
buttons[i].setBackground(COLORS[buttons[i].currentColor]);
buttons[i].setText(("# of clicks = " + buttons[i].getClicks() ) );
}
}
private Integer getClicks() {
return clicks;
}
private int nextColor( int curCol ) {
final int colLen = COLORS.length;
curCol--;
curCol = (colLen + curCol % colLen) % colLen;
return curCol;
}
private void firstClick( ActionEvent event ) {
int curCol = 0;
for (int i=buttons.length-1;i>=0;i--){
if ( buttons[i] == event.getSource() ) {
buttons[i].currentColor = curCol;
curCol++;
currentColor++;
}
}}
#Override
public void actionPerformed( ActionEvent event ) {
if ( -1 == currentColor ) {
firstClick( event );
}
updateButton( );
}
}
Thank you very much for the help :)
You have a couple issues with the code you posted, but they generally boil down to being clear about what is a member of the class(static) and what is a member of the instance.
For starters, you buttons array only exists inside your main method and can't be accessed by changeColors(). Along those same lines, since changeColors() is an instance method, setBackground() needs to be called directly on the button in your array. as written you are setting the color for one button 3 times.
Additionally, the logic in changeColors() is not properly rotating the currentColor index. You need to both increase the counter and ensure is wraps for the length of the color array. If the arrays are the same size, you need to make sure there is an extra addition to make the colors cycle.
private static void changeColors( ) {
for (int i=0;i<buttons.length;i++){
buttons[i].setBackground(COLORS[currentColor]);
currentColor = nextColor(currentColor);
}
if (buttons.length == COLORS.length) {
currentColor = nextColor(currentColor);
}
}
private static int nextColor(int currentColor) {
return (currentColor+1)% COLORS.length;
}
Edit for new code:
I'm not sure why you re-wrote nextColor(), as what I posted worked. But in general, I feel like you are running into issues because your code is not well partitioned for the tasks you are trying to achieve. You have code related to the specific button instance and code related to controlling all the buttons mixing together.
With the following implementation, the issue of how many times a button was clicked is clearly self-contained in the button class. Then every button press also calls the one method in the owning panel. This method knows how many buttons there are and the color of the first button. And each subsequent button will contain the next color in the list, wrapping when necessary.
public class RotateButtons extends JPanel {
private static final Color[] COLORS = { Color.ORANGE, Color.WHITE, Color.GREEN };
private static final int BUTTON_COUNT = 3;
private JButton[] _buttons;
private int _currentColor = 0;
public static void main(String[] args)
{
JFrame frame = new JFrame("JFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RotateButtons());
frame.setSize(500, 500);
frame.setVisible(true);
}
public RotateButtons()
{
_buttons = new JButton[BUTTON_COUNT];
for (int i = 0; i < _buttons.length; i++) {
_buttons[i] = new CountButton();
add(_buttons[i]);
}
}
private void rotateButtons()
{
for (JButton button : _buttons) {
button.setBackground(COLORS[_currentColor]);
_currentColor = nextColor(_currentColor);
}
if (_buttons.length == COLORS.length) {
_currentColor = nextColor(_currentColor);
}
}
private int nextColor(int currentColor)
{
return (currentColor + 1) % COLORS.length;
}
private class CountButton extends JButton {
private int _count = 0;
public CountButton()
{
setBackground(Color.YELLOW);
setText("Pick ME");
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0)
{
_count++;
setText("# of clicks = " + _count);
rotateButtons();
}
});
}
}
}
2nd Edit:
Shows just the changes to shift _currentColor by the necessary amount on the first click.
public class RotateButtons extends JPanel {
...
private boolean _firstClick = true;
...
private void rotateButtons(CountButton source)
{
if (_firstClick) {
_firstClick = false;
boolean foundSource = false;
for (int i = 0; i < _buttons.length; i++) {
if (foundSource) {
_currentColor = nextColor(_currentColor);
} else {
foundSource = _buttons[i] == source;
}
}
}
...
}
private class CountButton extends JButton {
...
public CountButton()
{
...
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0)
{
...
rotateButtons(CountButton.this);
}
});
}
}
One thing that I noticed is you are using currentColor to assign the color, but the currentColor is initialized to 0 and the only manipulation is currentColor %= 2 which does not change it.
If I'm understanding what you are wanting to achieve, I'm thinking to change currentColor %= 2 to ++currentColor, and setBackground(COLORS[currentColor]); to buttons[i].setBackground(COLORS[(i + currentColor) % 3]);. That way, your colours should cycle around your buttons each time one is clicked.
EDIT: it's probably also worth calling changeColors from within main to initialise your button colours. And, as #unholysampler notes, your array buttons is local to main and should (for example) be refactored as a static member variable, and have changeColors become a static method.