Matty2532
Matty2532

Reputation: 50

JLabel setIcon not working

I have a program that displays a picture of a coin. When the user clicks the coin the coin changes from heads to tails and vice versa. That works fine. The problem arises when I want to have a button that flips the coin a random number of times (In this case between 3 and 10 times inclusive). The method used to change the image icon:

flip.addActionListener(new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e1) {
            playerCoinState = coinState;
            System.out.println("Clicked");
            int flips = (new Random().nextInt(8)) + 3;
                    for(int i = 0; i < flips; i++){
                        try{
                            Thread.sleep(1000);
                        }catch(InterruptedException e2){
                            System.exit(1);
                        }
                        System.out.println("Auto Flipped");
                        changeFace();
                    }
        }
    });

And this is the method used to change the ImageIcon of the JLabel coin:

private void changeFace(){
    System.out.println("Changing...");
    switch(coinState){
    case 0:
        System.out.println("Coin State 0");
        try {
            coin.setIcon(new ImageIcon(ImageIO.read(new File("res/Heads.png"))));
        } catch (IOException e) {
            e.printStackTrace();
        }
        coinState = 1;
        break;
    case 1:
        System.out.println("Coin State 1");
        try {
            coin.setIcon(new ImageIcon(ImageIO.read(new File("res/Tails.png"))));
        } catch (IOException e) {
            e.printStackTrace();
        }
        coinState = 0;
        break;
    }
}

The JLabel coin is initialised as:

coin = new JLabel(new ImageIcon("res/Tails.png"));

coinState represents the value of the coin. 0 for heads, 1 for tails. playerCoinState is used to keep track of the coin state the player has selected before the coin is to be flipped by the computer the random amount of times.

Upvotes: 1

Views: 1064

Answers (3)

Matty2532
Matty2532

Reputation: 50

MadProgrammer helped me to solve this.
The new and improved ActionListener for the button is:

flip.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e1) {
            playerCoinState = coinState;
            int flips = (new Random().nextInt(10) + 5);
            Timer timer = new Timer(400, new ActionListener(){
            int counter = 0;
                @Override
                public void actionPerformed(ActionEvent e) {
                    if(counter == flips){
                        ((Timer)e.getSource()).stop();
                    }
                    changeFace();
                    counter++;
                }

            });
            timer.start();
        }
    }); 

Thanks again MadProgrammer =)

Upvotes: 0

MadProgrammer
MadProgrammer

Reputation: 347334

This...

               for(int i = 0; i < flips; i++){
                    try{
                        Thread.sleep(1000);
                    }catch(InterruptedException e2){
                        System.exit(1);
                    }
                    System.out.println("Auto Flipped");
                    changeFace();
                }

Is blocking the event dispatching thread, preventing ui from been updated until after the method exits

You should try using a Swing Timer instead, which acts as a pseudo loop, but waits in the background for a prescribed period of time before triggering a tick within the context of the EDT, making it safe to update the UI from

Upvotes: 1

Timf2000
Timf2000

Reputation: 29

coin = new JLabel(new ImageIcon((ImageIO.read(new File("path"))));

Use this instead of coin.setIcon(new ImageIcon(ImageIO.read(new File("res/Tails.png")))); So you are creating the coin label new every time. If you are working with eclispe and windowbuilder, you can just use the tools on the sidebar.

Upvotes: 1

Related Questions