Swing threading model - Java SE (Archived)

The single thread model for Swing really places a burden on developers, and even when we manage to figure out how to make it work we end up with some very messy code.
You can't block the event dispatch thread, so you fork a new thread to deal with a slow task... but then your slow task needs to update the UI occasionally, so you have to deal with SwingUtilities.invokeLater(), or in some cases  invokeAndWait.  But invokeAndWait can cause a deadlock, so
you've gotta be careful with that.
Yes I know about SwingWorker- it's an OK solution for the simple case.  But in any moderate to complicated Swing app it's very easy to get lost jumping into and out of the event dispatch thread.
Can we find some way to fix this?  The modal dialog seems to do it- it blocks the calling thread, yet allows the GUI to remain responsive.  I believe this is what the Foxtrot folks are using.  The threading issue is a major hurdle to good, responsive GUI app development, and a standard solution is really needed.
Thanks for listening.

Yes, the problems of EDT blockage that you described can be solved using Foxtrot. We are planning to export some public APIs in Mustang that will allow you to do the same.
As for threading model, it can not be changed - it will be one of the most backward-incompatible changes. So, whenever you want to update Swing GUI, you must use invokeLater.

From where I am standing the concept of one thread that manages swing objects is just fine;  it really is a good concept!
Thing you are missing is a layer on top; a simple way to manage actions and workers.  I see solutions popping up on all sides; some better then others.
I really doubt the JDK should solve this problem; the various open source libraries will do a much better job over time.
I made a full-scale solution myself (part of the UICompiler project) which I (naturally) think is better then all te others;  competition is healthy :)

YES yes yes.
Management of actions, long running actions, actions on popups sensitive to JTree, etc.  Management of actions relating to plugins, etc.
Its a common problem which every complex app has to deal with.  I'd hesitate to say what the best 'solution' is, and I would hesitate even more regarding putting a less than ideal solution into the JDK, but its definately worthwhile.
Definately consider putting Swixml (or a derivative) into the JDK and see how it could be extended further.  Adding SWT support to Swixml may 'satisfy' the SWT crowd.

> Definately consider putting Swixml (or a derivative)
> into the JDK and see how it could be extended
> further.  Adding SWT support to Swixml may 'satisfy'
> the SWT crowd.
Why should it be placed in the JDK? Whats wrong with using an external library and shipping that to your clients?

I was thinking about that a while back.
In the current environment, something gains credibility being included in the JDK.  At the same time there is the problem that the JDK seems to grow.  Deprecated stuff never gets removed, etc.
Maybe some sort of 'application stack' of some sort.  What is really wanted from a technology point of view is good documentation, active development and support of issues/problems.  At the moment it seems as if 'side' projects/experiments get mothballed after a while.

Hmm... mincing my words.
Maybe some sort of 'application stack' should be pushed by Sun.  Include in this stack things like Java Help, Swixml, etc.

My thoughts exactly;
see: "Great Suggestion!" in: http://forums.java.net/jive/thread.jspa?messageID=2407

> From where I am standing the concept of one thread
> that manages swing objects is just fine;  it really
> is a good concept!
Completely agree. Why make it much more complex than necessary. Own frameworks arise automatically - like your UICompiler project.

Hello all.
> Yes I know about SwingWorker- it's an OK solution for
> the simple case.  But in any moderate to complicated
> Swing app it's very easy to get lost jumping into and
> out of the event dispatch thread.
I am glad to see that in jdk1.6 javax.swing.SwingWorker was introduced.
I'm new here, so I'm still a little bit confused about projects and I don't know if
this (I mean: https://swingworker.dev.java.net/servlets/ProjectDocumentList ) is exactly the jdk1.6 introduced classes.
In my experience a useful scheduling for the events is "forget the old events and do the current one". This makes possible to write very responsive interface in case you need e.g. to show something that depends on mouse position: often is NOT necessary to process the entire (maybe long) event queue. If the task to be performed is heavy, "forgetting old events" is a very good solution (if it is possible, of course!)
I successfully implemented this scheduling for an application I developed, but I had to do my custom threading (in fact with the "old" SwingWorker you have to do a similar work by yourself).
It is not clear (to me) if the use of ThreadPoolExecutor in the "new" SwingWorker is flexible enough to make the "forget the old events and do the current one" scheduling immediate. If this is NOT the case, I suggest to add such a feature. This will simplify the building of responsive GUI, and will improve java reputation, too often believed  a "too slow language".
Of course, if something is needed, I am happy to contribute, eg writing and submitting my code (where?)
Bye,
;Davide

Hi,
>In my experience a useful scheduling for the events is "forget the old events and do the current one". This makes possible to write very responsive interface in case you need e.g. to show something that depends on mouse position: often is NOT necessary to process the entire (maybe long) event queue. If the task to be performed is heavy, "forgetting old events" is a very good solution (if it is possible, of course!)
There are two things which might become obsolete.
1. background task could be obsolete itself.
For example background task is weather forecast for 12pm. At 12pm this background task becomes obsolete.
If it is not done by 12pm one wants to cancel it.
SwingWorker can be implemented to support cancellation.( there is an example in the documentation )
One can cancel SwingWorker explicitly or have custom ExecutorService which will support cancellation of all currently submitted tasks and run SwingWorkers in this ExecutorService.
2. partial result produced by the background task could be obsolete.
For example background task continuously reads data from thermometer and displays result in some swing component.
Say we read data from thermometer faster than we display it. One might want to display the latest reading only.
Using SwingWorker one can implement this like:
[code]
doInBackground() {
    while(true) {
        publish(getThermometerData());
    }
}
process(Integer... chunks) {
    label.setText(chunks[chunks.length - 1]);
}
[/code]
> I'm new here, so I'm still a little bit confused about projects and I don't know if this (I mean: https://swingworker.dev.java.net/servlets/ProjectDocumentList ) is exactly the jdk1.6 introduced classes.
At this point there is only one difference : SwingWorker from swingworker.dev.java.net implements Runnable and Future where is SwingWorker from jdk1.6 implements RunnableFuture (RunnableFuture implements Runnable and Future and was introduced since jdk1.6)
Thanks,
  Igor

How about something like this (simplified):
you define your app-level commands w/some interface
interface ICommand {
  void run(IAnswer a);
}
And your command replies to Swing via IAnswer:
interface IAnswer {
....public void reportProgress(float percent);
....public void end(Object result);
}
To run commands you use  a dispatcher..
class Dispatcher {
....public void dispatch(ICommand c, IAnswer a) {
........Thread t = new Thread(
............new CmdWrapper(c, new AnswerWrapper(a)));
........t.start();
....}
....private static class CmdWrapper implements Runnable {
........public CmdWrapper(ICommand c, IAnswer a) {
............_cmd = c; _answer = a;
........}
........public void run() {
............_cmd.run(_answer);
........}
....}
....private static class AnswerWrapper implements IAnswer {
........public AnswerWrapper(IAnswer a) {
............_answer = a;
........}
........public void reportProgress(float percent) {
............SwingUtilities.invokeLater(new Runnable() {
................public void run() {
...................._answer.reportProgress(porcentaje);
................}
............});
........}
........public void end(Object result) {
............SwingUtilities.invokeLater(new Runnable() {
................public void run() {
...................._answer.end(result);
................}
............});
........}
....}
}
Now in your UI code just run something like:
public MyActionListener implements ActionListener {
..public void actionPerformed(ActionEvent e) {
....dispatcher.dispatch(factory.get(e.getActionCommand()),
......new AnswerAdaptor() {
........public void end(Object result) {
............// update UI
........}
....});
..}
} 
Advantages:
- All commands run on their own thread.. everything is super responsive
- All answers run on Swing thread
- ICommand w/ a different dispatcher works on web apps too so you don't have to change any model code
- One mechanism.. very little specialized code
Caveats:
- Your model code should be thread safe (probably not so bad in a GUI app)

Alternatively, if you don't want to bother to make the model threadsafe.. just run a single background thread and queue commands in the dispatcher.

Thanks to both for reply.
> There are two things which might become obsolete.
> 1. background task could be obsolete itself.
> For example background task is weather forecast for
> 12pm. At 12pm this background task becomes obsolete.
>
> If it is not done by 12pm one wants to cancel it.
>
> SwingWorker can be implemented to support
> cancellation.( there is an example in the
> documentation )
Ok (I think this will be used mainly with "cancel" buttons).
> One can cancel SwingWorker explicitly or have custom
> ExecutorService which will support cancellation of
> all currently submitted tasks and run SwingWorkers in
> this ExecutorService.
This is similar to what I have in mind...
> 2. partial result produced by the background task
> could be obsolete.
> For example background task continuously reads data
> from thermometer and displays result in some swing
> component.
This in interesting, but is another story...
Consider the following example, that is similar to the one I solved: depending on the mouse position on a image (here simple the "Move the mouse here" words) I draw something on another panel (here simply the mouse x coordinate). The heavy calculation on the image are simulated with the sleep().
In this situation the "standard" SwingWorker behavior, is (in some way) worse than the simpler code in AWT thread: try to move the mouse a lot!
I don't understand if there is a *simple* way to use SwingWorker in order to obtain what I want: process only the last available event.
The solution I used for my application: my own class (which can be used like SwingWorker) that start a thread which process only the last event. There is not any queue. My class is simple, but is not completely trivial: a little bit of thread synchronization is required.
I think that a *simple* way to handle similar situation should exist in SwingWorker, don't you?
If so (and if there isn't any *simple* alternative yet) I think that I can contribute with my code to the current SwingWorker implementation.
Bye,
;Davide
import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import javax.swing.SwingWorker;
public class mySwingWorkerExample {
     public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
                 public void run() {
                   createAndShowGUI();
              }
          });
     }
     private static void createAndShowGUI() {
          //Create and set up the window
          JFrame frame = new JFrame("mySwingWorkerExample");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          JPanel newContentPane = buildContent();
          newContentPane.setOpaque(true); //content panes must be opaque
          frame.setContentPane(newContentPane);
          //Display the window.
          frame.pack();
          frame.setResizable(false);
          frame.setVisible(true);
     }
     private static JPanel buildContent() {
          JPanel ritorna = new JPanel();
          JTabbedPane tab_pan = new JTabbedPane();
          for (dispatch_policies policy : dispatch_policies.values())
          {
               // construct the container
               JPanel panel = new JPanel(new java.awt.GridLayout(3,1));
               
               // construct the description
               JTextField descr = new JTextField(policy.getDescription());
               descr.setEditable(false);
               descr.setHorizontalAlignment(JTextField.CENTER);
               panel.add(descr);
               
               // construct the responce field and assign to the listener
               JTextField responce = new JTextField("50");
               responce.setEditable(false);
               responce.setHorizontalAlignment(JTextField.CENTER);
               panel.add(responce);
               policy.setTheResultIn(responce);
               
               // construct the active field and activate the listener
               JTextField mouseHere = new JTextField("Move the mouse here");
               mouseHere.setEditable(false);
               mouseHere.setHorizontalAlignment(JTextField.CENTER);
               panel.add(mouseHere);
               mouseHere.addMouseMotionListener(policy);
          
               panel.setPreferredSize(new java.awt.Dimension(400,300));
               tab_pan.add(policy.toString(), panel);
          }
          
          ritorna.add(tab_pan);
          return ritorna;
     }
}
                     
enum dispatch_policies implements MouseMotionListener {
     EXAMPLE {
            void doSomething(MouseEvent e, JTextComponent myTxt) {
               myTxt.setText(String.valueOf(e.getX()));
          }
          
          public String getDescription() {
               return "This is good for fast elaborations " +
                    "in the AWT thread...";
          }
     },
     AWT_STD {
            void doSomething(MouseEvent e, JTextComponent myTxt) {
               sleep();
               myTxt.setText(String.valueOf(e.getX()));
          }
          
            public String getDescription() {
               return "But what's about if a heavy " +
                    "task is needed?";
          }
     },
     NEW_THREAD {
            void doSomething(final MouseEvent e, final JTextComponent myTxt) {
               final SwingWorker worker = new SwingWorker() {
                    public String doInBackground() {
                         sleep();
                         return "well done!";
                    }
                    protected void done() {
                         myTxt.setText(String.valueOf(e.getX()));
                    }
               };
               worker.execute();
          }
          
            public String getDescription() {
               return "Nice, but a the new thread " +
                    "will execute ALL the events.";
          }
     };
     private static int delayTime = 500;
     private JTextComponent myTxt = new JTextField();
     public void setTheResultIn(JTextComponent who) {
          myTxt = who;
     }
      
     public void mouseMoved(MouseEvent e) {
          doSomething(e, myTxt);
     }
     public void mouseEntered(MouseEvent e) {}
     public void mouseExited(MouseEvent e) {}
     public void mouseClicked(MouseEvent e) {}
     public void mouseDragged(MouseEvent e) {}
     
     private static void sleep() {
          try {
               Thread.sleep(delayTime);
          }
          catch(InterruptedException e)
          {
               //sleep something less, but tell me why
               e.printStackTrace();
          }
     }
     public abstract String getDescription();
     abstract void doSomething(MouseEvent e, JTextComponent myTxt);
}

Hi,
>Consider the following example, that is similar to the one I solved: depending on the mouse position on a image (here simple the "Move the mouse here" words) I draw something on another panel (here simply the mouse x coordinate). The heavy calculation on the image are simulated with the sleep().
>In this situation the "standard" SwingWorker behavior, is (in some way) worse than the simpler code in AWT thread: try to move the mouse a lot!
I don't understand if there is a *simple* way to use SwingWorker in order to obtain what I want: process only the last available event.
SwingWorker has internal ThreadPoolExecutor. There are a number of worker threads available in this ExecutorService. SwingWorker.doInBackground is executed in a worker thread. Multiple SwingWorkers can run in parallel. If internal ThreadPoolExecutor can not run SwingWorker right away it queues it and run as soon as there is a worker thread available.
Your example starts new SwingWorker on every mouse event. All of them are executed and display result. Because there are so many SwingWorkers submitted for execution it takes so much time to finally see the result. (By the way the result one finally see on the screen is not necessarily produced by the last SwingWorker. There is no guarantee that SwingWorkers finish in the same order they are executed.)
Moving mouse obsoletes all the previously running background tasks. For this case one needs only last SwingWorker to finish and all others can be canceled as soon as the new one starts. In fact one needs no more than one SwingWorker running at all.
to post code with indentation one can wrap code
into [b][[/b]code[b]] [[/b]/code[b]][/b] brackets.
[code]
import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import javax.swing.SwingWorker;
public class mySwingWorkerExample {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
    private static void createAndShowGUI() {
        /* Create and set up the window */
        JFrame frame = new JFrame("mySwingWorkerExample");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel newContentPane = buildContent();
        newContentPane.setOpaque(true); /* content panes must be opaque */
        frame.setContentPane(newContentPane);
        /* Display the window. */
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
    }
    private static JPanel buildContent() {
        JPanel ritorna = new JPanel();
        JTabbedPane tab_pan = new JTabbedPane();
        for (dispatch_policies policy : dispatch_policies.values()) {
            /* construct the container */
            JPanel panel = new JPanel(new java.awt.GridLayout(3, 1));
            /* construct the description */
            JTextField descr = new JTextField(policy.getDescription());
            descr.setEditable(false);
            descr.setHorizontalAlignment(JTextField.CENTER);
            panel.add(descr);
            /* construct the responce field and assign to the listener */
            JTextField responce = new JTextField("50");
            responce.setEditable(false);
            responce.setHorizontalAlignment(JTextField.CENTER);
            panel.add(responce);
            policy.setTheResultIn(responce);
            /* construct the active field and activate the listener */
            JTextField mouseHere = new JTextField("Move the mouse here");
            mouseHere.setEditable(false);
            mouseHere.setHorizontalAlignment(JTextField.CENTER);
            panel.add(mouseHere);
            mouseHere.addMouseMotionListener(policy);
            panel.setPreferredSize(new java.awt.Dimension(400, 300));
            tab_pan.add(policy.toString(), panel);
        }
        ritorna.add(tab_pan);
        return ritorna;
    }
}
enum dispatch_policies implements MouseMotionListener {
   
    EXAMPLE {
        void doSomething(MouseEvent e, JTextComponent myTxt) {
            myTxt.setText(String.valueOf(e.getX()));
        }
        public String getDescription() {
            return "This is good for fast elaborations "
                    + "in the AWT thread...";
        }
    },
    AWT_STD {
        void doSomething(MouseEvent e, JTextComponent myTxt) {
            sleep();
            myTxt.setText(String.valueOf(e.getX()));
        }
        public String getDescription() {
            return "But what's about if a heavy " + "task is needed?";
        }
    },
    NEW_THREAD {
        void doSomething(final MouseEvent e, final JTextComponent myTxt) {
            if (worker != null) {
                worker.cancel(true);
            }
            worker = new SwingWorker() {
                public String doInBackground() throws Exception {
                    sleep();
                    return "well done!";
                }
                protected void done() {
                    if (!isCancelled()) {
                        myTxt.setText(String.valueOf(e.getX()));
                    }
                }
            };
            worker.execute();
        }
        public String getDescription() {
            return "Nice, but a the new thread "
                    + "will execute ALL the events.";
        }
    };
    private static SwingWorker worker = null;
   
    private static int delayTime = 500;
    private JTextComponent myTxt = new JTextField();
    public void setTheResultIn(JTextComponent who) {
        myTxt = who;
    }
    public void mouseMoved(MouseEvent e) {
        doSomething(e, myTxt);
    }
    public void mouseEntered(MouseEvent e) {
    }
    public void mouseExited(MouseEvent e) {
    }
    public void mouseClicked(MouseEvent e) {
    }
    public void mouseDragged(MouseEvent e) {
    }
    private static void sleep() {
        try {
            Thread.sleep(delayTime);
        } catch (InterruptedException e) {
            /* we can be interrupted if cancel is invoked */
        }
    }
    public abstract String getDescription();
    abstract void doSomething(MouseEvent e, JTextComponent myTxt);
}
[/code]
Thanks,
  Igor
Message was edited by: idk

Related

Frame resizing

I wonder if this is just me being stupid but...
I have a swing gui which is two panels; the top one lets the user set query parameters to query a database, the lower one contains a JTable showing teh results.
Problem 1:
Sometimes (and not reproducibly), the lower panel disappears. I think this is related to the user resizing the enclosing frame while the query results are being populated (i.e. a new TableModel is being created).
Problem 2:
In an effort to overcome problem 1, I have added a setResizable(false) before I send the query off, and setResizable(true) when the table model has been built. This works (in that it disallows resizing), but from a usability POV it sucks. On each call above, the entire frame disappears for a fraction of a second, and then reappears. This is clearly disconcerting for the user. Has anyone else come across this prblem and/or can suggest a solution
Try executing the query in a separate Thread. 
Yes, I've seen the same behaviour. Theres a new Layout Manager called SpringLayout that I'm going to try some day when I have lots of time. It appears to provide the kind of control I need in these cases, but it makes the GridBag look simple. If you try it and get it working please post the results. 
Two thoughts. First, I have done close to this same thing and it seems to work better than your results. The main difference I see is that I don't replace the table model. I extend the table model and add a setData() method which overlays the underlying data and then calls fireTableDataChanged().
Second, I just learned a couple of days ago it's not a good idea to update the GUI from elsewhere than the event thread. Most of the time this is automatic (listeners & such). However, if your query and update is in it's own thread, you may have this problem. Use SwingUtilities.invokeLater() to get the update on the event thread. 
The query is already running in a separate thread - but the results processing chews up large amounts of CPU (loadsa XML parsing - lovely).
As for different layout mgrs - I will have a look. Finally decided to upgrade from 1.3.1 to 1.4.1 company wide today. This was my first hack. 
Its definitely a LayoutManager problem as I could change the behaviour by choosing different locations in a BorderLayout. The SpringLayout tutorial
http://java.sun.com/docs/books/tutorial/uiswing/layout/spring.html
Has some interesting looking stuff.
Thanks BB -
That may be it. I will try that out. I have all the updates running from the event thread. In the code that repopulates the model, I clear the old model and repopulate. This is lagacy code, but I here it is...  public void run() {
      // Clear the current model
      if (model != null) {
       model.clear();
      }
      modelIndex.clear();
      // Parse the MSB summary which should have already been generated from the query.
      try {
       DocumentBuilderFactory factory =
           DocumentBuilderFactory.newInstance();
      
       DocumentBuilder builder = factory.newDocumentBuilder();
       doc = builder.parse( new File(MSB_SUMMARY));
       docIsNull = false;
      
      }
      catch (SAXException sxe) {
       Exception  x = sxe;
       if (sxe.getException() != null)
           x = sxe.getException();
       logger.error("SAX Error generated during parsing", x);
      
      }
      catch(ParserConfigurationException pce) {
       logger.error("ParseConfiguration Error generated during parsing", pce);
      }
      catch (IOException ioe) {
       logger.error("IO Error generated attempting to build Document", ioe);
      }
     
      // If the document exists, build a new model so we don't need to keep
      // going back to the XML.
      if (doc != null) {
       logger.info("Building new model");
       model = XmlUtils.getNewModel(doc, ROOT_ELEMENT_TAG);
       // Move the columns around to the current bitset.
       adjustColumnData(currentBitSet);
       if (model != null) {
           // Create an internal map of projects to MSBs
           for (int i=0; i<model.size();i++) {
            modelIndex.add(((XmlUtils.MSBTableModel)model.elementAt(i)).getProjectId());
           }
       }
       _projectId = "all";
       logger.info("Result contained "+getRowCount()+" MSBs in "+modelIndex.size()+" Projects");
      }
  } 
I would try to shoot for something like thisfinal XMLData newData = XmlUtils.getNewModel(doc, ROOT_ELEMENT_TAG);
final MyModel tmpModel = (MyModel)myTree.getModel();
SwingUtilities.invokeLater(new Runnable() {
  public void run() {
    tmpModel.setData(newData);
  }
}
class MyModel extends AbstractTableModel {
  XMLData currentData;
  public Object getValueAt(int row, int col) {
     switch (col) {
       case 0: return currentData.get(i).getTitle();
     ...
    }
  }
  public void setData(XMLData NewData) {
    currentData = NewData;
    fireTableDataChanged();
  }
}
You could also minimize the flash by moving the clear() calls down to after the processing is done. 
I just figured you already had the DB stuff in another thread. Just remember to use invokeLater to get the results back into your JTable. You can update the model from your DB thread but the firexxx methods do not create events that run in the Event Dispatch Thread when they are run from another thread.
Just thought I would do some testing. Code is below. I am running java 1.4.1_05 on RedHat 9. The flasing is really really noticeable. Anyone know if I can just catch "resize events" and ignore them?
import javax.swing.*;
import java.awt.event.*;
import java.awt.FlowLayout;
public class Test extends JFrame {
    public Test() {
     // Add a window listener and a few buttons, just so repaint
     // has something to do
     getContentPane().setLayout(new FlowLayout());
     for ( int i=0; i<5; i++) {
         JButton button = new JButton (""+i);
         button.addActionListener( new ActionListener () {
              public void actionPerformed (ActionEvent e) {
               resize();
              }
          });
         getContentPane().add(button);
        
     }
     addWindowListener( new WindowAdapter () {
          public void windowClosing(WindowEvent e) {
              System.exit(0);
          }
         });
     validate();     
     setVisible (true);
    }
    private void resize() {
     setResizable (false);
     setResizable(true);
    }
    public static void main (String [] args) {
     Test t = new Test();
    }
} //end of public class Test 
And more testing...
Using Java 1.3.1 on either RH9 or RH7 makes the problem go away. Interesting eh. 
<bump> just 'cos it used to work and now it don't. Grrrrrrr 
When you say the table disappears, does it get very tiny or does it stay the correct size but turn grey. I posted a question about the second behaviour, in a case that involved a JTable, but in mine a JFrame in another java app froze. The consensus was that its a graphics problem but the last reply said that there are new graphivs problems in 1.4
http://forum.java.sun.com/thread.jsp?forum=31&thread=445837 
I mean the table disappears - no resizing willl ever bring it back. Even submitting a new query does not cause it to reappear - the table model is built and all my debugging leads me to believe that the data gets added, but the table itself has just disappeared into X oblivion.

Modality..what is it good for (absolutely nooothing)

Alrighty. Here's some code that demonstrates that the focus manager for 1.3 is good for nothing if not nothing.
Run the program. 2 frames appear. Click "Button 1" in the first frame. A modal dialog appears. Now, click the non-selected frame from the taskbar (I'm assuming you're using winblows 95+) so that the frame you DIDN'T click "Button 1" in gets the focus. Notice that using the mouse does nothing, but if you hit TAB you're able to focus over either of the buttons and press them with the "Enter" key, including opening up another modal dialog.
In other words if you have 2 frames in 1 JVM, 1 of which has a modal dialog open, you can still use the keyboard in the other.
This will cause problems in my application...so is there a recommended workaround for this bug?
Aaron
======================================================================
package PrintTest;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.table.*;
public class PrintTest extends JFrame
{
JDialog dialog = new JDialog(this);
JButton button1 = new JButton("Button 1");
JButton button2 = new JButton("Button 2");
public PrintTest()
{
}
public void show()
{
Container c = getRootPane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
c.setLayout(null);
c.add(button1);
c.add(button2);
setSize(300, 200);
button1.setSize(100, 25);
button2.setSize(100, 25);
button1.setLocation(0, 0);
button2.setLocation(110, 0);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
dialog.setSize(100, 100);
dialog.setTitle("Modal dialog");
dialog.setModal(true);
dialog.show();
}
});
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
getToolkit().beep();
}
});
super.show();
}
public static void main(String[] args)
{
try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception ex) {}
PrintTest t = new PrintTest();
t.setLocation(0, 0);
t.show();
t = new PrintTest();
t.setLocation(500, 0);
t.show();
ofcourse the simplest solution is declare your dialog as static.
and
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
/****************************************/
if(dialog.isShowing())return;
/****************************************/
....
}
});
interstinng bug ..i was trying to figure out how this happening .. 
I'm working on an enormous application. All dialogs inherit the same base class just as all frames do. I'm looking for a way to block keyboard input there.
I need to know how you can tell if a frame should be blocked due to some modal dialog being open.
Aaron 
Hi StarTurtle,
I am experiencing this same bug in my application. Fortunately it's not a show stopper yet.
Have you check the bug reports? I will definitely vote for this one.
Regards,
Nick G.
Hi StarTurtle,
I am experiencing this same bug in my application.
Fortunately it's not a show stopper yet.
Have you check the bug reports? I will definitely
vote for this one.
Regards,
Nick G.Yeah, I've found similar bugs. I didn't know whether or not to submit this one. 
It works okay for me...don't know why but it does.
I can select the other window through the taskbar, but I can't focus on the buttons. Neither with the mouse or by tabbing to them. 
Hi again , i can thin of another woraround that would defnetly work.
1.) intead of adding an anonymous actionListener create an inner class for the action lystener say MyActionlistener
and then just before u pop the dialog what u could do is use the
removeActionListner(myActionListener)and once the dialog action is complete set it back by
addActionListener(myActionListener) 
Hi again , i can thin of another woraround that would
defnetly work.
1.) intead of adding an anonymous actionListener
create an inner class for the action lystener say
MyActionlistener
and then just before u pop the dialog what u could do
is use the
removeActionListner(myActionListener)and once the dialog action is complete set it back by
addActionListener(myActionListener)There are an untold number of dialogs in this application. I can't possibly go apply a fix for each one of them, that would be too bug-prone. I need a fix-one-fix-all solution. 
extend your dialog to activate / inactivate action listeners! that should be simple .
extend your dialog to activate / inactivate action
listeners! that should be simple .It's not one dialog I have to wory about, but probably about 50 or more (plus frames). Like I said this is a huge application with lots of frames and dialogs. I can't possibly give an event listener to each and every component in the application.
I need to be able to emulate for a frame to believe a modal dialog is open so that it cannot recieve the focus by any means. 
I haven't had the problems you speak of, but perhaps I haven't tried hard enough :-)
However, I too have found the standard dialog modality to be a problem on WinXX platforms, more to do with losing windows and not being able to easily get them back. Anyway, a better solution might be to put your own event processor into the awt event queue. I do this to manage dialog modality myself, which has the added benefit that yo can still move parent windows around while a "modal" dialog is showing.
First, here's my event processor:
static private class EventProcessor extends EventQueue
{
  public EventProcessor()
  {
    Toolkit.getDefaultToolkit().
    getSystemEventQueue().push(this);
  }
  protected void dispatchEvent(AWTEvent e)
  {
    boolean consumed = false;
    int id = e.getID();
    if((id == MouseEvent.MOUSE_PRESSED) ||
       (id == MouseEvent.MOUSE_RELEASED) ||
       (id == KeyEvent.KEY_PRESSED) ||
       (id == KeyEvent.KEY_RELEASED))
    {
      consumed = AnyDialog.raiseActiveDialog(e);
    }
    if (!consumed)
    {
      if (Globals.process__ != null && Globals.awtSync__)
      {
        synchronized(Globals.process__)
        {
          super.dispatchEvent(e);
        }
      }
      else
      {
        super.dispatchEvent(e);
      }
    }
  }
}You just new() this somewhere appropriate to get it on the queue. The method raiseActiveDialog() looks like this:
public static boolean raiseActiveDialog(AWTEvent e)
{
  boolean ret = false;
          
  if (activeDialogs__.entries() != 0)
  {
    DialogF d = (DialogF)activeDialogs__.get(activeDialogs__.entries() - 1);
    Container c = d.getComponent();
    Object source = e.getSource();
    JWindow wSource = (source instanceof JWindow) ? (JWindow)source : null;
    if (c == source ||
       popupClass__.isInstance(source) ||
       (wSource != null && c == wSource.getOwner())) // this last one for JDK1.4
      return false;
    if (!d.isModal())
      return false;
    d.show(false);
    ret = true;
  }
  return ret;
}The gist of it is that the array activeDialogs__ contains my active dialogs and the last one is assumed to be the one to which the focus is directed. If the event comes from that dialog (or a popup associated with it) then all well and good and we dispatch as normal. Otherwise we just show that dialog again (to bring it to the front)
In the java sense, all dialogs are non-modal but I wrap my JComponents in classes of my own for various reasons (generally better than subclassing) and implement my own modal flag there, but I digress. A dialog gets entered/removed from activeDialogs__ by capturing the ACTIVATED/OPENED/DEICONIFIED events and similarly the CLOSED/CLOSING/ICONIFIED as well as overriding hide()
Hope that helps
--
GUIs and much more in XML: http://www.inqwell.com/tech/toc.htm
I appreciate the suggestions for workarounds. Since this isn't a show-stopper for my app (yet), I can ignore it.
But, I still think this is a bug, and should be fixed by Sun on a global scale.
For me, standard dialogs work modally. But if I provide my own container for the contents, then it does not work. I presume it's related to the event handling (as mentioned in this thread). But a workaround shouldn't be the solution (perhaps only in the interum).
I don't have the time right now to create a simple app to submit in the bug parage. If someone does, please respond to this thread and I will vote for it.
Regards,
Nick G. 
tsanders,
I like your ideas about creating your own event processor, but how do you mimic the blocking behavior of Sun's modal dialogs using your technique? I am struggling with this. I have been trying to overwrite the show() method for all my dialogs so if it is running in the event processing thread when it comes into show it will continue to dispatch events. here is my rather messy code that is doing that.
public void show() {
    try {
        if(isWFMModal() && isShowing.isFalse()) {
            keepBlocking.setValue(true);
            if(SwingUtilities.isEventDispatchThread()) {
                super.show();
                EventQueue eventQueue = com.eds.wfm.tester.EventProcessor.singleton();
                Method method = EventQueue.class.getDeclaredMethod("dispatchEvent"
                    , new Class[] { AWTEvent.class });
                method.setAccessible(true);
                AWTEvent[] event = new AWTEvent[1];
                for(;;) {
                    event[0] = eventQueue.getNextEvent();
                    if(event[0] != null) {
                        try {
                            method.invoke(eventQueue, event);
                        } catch (Exception ex) { System.out.println(ex); }
                    }
                    if(keepBlocking.isFalse()) break;
                }
            } else {
                super.show();
                isShowing.setValue(true);
                synchronized (getTreeLock()) {
                    while (keepBlocking.isTrue()) {
                        try {
                            getTreeLock().wait();
                        } catch (InterruptedException e) {
                            break;
                        }
                    }
                }                   
            }
        } else {
            super.show();
        }
    } catch (Exception ex) {
        System.out.println("Error Caught "+ ex);
    }
}
   
public void hide() {
        super.hide();
        isShowing.setValue(false);
        synchronized (getTreeLock()) {
            keepBlocking.setValue(false);
            EventQueue.invokeLater(new Runnable(){ public void run() {} });
            getTreeLock().notifyAll();
        }
    } else {
        super.hide();
    }
}I was thinking this should work. However, when I implement it I get strange/inconsistent results. Every now and then when I close a dialog I seem to be getting something that looks like a race condition, but I can't find out where it is.
Lance

MouseEvent doubleClick Listener

Hi,
I have a requirement in which when you click a node you call "action A" and on double click you call "action B".
I was using the following code all this while:
+Node.setOnMouseClicked(new EventHandler<MouseEvent>(){+*
+#Override+
+public void handle(MouseEvent arg0) {+*
+if(arg0.getClickCount()==1){+*
+// do Action A.+
+}+
+if(arg0.getClickCount()==2){+*
+// do Action B.+
+}+
+}+
+});+
However, on double click-- this also triggers first click action . To make the matter worse, if Action A called by first click takes substantial time , then double click is interpreted as two single clicks not a double Click and action B never gets executed.
Is there any Listener to differentiate single and double click?
Pls advice appropriate approach for this.
Thanks 
I think this is necessarily a bit ugly.
The behavior you observe is expected. Each click generates an independent event. The getClickCount() method returns a count of clicks within a small space of time (OS configurable) and a small (spatial) region. The same behavior happens in AWT.
To detect a genuine single click, you need to wait and see if another click occurs before interpreting it as a single click. So something like this:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.LabelBuilder;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.layout.VBoxBuilder;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.RectangleBuilder;
import javafx.stage.Stage;
public class ClickCountTest extends Application {
 
  private boolean boxDoubleClicked ;
 
  private static final int DOUBLE_CLICK_WAIT_TIME = 400 ; // milliseconds
  #Override
  public void start(Stage primaryStage) throws Exception {
    boxDoubleClicked = false ;
    final Rectangle box = RectangleBuilder.create()
        .fill(Color.AQUAMARINE)
        .stroke(Color.BLACK)
        .width(200)
        .height(200)
        .build();
    final Label status = LabelBuilder.create()
        .text("Nothing clicked yet")
        .build();
    box.setOnMouseClicked(new EventHandler<MouseEvent>() {
      #Override
      public void handle(MouseEvent event) {
        if (event.getClickCount()==1) {
          processFirstClick(status);
        }
        if (event.getClickCount()==2) {
          processSecondClick(status);
        }
      }    
    });   
    VBox root = VBoxBuilder.create()
        .children(
            box, status
        )
        .build();
    Scene scene = new Scene(root);
    primaryStage.setScene(scene);
    primaryStage.sizeToScene();
    primaryStage.show();
  }
  private void processFirstClick(final Label label) {
    new Thread(new Runnable() {
      #Override
      public void run() {
        try {
          Thread.sleep(DOUBLE_CLICK_WAIT_TIME);
          if (! isBoxDoubleClicked()) {
            Platform.runLater(new Runnable() {
              #Override
              public void run() {
                  label.setText("Single click");
                  System.out.println("Single click");
                }
            });
          }
        } catch (InterruptedException exc) {
          // Should not be possible
          throw new Error(exc);
        }
      }
    }).start();
  }
 
  private void processSecondClick(final Label label) {
    setBoxDoubleClicked(true);
    label.setText("Double click");
    System.out.println("Double click");
    new Thread(new Runnable() {
      #Override
      public void run() {
        try {
          Thread.sleep(DOUBLE_CLICK_WAIT_TIME);
          setBoxDoubleClicked(false);
        } catch (InterruptedException exc) {
          // should not happen
          throw new Error(exc);
        }
      }
    }).start();
  }
 
  public synchronized void setBoxDoubleClicked(boolean doubleClicked) {
    boxDoubleClicked = doubleClicked ;
  }
 
  public synchronized boolean isBoxDoubleClicked() {
    return boxDoubleClicked ;
  }
 
  public static void main(String[] args) {
    launch(args);
  }
}Here processFirstClick() waits a period of time, then checks the boxDoubleClicked flag. If the box has not been double clicked, it proceeds to change the state of the UI. Note that the waiting must happen on a different thread, and the change to the UI must happen on the FX application thread, using Platform.runLater(...).
processSecondClick() in turn sets the boxDoubleClicked flag, then updates the UI. This all happens on the FX application thread as it was invoked by the event handler. It then starts a new thread which waits and then clears the boxDoubleClicked flag, so that subsequent single clicks get the correct value.
You might want to tune the DOUBLE_CLICK_WAIT_TIME to get optimal behavior.
Note the isBoxDoubleClicked and setBoxDoubleClicked methods must be synchronized as they change shared state from different threads.
There may be easier ways to do this that I don't know about or can't see immediately: others will likely post if that is true.
Incidentally, regarding your comment
890627 wrote:
To make the matter worse, if Action A called by first click takes substantial time , then double click is interpreted as two single clicks not a double Click and action B never gets executed. you really shouldn't do this. If an action takes substantial time, don't execute it on the FX application thread: launch a new thread to manage it and use Platform.runLater(...) to update the UI once it has done its time-consuming work. 
looks legit.. but confused 
Thanks James for your insight. 
You can probably clean this up considerably using java.util.Timer and java.util.TimerTask. 
Multiple click handling strategies were discussed by the javafx development team.
And they specifically decided not to add functionality to facilitate detecting situations like your example because it was considered "bad UI design".
http://mail.openjdk.java.net/pipermail/openjfx-dev/2012-May/001785.html
For example if you take a look at the click handling on windows desktop icon:
- one click to select and highlight an icon
- double click to launch the app
For the launch, it doesn't matter that the icon was first selected and highlighted or how many times it was selected and highlighted.
So the suggestion is that you would change your application functionality such that:
a. the first click action (Action A) should execute very quickly and not take a substantial time.
b. it doesn't matter if action A is triggered multiple times.
c. on double click (Action B) it doesn't matter that the first click action (Action A) is also triggered.
You could use James code as a work-around, but I wouldn't advise it unless this behavior is absolutely critical to your app, especially if the work-around seems confusing.
Overall, the JavaFX philosophy is to make common things simple and other things possible, your current UI design is one which falls in the latter class. 
Thanks jsmith.
I understand having action A executed promptly (perhaps by having it on different thread) might fix the problem .
I was just not sure , if a double click requirement was worthy enough to get into thread mgmt stuff .
Any way, I think now I should.
Regards. 
FWIW I agree entirely with jsmith's post above. I was actually going to write something expressing that but had to go to a meeting. jsmith said it better anyway.
If the actions you want to perform are mutually exclusive in their functionality, it makes sense for the ui inputs that cause them to be invoked to be mutually exclusive as well. Single-click and double-click on the same mouse button are not mutually exclusive; one is a subset of the other. Obviously, you may be writing to someone else's requirement document here, but if you have the option to change the requirements it's probably worth fighting that battle. There are a number of ways you could have similar but more appropriate input events to invoke the actions you want: for example a context menu with the two options, different mouse buttons, or (less preferably perhaps) using modifier keys on the mouse click.
The code to do what you want, as you can see, is a little tricky and will be harder to maintain; the code sample I have is not really a particularly robust solution (it would take me a lot more time to make it so). Additionally the UI is likely to be harder to use (if the user is too slow with their double-click, for example, they will end up invoking a different, unrelated piece of functionality (twice) to the one they intended). 
Hi James,
I want to go with the idea of finishing action of first click fast enough so that multiple selection in multiple click wont be a problem.
You have suggested to launch a new thread to manage doActionA() from first click.
I have created an instance of the task having action A in its call() and run it in a new thread . But the problem is not solved yet. still, double click is getting interpreted as single click two times.
I am sure I am missing something ...
node.setOnMouseClicked(new EventHandler<MouseEvent>(){
      #Override
      public void handle(MouseEvent arg0) {
          //PART1
     if (arg0.getClickCount()==1){
                  Task<Void> task = new Task<Void>() {
             #Override
             protected Void call() throws Exception {
               Platform.runLater(new Runnable() {
                 #Override
                 public void run() {
                  doActionA();
                 }
              });
               return null;
             }
           };
         new Thread(task).start();
        }
     //PART 2
         if(arg0.getClickCount()==2){
        doActionB();
        }
      }Edited by: 890627 on Oct 30, 2012 4:42 PM 
For a double click, the code you posted should invoke action A (run on a background thread), then invoke action B. The first click of the double click will invoke the handle(...) method with a MouseEvent whose clickCount is 1; the second click will invoke the handle method with a MouseEvent whose clickCount is 2.
If you're getting something different, post a complete executable example (the simplest one that shows the behavior). 
Oh, sorry; I see the issue now.
Your code to handle the single click doesn't actually achieve the aim of running doActionA() on a different thread. It launches a new thread which merely schedules doActionA() to be invoked on the FX application thread. So if doActionA() takes a long time, you're still tying up the FX Application thread (preventing it from detecting the second click of the double click) until it's complete.
The structure you want is
public void handle(MouseEvent evt) {
  if (evt.getClickCount()==1) {
          Task<Void> task = new Task<Void>() {
            #Override
            protected Void call() throws Exception {
              doActionA();
            return null;
          }
       };
      new Thread(task).start();
   }
   ...
}
...
private void doActionA() {
   // do time-consuming work that doesn't change the UI here:
   // ...
   Platform.runLater(new Runnable() {
    #Override
    public void run() {
       // now update the UI with the results of your work here
       //...
    }
  });
} 
Thanks , got it working now.

JPROGRESS BAR without progress

In one of my application i am using a JProgressBar
now all is correct like
dd.jpb = new JProgressBar(JProgressBar.HORIZONTAL,0,100);
dd.jpb.setString("Download Status") ;
dd.jpb.setStringPainted(true);
jpb.setValue(0);
jpb.setMaximum(contentLength);
-----
jpb.setValue(k);
actually i have done all above correctly
the program is downloading application
the k is the file size downloaded at present time
contentLength is the full file length
---------------
but jpb does not show any progress gradually
it disappears when downloading starts and appears when
download is complete
i want it to show the progress gradually while downloading
please check if jpb.setValue (position );
is correct to show progress gradually
tell me how to rectify the problem
please dont show the links to java tutorial...
Perhaps it is because you did not force the update of the component:
try something like jpb.revalidate() each time you change the value 
i just tried jpb.revalidate();
but there is no change
it just disappears and never comes back before download is
complete...... 
You need update in while loop:
private synchronized String load(int k) {
     progressBar.setMaximum(k);
    for(int i=0; i <k; i++) {
             //do your loading or whatever
            updateStatus(i);
                  progressBar.setString("Loading...");
        }
            updateStatus(0);
                  progressBar.setString("Done...");
       return whatever;
     }
public  void updateStatus(final int i) {
      Runnable doSetProgressBarValue = new Runnable() {
           public void run() {
                progressBar.setValue(i);
           }
      };
      SwingUtilities.invokeLater(doSetProgressBarValue);
        }If you have long value then you, probably, want to increment by fractions of it, like k/100 or something
Hope this helps.
Do not throw Runnables away, otherwise you risk to freez your gui. 
i am sorry i am not unable to understand the above
please send with simple code and full description of it
thanks for all the trouble u take
OK, trying to make it more clear, i pasted skeleton before,
now i modified it so you can test it and once you understand, you can adjust it to your situation:
//some method performing long operation
//k is limit of some value which allows to measure yor progress
//when value reaches its limit(k), progressbar will be fully painted
//for example,it can be length of a file you are loading
public void load(int k)
  {
//set progress bar max value to the limit
     progressBar.setMaximum(k);
        progressBar.setString("Loading...");      
      for(int i=0; i <k; i++) {
//between iterations allow the thread to sleep
//just to slow the operation enough so you can observe the progress          
     try{
     Thread.currentThread().sleep(50);
      }
    catch(InterruptedException e){e.printStackTrace()};
//call method that updates progress bar
//and repaints  by setting its
//value to i
           updateStatus(i);                
}
//upon completion of the above loop reset the progress bar
           updateStatus(0);              
    progressBar.setString("Done...");     
      }
//method updates the progress bar in
//event dispatching thread
//to learn more about updating swing gui in
//event dispatching thread please read tutorials
//"Swing and  threads" here on the site
public  void updateStatus(final int i)
{     
Runnable doSetProgressBarValue = new Runnable() {     
      public void run() {     
           progressBar.setValue(i);     
      }      };     
SwingUtilities.invokeLater(doSetProgressBarValue);  
     }I hope i did not make any sintax mistakes. 
Made mistake in try-catch:
try{   
Thread.currentThread().sleep(50);    
}    catch(InterruptedException e){e.printStackTrace();}It's kind of late, sorry 
i have come to know what r u trying to say
actually thread sleep decreases the speed in downloading
well i even tried your statements but there is no
effect
so i am sending my source code
on http://pramod.home.icq.com/down.zip
this consists of down.java the source for downloader
u will have to write the url in the url box and then have
to press start button (others buttons are fake one dont try them)
to check on system u can write
file://c:/yourfolder/yourfile.ext as a url
please then send the correct code by mail to mailpramod#icqmail.com
or in this form
great thanks to SSvetlana for taking interest
Here is test class for you. I do not have time to check your code. This code below is working code, i am posting it here so anybody can read and test it too. If you do not understand code, please read textbooks on threads:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public final  class progress extends JFrame {
     JProgressBar pb;
     progress () {
          Container c = getContentPane();
          JPanel p = new JPanel();
          JButton b = new JButton("progress");
          b.addActionListener(new ActionListener() {
               public void actionPerformed (ActionEvent e) {
                    load(100);
               }
          }
          );
           pb = new JProgressBar();
           pb.setStringPainted(true);
              pb.setMinimum(0);
        pb.setString("Ready");
          p.add(b, BorderLayout.CENTER);
          p.add(pb, BorderLayout.NORTH);
        c.add(p);
        setSize( 200, 200 );
        setVisible( true );
     }
public void load(final int k) {
     Runnable r  = new Runnable() {
          public void run() {
               doLoad(k);
          }};
          Thread t = new Thread(r);
          t.start();
     }
public void doLoad(int k)
{
pb.setMaximum(k);
pb.setString("Loading...");
for(int i=0; i <k; i++)
{
try{Thread.sleep(25);}
catch(InterruptedException e){e.printStackTrace();}
updateStatus(i);
}
updateStatus(0);
pb.setString("Done...");
}
public void updateStatus(final int i)
{
Runnable doSetProgressBarValue = new Runnable()
{
public void run() {
pb.setValue(i);
}      };
SwingUtilities.invokeLater(doSetProgressBarValue);
}
public static void main( String args[] )
{
new progress();
}
} 
make method doLoad() private 
ssvetlana i want to have chat with u
my icq no is 163277388
on yahoo chat i am on pramod_topgun
Please keep in mind that if the event queue thread does the work (loading in your example) there is no gui update while running an event handling. If you think its to complex to do the work in a new thread, you should call the following after setting a new value into the progress bar:
component.paintImmediately(javax.swing.SwingUtilities.getLocalBounds(component))
...where component is your progress bar. I recommend to subclass the JProgessBar (ImmediatelyPaintedProgressBar would be a suitable name) and overwrite the following methods in it: setValue(int), setMinimum(int), setMaximum(int). In these you should call the super methods and then call the statement above in addition.
This solution works fine in our project. Good luck.
Andre 
thanks aw#sun
u have solved my problem
i am getting what i requested
but still there is a way to go
as jpb is visible only when your paintimme~~ comes in way
actually wanted it should be visible all time
(actually jpb is visible all time untill application is
refreshed by minimize or maximize )
i will see the later
thanks

progress dialog

Hi
What is the best way to show a ProgressDialog? At the moment I call show in a callserially-call, but this way no events can get through. If I don't call it in callSerially, the dialog is not always showed correctly...
Another question: Say I have a cancel button that cancels a download. I want that after the user clicks cancel, a cancelling-dialog appears while the download is cancelling. When the download is cancelled, a downloadCancelledEvent is fired by the DownloadManager. That is the signal to dispose the cancelling-dialog...
How should the dialog be showed here?
Anyone?
The code is partial so no idea what you are doing wrong.
However removeDialog() seems like a huge mistake, NEVER hold back the EDT.
Another example with full code (if not enough, please tell me what's missing):
[code]
public class ProgressDialog extends Dialog {
    public ProgressDialog(String message) {
        super();
        setLayout(new BorderLayout());
        final Label msgLabel = new Label(message);
        msgLabel.setAlignment(CENTER);
        addComponent(BorderLayout.CENTER, msgLabel);
        Display.getInstance().callSerially(new Runnable() {
            public void run() {
                showPacked(BorderLayout.CENTER, true);
            }
        });
    }
    /**
     * Remove the dialog from the screen.
     */
    public void removeDialog() {
        while (!isVisible()) {
            Utils.sleep(50);
        }
        dispose();
    }
}
[/code]
This class is used when in my Form a Command is pressed that initiates a big task (like download):
[code]
Command download = new Command(Default.COMMAND_DOWNLOAD_STRING) {
     public void actionPerformed(ActionEvent event) {
          doDownload(list.getSelectedVideo());
     }
};
[/code]
And this is what happens in doDownload:
[code]
private void doDownload(final Video video) {
    Display.getInstance().invokeAndBlock(new Runnable() {
        public void run() {
            boolean shouldQueue = CA.shouldQueueDownload(video);
            if (shouldQueue) {
                ProgressDialog pd = new ProgressDialog(DialogStrings.PDIALOG_QUEUE);
                CA.doDownload(video);
                pd.removeDialog();
            }
        }
    });
}
[/code]
In the doDownload method, CA.doDownload(video) executes a big task that returns when it is finished. What is wrong/dangerous with this code?
And what code is missing in my previous example, so that I can trace what I'm doing wrong there...
If above example is still not clear, I hope it at least explains what I'm trying to do.
If so, what is the best way of doing that... (showing a progressDialog that doesn't block the EDT)
I don't understand the problem you are experiencing but here are a few tips to improve your code:
1. Get rid of the call serially and always use LWUIT on the EDT.
2. Since doDownload is called on the EDT you can just construct the ProgressDialog in the method and only then span a thread.
3. Do you really need invokeAndBlock?
It seems like you don't. I'm assuming shouldQueueDownload is fast...
I suggest:
[code]
private void doDownload(final Video video) {
   boolean shouldQueue = CA.shouldQueueDownload(video);
   if (shouldQueue) {
       new Thread() {
            public void run() {
                ProgressDialog pd = new ProgressDialog(DialogStrings.PDIALOG_QUEUE);
                CA.doDownload(video);
                pd.removeDialog();
            }
        }.start();;
    }
}
[/code]
In the above adaptation of doDownload, how should the ProgressDialog constructor be?
If I understand your remarks it should be without the callserially, but then I call the show on the Dialog from a BG-thread... is that a problem?
ProgressDialog constructor:
[code]
public ProgressDialog(String message) {
        super();
        setLayout(new BorderLayout());
        final Label msgLabel = new Label(message);
        msgLabel.setAlignment(CENTER);
        addComponent(BorderLayout.CENTER, msgLabel);
        showPacked(BorderLayout.CENTER, true);
}
[/code]
Another question about your last post:
What happens if the thread that constructs the progressDialog takes a long time to start?
My experience is that when the user calls doDownload a few times fast after each other, the code is executed multiple times.
This is why the invokeandBlock is there: to prevent the possibility that the action is taken twice when the user clicks multiple times.
How can this be prevented in your code without using invokeAndBlock?
Hi,
I'm having a similar problem. I also use a dialog to display the action which is currently in progress. I use a global boolean to check whether other actions are permitted at a given moment in a given form. For example when an action is started but the dialog is not yet displayed, user input is disabled based on that global boolean.
When a given action is finished, I want to dispose the dialog and show the underlying form. Sometimes however, the dialog isn't disposed of until I press a key (up or down key or another one).
I'm using a similar construction you stated earlier in this thread:
[code]
    private void doAction() {
        if (!isBusy) {
            setBusy(true);
            new Thread() {
                public void run() {
                    pd = new ProgressDialog();
                    // execute action here
                    removeDialog();
                    setBusy(false);
                }
            }.start();
        }
    }
[/code]
ProgressDialog extends Dialog and in the constructor of ProgressDialog the show method is called on the EDT. However the actual 'show'-call happens in a new Thread to not block the EDT.
'removeDialog()' contains the 'dispose()' call.
Why isn't the Dialog properly removed sometimes and how can I achieve a proper disposal of the Dialog? I tried calling 'dispose' in a callSerially and in a invokeAndBlock call but that didn't solve the issue.
Is there an example (source code) for LWUIT out on the internet for a use case such as:
1) on pressing a button/executing a command show a progress dialog
2) execute an action in the background
3) remove the dialog when the action has finished
Also the user's input is ignored/disabled starting on 1) until 3) is finished.
Message was edited by: tswaenep
That was a minor mistake in my code, use something like this:
[code]
private void doDownload(final Video video) {
   boolean shouldQueue = CA.shouldQueueDownload(video);
   if (shouldQueue) {
       ProgressDialog pd = new ProgressDialog(DialogStrings.PDIALOG_QUEUE);
       new Thread() {
            public void run() {
                CA.doDownload(video);
                while(Display.getInstance().getCurrent() != pd) {
                     sleep (10);
                }
                pd.removeDialog();
            }
        }.start();
        // move this from the constructor since its a modal dialog it will block this method just like invoke and block
        showPacked(BorderLayout.CENTER, true);       
    }
}
[/code]
Two more questions:
1) Since doDownload is called from the EDT (actionPerformed), won't the call to showPacked block the edt?
2) If I would want to keep showPacked in the constructor, how could I do that?
I think the last answers from this post were removed... (during the forum errors a few months ago)
I have some more questions:
My progressdialog now is a standard dialog that displays a label without a title.
Below are 2 ways to do an action (both are found on the forum). Can someone tell me what the best way is?
Method A uses a new thread to do the long action.
Method B uses invokeAndBlock and is (imho) better then method A. The problem with this method is that it behaves weird: If the action is called from a command that is directly above a softbutton everything goes as expected. When the command is in the Menu (and thus the Menu-dialog is showed) the action is executed, but the parent is not showed... This problem can be solved by putting the parent.show() call in a callSerially-block. (Is this the good approach?)
Questions:
Is method B better then A? And can B be improved? How?
Why is there a difference when a command is called from the menu or from a softbutton directly?
Is it a correct to call the parent.show() from a callSerially block, are there other calls that must be in such a block (in the doAction methods)
method A:
[code]
public void doAction () {
    final ProgressDialog pd = new ProgressDialog();
    new Thread(new Runnable() {
        public void run() {
            //do long action
            while (Display.getInstance().getCurrent != pd) sleep(10);
            pd.dispose();
        }
    }).start();
    pd.showPacked (BorderLayout.CENTER, true);
    parent.show();
}
[/code]
method B:
[code]
public void doAction() {
    final ProgressDialog pd = new ProgressDialog();
    pd.showPacked (BorderLayout.CENTER, false);
    Display.getInstance().invokeAndBlock (new Runnable() {
        public void run () {
            //do long action
        }
    });
    pd.dispose();
    parent.show();
}
[/code]
Both methods are roughly equivalent.
A softbutton executes when the current form is initialized and showing, a menu item executes when the form is deinitialized and the menu dialog is the current active form.
All of LWUIT's methods must execute on the EDT which requires a callSerially call. repaint() will work off the EDT for most use cases but no promises.

Categories

Resources