1

Firstly, apologies but it would be really hard to reconstruct a SSCCE for this, though I think I can explain the situation considerably well and get my question across,

My situation is as thus: I have a JLabel that serves as a status indicator (e.g. that will display "Loading..." or "Ready") and I call the setText method in a MouseAdapter before another method is called to do the actual action. However, the JLabel text never changes, unless I do something like call JOptionPane.showMessageDialog() in which case the text does update.

So, does anybody have any suggestions as to how I can resolve this situation without doing something like displaying a message box for (what would be) no reason whatsoever?

Thanks in advance

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Andy
  • 3,600
  • 12
  • 53
  • 84
  • I'm sorry if this seems like bad advice, but have you tried calling `revalidate()` or `repaint()` on your frame after you change the label's text? – fireshadow52 Jan 18 '12 at 19:43
  • Oops. Disregard my previous comment. Make sure you aren't performing your task on the EDT as mentioned in the answers. – fireshadow52 Jan 18 '12 at 19:50
  • I think @fireshadow52's advice is good one to try out, it is better to use swingworker but if you are just prototyping you may try this first. – Ashwinee K Jha Jan 18 '12 at 20:04
  • @fireshadow52 No that is not bad advice. As a matter of fact, I did try calling those methods, but obviously it didn't achieve anything; but you didn't know that! AND AKJ, I'm not prototyping to be honest - I need a solution that is pretty much garenteed to work, so can you provide me with an answer/example in some form? – Andy Jan 18 '12 at 20:14
  • 1
    Scrap that last request for an example, @Unai Vive provided one and helped me! – Andy Jan 18 '12 at 20:54

2 Answers2

7

Make sure you don't run your task (your "Loading..." procedure) on the EDT (Event Dispatch Thread); if you do so, your GUI won't get updated.

You have to run your application code (unless it's very fast, say less than 100ms, no network access, no DB access, etc) on a separate thread. The SwingWorker (see javadocs) class might come handy for this purpose.

The EDT (e.g. code blocks inside user interface listeners) should only contain code for updating the GUI, operating on Swing components, etc. Everything else you should run on its own Runnable object.

--

EDIT: reponse to Andy's comment. Here's a raw example (written on the fly, it might have typos and such and might not run as-is) of how you can use the SwingWorker class

Put this in your mouse listener event or whatever makes your task start

//--- code up to this point runs on the EDT
SwingWorker<Boolean, Void> sw = new SwingWorker<Boolean, Void>()
{

    @Override
    protected Boolean doInBackground()//This is called when you .execute() the SwingWorker instance
    {//Runs on its own thread, thus not "freezing" the interface
        //let's assume that doMyLongComputation() returns true if OK, false if not OK.
        //(I used Boolean, but doInBackground can return whatever you need, an int, a
        //string, whatever)
        if(doMyLongComputation())
        {
            doSomeExtraStuff();
            return true;
        }
        else
        {
            doSomeExtraAlternativeStuff();
            return false;
        }
    }

    @Override
    protected void done()//this is called after doInBackground() has finished
    {//Runs on the EDT
        //Update your swing components here
        if(this.get())//here we take the return value from doInBackground()
            yourLabel.setText("Done loading!");
        else
            yourLabel.setText("Nuclear meltdown in 1 minute...");
        //progressBar.setIndeterminate(false);//decomment if you need it
        //progressBar.setVisible(false);//decomment if you need it
        myButton.setEnabled(true);
    }
};
//---code under this point runs on the EDT
yourLabel.setText("Loading...");
//progressBar.setIndeterminate(true);//decomment if you need it
//progressBar.setVisible(true);//decomment if you need it
myButton.setEnabled(false);//Prevent the user from clicking again before task is finished
sw.execute();
//---Anything you write under here runs on the EDT concurrently to you task, which has now been launched
Unai Vivi
  • 3,073
  • 3
  • 30
  • 46
  • Unfortunately, I am running the task in the EDT (silly me). I haven't really met `SwingWorker` before though; so could you give me an example please? Thanks. – Andy Jan 18 '12 at 19:54
  • @Andy I edited the answer adding a (not particularly beautiful) example. Hope it helps understand the mechanism – Unai Vivi Jan 18 '12 at 20:31
  • 1
    Thanks for the example, it really helped and know I have it working; possibly more importantly, I also have a better understanding of `SwingWorker`. Thanks again. – Andy Jan 18 '12 at 20:50
3

Do you call the setText() method from the EDT?

tilex
  • 1,744
  • 1
  • 17
  • 32
  • +1 you are right, that could be correct answer http://stackoverflow.com/questions/7943584/update-jlabel-every-x-seconds-from-arraylistlist-java/7944388#7944388 – mKorbel Jan 18 '12 at 19:49
  • OP says set text is getting invoked from mouse adapter, which should presumably be running on EDT. – Ashwinee K Jha Jan 18 '12 at 20:02
  • @AKJ Yes, the mouse adapter is running on the EDT, in answer to tilex's question as well. I'm really not to sure what to do though, can anybody please provide with me with some kind of an example? Please! – Andy Jan 18 '12 at 20:08
  • It doesn't matter about an example now, @Unai Vivi added one to his and now I have my program working how it should do. Thank you anyway. – Andy Jan 18 '12 at 20:53
  • You now have enough rep. to make comments. What you wrote was a comment, please enter it as such in future. – Andrew Thompson Jan 19 '12 at 03:24