views:

432

answers:

3

Hi, I'm super new to Java, and in need of some help. I'm making a little java desktop application where I basically have a grid of 4 JButtons ( 2 x 2 grid), and I need the background colour of individual JButtons to change, and after one second, change back to the original colour (the game I'm trying to make is like Simon, where you have to follow a pattern of buttons that light up). I have a vector that contains randomly generated numbers in the range of 1 to 4, and I want to be able to get each element from the vector and get the corresponding button to change to a different colour for one second (for example, if the vector contains 2 4 1, I would want button 2 to change, then button 4 to change, then button 1 to change).

Is this possible or is there a better way to go about doing this with something other than JButtons? How do I implement this?

Also, I'm running Mac OS X, which apparently (based on some things I've read on forums) doesn't like JButtons background changing (I think it's because of system look and feel), how can I change this so it works on mac?

Thank you in advance for any help :)

+2  A: 

One approach is to extend JToggleButton and override paintComponent() to display the color. A javax.swing.Timer can control timing. Here is a somewhat more elaborate example.

private static class SimonButton extends JToggleButton {

    private final Color color;
    Dimension size = new Dimension(100, 100);

    public SimonButton(Color color) {
        this.color = color;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (this.isSelected()) {
            g.setColor(color);
        } else {
            g.setColor(Color.lightGray);
        }
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
    }

    @Override
    public Dimension getPreferredSize() {
        return size;
    }
}
trashgod
+3  A: 

You can just use the setBackground(...) method to set the Color and then use a Swing Timer to reset the background when it fires.

Edit:

If your problem is that the setBackground() method doesn't work on some LAF's, then you could add an Icon to the button that is simply a solid Color. Then to change the background color you simple change the Icon.

camickr
Yep, `com.apple.laf.AquaButtonUI` is recalcitrant. I sometimes implement `Icon` and do `setIcon(this)`, drawing in `paintIcon()` instead of `paintComponent().
trashgod
+2  A: 

For your purposes, you don't necessarily have to use a JButton. You can use JLabels or JPanels.

During initialization, you can setBackground() on each one to set its color, and add a MouseListener to each one to detect a click.

To flash the Simon pattern, create a javax.swing.Timer that fires once every second. (You may want to make the delay configurable if 1 second seems like a long time.) For simplicity, the timer could setOpaque(false) on all the JLabels, then setOpaque(true) on the JLabel whose color you want to flash. Note that you might want to wait until the next timer iteration before doing setOpaque(true), so the flashes don't run together if you want to flash the same JLabel multiple times in a row.

The advantage of using setOpaque() is that you can set the MouseListener to just call setOpaque(true) on press and setOpaque(false) on release, and check whether the correct JLabel was clicked, without having to repeatedly recompute which color should be used for a given JLabel.

rob
This is the right way to go but you should use javax.swing.Timer rather than TimerTask as the setOpaque call should be made on the EDT.
Russ Hayward
Thanks for catching that, Russ; I fixed it.
rob