Totoro
Totoro

Reputation: 101

Label issues with GUI

I'm fairly new to Java and I am trying to make a GUI. This is the code in my GUI.java file. It contains a button and a label. When I click the button, the label is supposed to show "loading..." and enter a static void method in the Main class (in Main.java) called searcher and does stuff. After searcher is done, label becomes "".

Problem: Label doesn't change at all when I press press the button. Seems like neither the setText in the actionListener nor searcher() works. However, the other "stuff" I wanted it to do inside searcher() still works fine. I don't see any errors.

Note: If I try to call searcher() from the main it works fine.

GUI.java:

 public class GUI extends JFrame implements ActionListener{

    public JButton button = new JButton("Refresh!");
    public JLabel label = new JLabel("");

    public GUI(){
        Container pane = getContentPane();
        button.addActionListener(this); 
        button.setActionCommand("refresh");
        pane.add(button);
        pane.add(label);
    }
}
public void actionPerformed(ActionEvent e) {
    if ("refresh".equals(e.getActionCommand())) {
                label.setText("Loading...");
                Main.searcher(this, "", "");
                label.setText("");
            }
}

Main.java:

public class Main{ 
public static void searcher(GUI gu, String popup, String url) {
    gu.label.setText("Loading...");
    //do stuff
    gu.label.setText("");
}
public static void main(String[] args) {
    GUI gu = new GUI ();
}
}

EDIT: I've changed to code to use SwingWorker and propertylistener as suggested, but I'm having trouble now. Firstly, 'this' no longer refers to the GUI.. what should I pass in the searcher method to pass the current instance of class GUI?

I'm also getting this error and I'm not really sure how to fix it:

.\GUI.java:77: error: is not abstract and does not override abstract method propertyChange(PropertyChangeEvent) in PropertyChangeListener PropertyChangeListener propChangeListn = new PropertyChangeListener() {^

public void actionPerformed(ActionEvent e) {
            if ("refresh".equals(e.getActionCommand())) {
                label.setText("Loading...");
                SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
                    public Void doInBackground() throws Exception {
                        Main.searcher(this, "", "http://maple.fm/api/2/search?server=0");
                        return null;
                        }
                    };
                //worker.addPropertyChangeListener(new propertyChangeListener listener) {
                PropertyChangeListener propChangeListn = new PropertyChangeListener() {
                public void propertyChanged(PropertyChangeEvent pcEvt) {
                    if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
                        label.setText("");
                    }
                }
            };
            worker.addPropertyChangeListener(propChangeListn);
            worker.execute();
            }

Upvotes: 2

Views: 140

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

Yours is a classic Swing threading issue where you are tying the Swing event thread with a long-running process, preventing this thread from updating the GUI's graphics or from interacting with the user. The solution is the same as always -- use a background thread to do your long-running processing. If you used a SwingWorker for this, you could even add a PropertyChangeListener to it and then be notified when the worker has completed its task, allowing you to update the GUI with this information.

Google Concurrency in Swing and click on the first hit for more on this.

e.g.,

public void actionPerformed(ActionEvent e) {
    if ("refresh".equals(e.getActionCommand())) {
        label.setText("Loading...");

        // create a SwingWorker object
        final SwingWorker<Void, Void> worker = new Swingworker<Void, Void>() {

            // long running code would go in doInBackground
            public Void doInBackground() throws Exception {
                Main.searcher(...);
                return null;
            }
        }

        // add a listener to worker to be notified when it is done
        worker.addPropertyChangeListener(PropertyChangeListener listener) {
            public void propertyChanged(PropertyChangeEvent pcEvt) {

                // if the worker is done...
                if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
                    label.setText("");

                    // you will probably want to call get() on your worker here
                    // and catch any exceptions that may have occurred.
                }
            }
        }

        // it may seem counter-intuitive, but you need to start the worker with 
        // execute() *after* setting all the above code up.
        worker.execute();
    }
}

Upvotes: 3

Related Questions