Hi, I recently decided to have another go at learning some programming, and decided to make some sort of 2d gameboard useable for stuff like Chess and Othello. I ran into a problem that I ran into last time I tried learning programming as well, and it has to do with updating Swing elements with a delay. Say I want to change the color or appearance of a series of JButtons, but I want to "turn" one button then wait for a second before turning the next one and so on. What I keep ending up with is that the program waits the combined waitingperiod for all the buttons then repaints them all at once. Last time I tried I went about the coding quite differently with classes extending Thread / implementing Runnable but always hit the same issue (Old "solutions" are on old computer which is currently not working) Here's todays attempt, if anyone is able to give me some pointers as to why it's updating in bulk instead of one by one I'd be very happy :) The main only contains new Board(8,8, "Game");

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Board implements ActionListener{
    //GameButton[][] gameButtons;
    JButton[][] gameButtons;
    JFrame board;
    public Board(int width, int height, String name) {
        gameButtons = new JButton[width][height];
        board = new JFrame(name);
        board.setPreferredSize(new Dimension(height*60, width*60));
        board.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        board.setVisible(true);
        board.setLayout(new BorderLayout());
        board.add(getButtons(width, height), BorderLayout.CENTER);
        board.pack();       
    }

    private JPanel getButtons(int width, int height) {
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(width, height));
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                //gameButtons[i][j] = new GameButton(this, ""+i+""+j);
                gameButtons[i][j] = new JButton();
                gameButtons[i][j].addActionListener(this);
                buttonPanel.add(gameButtons[i][j]);
            }
        }       
        return buttonPanel;
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        swapColors();
    }

    private void swapColors() {
        //gameButtons[3][1].changeColor(Color.WHITE);
        gameButtons[3][1].setBackground(Color.WHITE);
        System.out.println("a");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        gameButtons[3][2].setBackground(Color.WHITE);
        gameButtons[3][2].repaint();
        System.out.println("b");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        gameButtons[4][3].setBackground(Color.WHITE);
        System.out.println("c");
    }
}

EDIT:When changing from custom button (Extends JButton) to regular JButton for ease of reading I forgot to add actionListener in the post, that's fixed now.

Recommended Answers

All 3 Replies

The updating of GUI is done on the same execution thread that was used to call your listener method.
It will not do any updating until the listener method returns usage of the thread.
All the changes you make on the thread are not made visible until the JVM gets control of the thread back. If you want to show individual changes, you need to use a Timer to make each change and then return the thread to the JVM's GUI code to show the change.

commented: Sounds like you are on to something there :) Thanks for the explanation. I ahve tried using Timer before but ran into the same problem as I never returned the thread to the JVM's GUI code. (Still no idea on how to do that, but I'll look into it) Guess I n +0

NormR1: Thanks for the reply. Played around a bit with the Timer (swing one, not util) and it seems I got it working. You do mention that I need to "return the thread to the JVM's GUI code" not sure if you meant that is something I explicitly have to code in or not. (I got it working without explicitly returning the thread, but if you'd like to enlighten me on that subject I'm of course all ears)
Anyway; here's the code now, does this seem like an ok solution?
package UI;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Board implements ActionListener{
    //GameButton[][] gameButtons;
    Timer timer = new Timer(500, this);
    int line = 0;
    JButton[][] gameButtons;
    ArrayList<JButton> toSwap = new ArrayList<JButton>();
    JFrame board;
    public Board(int width, int height, String name) {
        gameButtons = new JButton[width][height];
        board = new JFrame(name);
        board.setPreferredSize(new Dimension(height*60, width*60));
        board.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        board.setVisible(true);
        board.setLayout(new BorderLayout());
        board.add(getButtons(width, height), BorderLayout.CENTER);
        board.pack();   
    }

    private JPanel getButtons(int width, int height) {
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(width, height));
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                gameButtons[i][j] = new JButton();
                gameButtons[i][j].addActionListener(this);
                gameButtons[i][j].setActionCommand(""+i+""+j);
                //gameButtons[i][j] = new GameButton(this, ""+i+""+j);
                buttonPanel.add(gameButtons[i][j]);
            }
        }       
        return buttonPanel;
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        if (arg0.getSource().getClass().equals(JButton.class)) {
            System.out.println("adding to toSwap");
            toSwap.add(gameButtons[0][line]);
            toSwap.add(gameButtons[1][line]);
            toSwap.add(gameButtons[2][line]);
            toSwap.add(gameButtons[3][line]);
            toSwap.add(gameButtons[4][line]);
            line++;
            timer.start();
        }else {
            if (toSwap.size() > 0) {
                toSwap.remove(0).setBackground(Color.GREEN);

            }else timer.stop();
        }
    }

}

By "return the thread" I meant that the code in your program should return from the method called by the JVM returning control to the program that called it.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.