Search code examples
javauser-interfaceactionlistener

How can I change an image label upon click using actionListener


I am trying to create a simple dice GUI where a random image of a dice value will appear on click, without the same value appearing twice in a row. I am to the point where I need to define the code in the actionListener, but upon clicking, the images do not change. The line of code that should cause the images to change is lblNewLabel.setIcon(dice[verifiedNum]) in the defineBtn method but I get the error that it cannot be resolved to a type. My question is: what changes do I need to make in order to get the JLabel to change images randomly without repeating the same image? The error I get is Exception in thread "AWT-EventQueue-0" java.lang.Error: Unresolved compilation problem: lblNewLabel cannot be resolved.


public class LabGuiDice extends JFrame {
    
    final ImageIcon image1 = new ImageIcon(LabGuiDice.class.getResource("/guiDice/img/die-1.png"));

    final ImageIcon image2 = new ImageIcon(LabGuiDice.class.getResource("/guiDice/img/die-2.png"));

    final ImageIcon image3 = new ImageIcon(LabGuiDice.class.getResource("/guiDice/img/die-3.png"));

    final ImageIcon image4 = new ImageIcon(LabGuiDice.class.getResource("/guiDice/img/die-4.png"));

    final ImageIcon image5 = new ImageIcon(LabGuiDice.class.getResource("/guiDice/img/die-5.png"));

    final ImageIcon image6 = new ImageIcon(LabGuiDice.class.getResource("/guiDice/img/die-6.png"));

    final JPanel contentPane;

    final ImageIcon[] dice = { image1, image2, image3, image4, image5, image6 };

    

    final Random rand = new Random();

    int randNum = rand.nextInt(6);

    int verifiedNum = 0;

    

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    LabGuiDice frame = new LabGuiDice();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        
    }
        
    /**
     * Create the frame.
     */
    public LabGuiDice() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));

        setContentPane(contentPane);
        contentPane.setLayout(new BorderLayout(0, 0));
        
        JButton btnNewButton = defineBtn();
        contentPane.add(btnNewButton, BorderLayout.SOUTH);
        
        JLabel lblNewLabel = diceLbl();
        contentPane.add(lblNewLabel, BorderLayout.CENTER);
        
        
        
    }
    
    private JButton defineBtn() {
        JButton btnNewButton = new JButton("Roll 'Em");
        btnNewButton.setAlignmentX(Component.CENTER_ALIGNMENT);
        btnNewButton.setAlignmentY(Component.TOP_ALIGNMENT);
        btnNewButton.setFont(new Font("Javanese Text", Font.PLAIN, 15));
        btnNewButton.setBackground(new Color(178, 172, 136));
        btnNewButton.setForeground(new Color(255, 255, 255));
        btnNewButton.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) { 
            do{randNum = rand.nextInt(6);} 
            while (randNum == verifiedNum);
            verifiedNum = randNum;
            lblNewLabel.setIcon(dice[verifiedNum]);
            
            }});
        return btnNewButton;
    }

    

    private JLabel diceLbl() {
        JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setOpaque(true);
        lblNewLabel.setBackground(new Color(192, 192, 192));
        lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
        lblNewLabel.setIcon(dice[randNum]);
        lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
        
        return lblNewLabel;
    }

    
}


When I tried to place lblNewLabel.setIcon(dice[verifiedNum]) inside of the diceLbl method the image still does not change upon click.


Solution

  • You have...

    private JLabel diceLbl() {
        JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setOpaque(true);
        lblNewLabel.setBackground(new Color(192, 192, 192));
        lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
        lblNewLabel.setIcon(dice[randNum]);
        lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
        
        return lblNewLabel;
    }
    

    which is interesting, but each time it's called, it will create a new instance of JLabel.

    Then in the constructor, you have...

    JLabel lblNewLabel = diceLbl();
    contentPane.add(lblNewLabel, BorderLayout.CENTER);
    

    which defines a local variable lblNewLabel which adds (the newly created instance) to the frame.

    But, lblNewLabel is undefined within the context of your ActionListener.

    Start by creating a instance variable (below the definition of verifiedNum)

    private JLabel lblNewLabel;
    

    Then modify the diceLbl method to only every create a single instance of the JLabel, something like...

        private JLabel diceLbl() {
            if (lblNewLabel == null) {
                lblNewLabel = new JLabel("");
                lblNewLabel.setOpaque(true);
                lblNewLabel.setBackground(new Color(192, 192, 192));
                lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
                lblNewLabel.setIcon(dice[randNum]);
                lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
            }
            return lblNewLabel;
        }
    

    Then, in your ActionListener you can simply do...

    diceLbl().setIcon(dice[verifiedNum]);