Question

I am trying to change the icon (background) of a JLabel, but I am having an issue with the icon not updating. Whenever I tried lblStatusImg.setIcon(new ImageIcon(Brix_Updater_Module.class.getResource("/resources/fail.png"))); to change the JLabel in the main method, the compiler was first complaining that the variable lblStatusImg did not exist, so I moved it from the JFrame initialization method to a class level variable. After this, Eclipse complained that I was trying to reference a nonstatic method from static context, so I made lblStatusImg static. This made it possible for the program to compile, but the icon did not change whenever it was supposed to.

Since it's kind of hard to understand my problem here is a download link for an Eclipse workspace that demonstrates my problem. When you first open it, you will notice that there are some problems with it. They were left there on purpose to make it easier for you to see where I am having a hard time. If Eclipse asks you to make the items in question static, just do it and then run the program. You'll notice that it does not change the label icons as it should.

Since not all of you have Eclipse, here's the entire code from the workspace.

import java.awt.Component;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;

import java.awt.Font;

import javax.swing.SwingConstants;

import java.awt.Window.Type;
import java.io.BufferedOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Timer;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.ImageIcon;
import javax.swing.JButton;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;


public class StackOverflow_Image_Resource_Demo {

    private JFrame frmUpdate;
    JLabel lblStatusImg = new JLabel("");
    JButton btnUpdateComplete = new JButton("OK");

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    StackOverflow_Image_Resource_Demo window = new StackOverflow_Image_Resource_Demo();
                    window.frmUpdate.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        try {
            lblStatusImg.setIcon(new ImageIcon(StackOverflow_Image_Resource_Demo.class.getResource("success.png")));
            btnUpdateComplete.setVisible(true);
        }
        catch(Exception e)
        {
            Component frame = null;
            lblStatusImg.setIcon(new ImageIcon(StackOverflow_Image_Resource_Demo.class.getResource("/resources/fail.png")));
            JOptionPane.showMessageDialog(frame, "Update Failed", "Update Failed", JOptionPane.ERROR_MESSAGE);
            System.exit(1);
        }
    }

    /**
     * Create the application.
     */
    public StackOverflow_Image_Resource_Demo() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frmUpdate = new JFrame();
        frmUpdate.setType(Type.UTILITY);
        frmUpdate.setTitle("StackOverflow Image Resource Issue Demo");
        frmUpdate.setBounds(100, 100, 450, 300);
        frmUpdate.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmUpdate.getContentPane().setLayout(null);

        //JLabel lblStatusImg = new JLabel(""); - Commented out when I made lblStatusImg class level.
        lblStatusImg.setIcon(new ImageIcon(StackOverflow_Image_Resource_Demo.class.getResource("/resources/updating.gif")));
        lblStatusImg.setBounds(10, 22, 414, 97);
        frmUpdate.getContentPane().add(lblStatusImg);

        //JButton btnUpdateComplete = new JButton("OK"); - Commented out when I made btnUpdateComplete class level.
        btnUpdateComplete.setVisible(false);
        btnUpdateComplete.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent arg0) {
                System.exit(1);
            }
        });
        btnUpdateComplete.setBounds(170, 179, 89, 23);
        frmUpdate.getContentPane().add(btnUpdateComplete);
    }
}

Here is a newer version of my code that updates the image, but doesn't fully load the UI until everything else is done.

import java.awt.Component;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;

import java.awt.Font;

import javax.swing.SwingConstants;

import java.awt.Window.Type;
import java.io.BufferedOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Timer;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.ImageIcon;
import javax.swing.JButton;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;


public class StackOverflow_Image_Resource_Demo {

    private JFrame frmUpdate;
    JLabel lblStatusImg = new JLabel("");
    JButton btnUpdateComplete = new JButton("OK");

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    StackOverflow_Image_Resource_Demo window = new StackOverflow_Image_Resource_Demo();

try { lblStatusImg.setIcon(new ImageIcon(StackOverflow_Image_Resource_Demo.class.getResource("success.png"))); btnUpdateComplete.setVisible(true); } catch(Exception e) { Component frame = null; lblStatusImg.setIcon(new ImageIcon(StackOverflow_Image_Resource_Demo.class.getResource("/resources/fail.png"))); JOptionPane.showMessageDialog(frame, "Update Failed", "Update Failed", JOptionPane.ERROR_MESSAGE); System.exit(1); } window.frmUpdate.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }

    /**
     * Create the application.
     */
    public StackOverflow_Image_Resource_Demo() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frmUpdate = new JFrame();
        frmUpdate.setType(Type.UTILITY);
        frmUpdate.setTitle("StackOverflow Image Resource Issue Demo");
        frmUpdate.setBounds(100, 100, 450, 300);
        frmUpdate.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmUpdate.getContentPane().setLayout(null);

        //JLabel lblStatusImg = new JLabel(""); - Commented out when I made lblStatusImg class level.
        lblStatusImg.setIcon(new ImageIcon(StackOverflow_Image_Resource_Demo.class.getResource("/resources/updating.gif")));
        lblStatusImg.setBounds(10, 22, 414, 97);
        frmUpdate.getContentPane().add(lblStatusImg);

        //JButton btnUpdateComplete = new JButton("OK"); - Commented out when I made btnUpdateComplete class level.
        btnUpdateComplete.setVisible(false);
        btnUpdateComplete.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent arg0) {
                System.exit(1);
            }
        });
        btnUpdateComplete.setBounds(170, 179, 89, 23);
        frmUpdate.getContentPane().add(btnUpdateComplete);
    }
}
Was it helpful?

Solution

Two things come to find. The first is, as you say, you're trying to reference a non-static variable from a static context.

The second is, you don't seem to understand how threading works...

Basically, main is typically executed within the "main" thread (when executed by the JVM).

You then use EventQueue.invokeLater. Which as, the name suggests, will execute the Runnable "later"...at some time in the future...

        EventQueue.invokeLater(new Runnable() {
            public void run() {

You then try and change the the icon (let's pass over the non-static reference for a momement)...but lblStatusImg won't have been initialized nor is it likely to have been displayed, as the Runnable has not yet been executed, meaning, even if you didn't run into a NullPointerException, you won't see the change...

You can test by adding a System.out in your Runnable and before the first lblStatusImg.setIcon call in the main method.

What you should do is...

  1. Move the "status" change change to within the Runnable context.
  2. Provide a setStatus method that is capable of changing the label and UI content as required based on the provide status

For example...

public static final int SUCCESS = 0;
public static final int FAIL = 0;

//...

public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    StackOverflow_Image_Resource_Demo window = new StackOverflow_Image_Resource_Demo();
                    // This e
                    window.frmUpdate.setVisible(true);

                    window.setStatus(StackOverflow_Image_Resource_Demo.SUCCESS);
                } catch (Exception e) {
                    e.printStackTrace();
                    Component frame = null;
                    window.setStatus(StackOverflow_Image_Resource_Demo.FAIL);
                    JOptionPane.showMessageDialog(frame, "Update Failed", "Update Failed", JOptionPane.ERROR_MESSAGE);
                    window.dispose();
                }
            }
        });
    }

You should avoid exposing instance fields as public and instead, provide methods that either change their state indirectly (such as setStatus) or directly (setStatusIcon). In this case, I prefer the first method as this allows the class to determine what a change in status actually means.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top