Results 1 to 19 of 19
  1. #1
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    My Swing application parses seletable XML-files and displays them within a JTable. As the files may become really huge I want to show to the user that the application is busy. But I see, that the "BUSY"-indication doesn't show up when set after the file chooser dialog. Here is a simplified sample, just to show what I mean:
    Java Code:
    import java.awt.Cursor;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    import javax.swing.JButton;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    import org.jdom2.Document;
    import org.jdom2.Element;
    import org.jdom2.JDOMException;
    import org.jdom2.input.SAXBuilder;
    import org.jdom2.input.sax.XMLReaderSAX2Factory;
    
    public class OneClassSample extends JFrame {
    	JPanel myPanel;
    	JLabel myLabel;
    	public OneClassSample() {
    		super("My Sample"); 
    		setDefaultCloseOperation(EXIT_ON_CLOSE);
    		setSize(400, 200);
    
    		myPanel = new JPanel();
    		JButton jb = new JButton("PressMe");
    		jb.setActionCommand("pressed");
    		jb.addActionListener(new PressedListener());
    		myLabel = new JLabel();
    		myPanel.add(jb);
    		myPanel.add(myLabel);
    		
    
    		this.add(myPanel);
    	}
    
    	class PressedListener implements ActionListener {
    		private String lastUsedPath="J:/xmls2/total.xml";
    		private List<String[]> listfiles = new ArrayList();
    		public void actionPerformed(ActionEvent event){
    			JFileChooser chooser = new JFileChooser();
    			chooser.setSelectedFile(new File(lastUsedPath));
    			chooser.setMultiSelectionEnabled(false);
    			chooser.setDialogTitle("Choose XML-File");
    			int option = chooser.showDialog(chooser, "Select");
    			File detectedFilesFile = chooser.getSelectedFile();
    			if (detectedFilesFile==null) return;
    			lastUsedPath=detectedFilesFile.getAbsolutePath();
    			
    			try {
    				myPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    				parseXMLfile(lastUsedPath);
    				myLabel.setText("Done");
    			} finally {
    				myPanel.setCursor(Cursor.getDefaultCursor());
    			}
    		}
    
    		private void parseXMLfile(String lastUsedPath) {
    			try {
    				SAXBuilder builder = new SAXBuilder(new XMLReaderSAX2Factory(false));
    				Document doc = builder.build(lastUsedPath);
    				Element root = doc.getRootElement();
    				List<Element> filetags = root.getChildren("File");
    				for (Element file : filetags) {
    					String[] row= {
    							file.getChild("field1").getText(),
    							file.getChild("field2").getText(),
    					};
    					listfiles.add(row);	
    				} 
    			} catch (Exception e) {}
    		}
    	}
    
    
    	public static void main(String[] args) throws Exception {
    		OneClassSample ocs=new OneClassSample();
    		ocs.setVisible(true);
    	}
    
    }
    The program works fine, but as already mentioned, it only indicates "Application Busy" when the line 50 is set to comment.
    Java Code:
    //			int option = chooser.showDialog(chooser, "Select");
    It's the same with Java 1.7 and Java 1.8.

    Is there a explanation know for this? I would appreciate any suggestion how to fix this.

  2. #2
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    12,059
    Rep Power
    25

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Don't perform long running tasks on the EDT as that prevents the GUI from repainting to update its state.

    Go through these:
    Lesson: Concurrency in Swing (The Java™ Tutorials > Creating a GUI With JFC/Swing) -- especially the section on SwingWorker
    How to Use Progress Bars (The Java™ Tutorials > Creating a GUI With JFC/Swing > Using Swing Components)

    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  3. #3
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by DarrylBurke View Post
    Don't perform long running tasks on the EDT as that prevents the GUI from repainting to update its state.
    Thanks for the reply. I will research the mentioned docs. I had already found some hints mentioning the idea not to put to much load to the EDT. But the load comes from the parser - and just parsing looks fine. That invoking the JFileChooser introduces this problem is sort of astonishing. But I will see.

  4. #4
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Anyway - running in a separate Thread solved it. Thank you.

  5. #5
    gimbal2 is offline Just a guy
    Join Date
    Jun 2013
    Location
    Netherlands
    Posts
    5,114
    Rep Power
    12

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by Ulrich View Post
    Anyway - running in a separate Thread solved it. Thank you.
    Do you understand why? You'll need to repeat the trick in the future so it pays off to know to identify when to use it.
    "Syntactic sugar causes cancer of the semicolon." -- Alan Perlis

  6. #6
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    I'm still not confident. When running the both of the tasks in a single thread it works, but when splitting I've still the same problem. Ok, I got a solution - but I've no idea what's going on here. I have now this code:
    Java Code:
    package com.lis.tecosim.storage.monitor.gui;
    
    import java.awt.Cursor;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    
    import javax.swing.JButton;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.SwingWorker;
    import javax.swing.filechooser.FileNameExtensionFilter;
    
    import org.jdom2.Document;
    import org.jdom2.Element;
    import org.jdom2.JDOMException;
    import org.jdom2.input.SAXBuilder;
    import org.jdom2.input.sax.XMLReaderSAX2Factory;
    
    public class OneClassSample extends JFrame {
    	JPanel myPanel;
    	JLabel myLabel;
    	public OneClassSample() {
    		super("My Sample"); 
    		setDefaultCloseOperation(EXIT_ON_CLOSE);
    		setSize(400, 200);
    
    		myPanel = new JPanel();
    		JButton jb = new JButton("PressMe");
    		jb.setActionCommand("pressed");
    		jb.addActionListener(new PressedListener());
    		myLabel = new JLabel();
    		myPanel.add(jb);
    		myPanel.add(myLabel);
    
    
    		this.add(myPanel);
    	}
    
    	class ChooserWorker extends SwingWorker {
    		protected boolean aborted = false;
    		protected boolean isRunning=true;
    		private String lastUsedPath;
    		
    		public ChooserWorker(String lastUsedPath) {
    			this.lastUsedPath=lastUsedPath;
    		}
    		public Object doInBackground() {
    			JFileChooser chooser = new JFileChooser();
    			chooser.setSelectedFile(new File(lastUsedPath));
    			chooser.setMultiSelectionEnabled(false);
    			chooser.setDialogTitle("Choose XML-File");
    			int chooserOption = chooser.showOpenDialog(chooser);
    			File detectedFilesFile = chooser.getSelectedFile();
    			lastUsedPath=detectedFilesFile.getAbsolutePath();
    			return lastUsedPath;
    		}
    	}
    
    	class ParsingWorker extends SwingWorker {
    		private List<String[]> listfiles = new ArrayList();
    		private boolean isRunning=true;
    		private final String lastUsedPath;
    		public ParsingWorker(String lastUsedPath) {
    			this.lastUsedPath=lastUsedPath;
    		}
    		public Object doInBackground() {
    			try {
    				myPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    				parseXMLfile(lastUsedPath);
    				myLabel.setText("Done");
    			} finally {
    				myPanel.setCursor(Cursor.getDefaultCursor());
    			}
    			return null;
    		}
    
    		private void parseXMLfile(String lastUsedPath) {
    			try {
    				SAXBuilder builder = new SAXBuilder(new XMLReaderSAX2Factory(false));
    				Document doc = builder.build(lastUsedPath);
    				Element root = doc.getRootElement();
    				List<Element> filetags = root.getChildren("File");
    				for (Element file : filetags) {
    					String[] row= {
    							file.getChild("path").getText(),
    							file.getChild("name").getText(),
    							file.getChild("owner").getText(),
    							file.getChild("lastUsed").getText(),
    							file.getChild("size").getText(),
    					};
    					listfiles.add(row);	
    				} 
    			} catch (Exception e) {}
    		}
    	}
    
    	class PressedListener implements ActionListener {
    		private String lastUsedPath="D:/xmls2/tec0052.filelist.xml";
    		private List<String[]> listfiles = new ArrayList();
    		public void actionPerformed(ActionEvent event){
    			try {
    				SwingWorker cw = new ChooserWorker(lastUsedPath);
    				cw.run();
    				lastUsedPath=(String) cw.get();
    				myLabel.setText("Starting");
    				myPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    				SwingWorker pw = new ParsingWorker(lastUsedPath);
    				pw.run();
    			} catch (InterruptedException | ExecutionException e) {
    				e.printStackTrace();
    			} finally {
    				myPanel.setCursor(Cursor.getDefaultCursor());
    			}
    		}
    
    	}
    
    
    	public static void main(String[] args) throws Exception {
    		OneClassSample ocs=new OneClassSample();
    		ocs.setVisible(true);
    	}
    
    }
    As can be seen, Choosing and Parsing are done now in separate Threads "ChooserWorker" (line 47) and "ParsingWorker" (line 67). If I put the "Cursor.WAIT_CURSOR" between the both invocations (line 114) nothing happens - I have to run it before "ChoosingWorker" to see an effect. This means nothing has changed by running separate threads. The same is true for the JLabel.setText() instruction (line 113) - the text doesn't show up in the panel.
    Last edited by Ulrich; 02-03-2015 at 01:47 PM.

  7. #7
    gimbal2 is offline Just a guy
    Join Date
    Jun 2013
    Location
    Netherlands
    Posts
    5,114
    Rep Power
    12

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    This is important to understand. I think you are struggling with two related opposites that both relate to the same entity: the EDT, or Event Dispatch Thread. I hope by now you know what the EDT does.

    - Some things MUST happen "on the EDT", which literally means that the EDT thread invokes the code when it is the right time to do it. You have mechanisms to make that happen, such as a SwingWorker or the SwingUtilities.invokeLater() method. Identifying what needs to happen on the EDT is a rather more difficult thing to state in a few words, but lets just say that it is generally actions that cause the GUI to change in some way or another.

    - Some things must NOT happen "on the EDT", which as Darryl says is code which takes a long to execute as long running code that is run by the EDT will have the effect of making it appear the user interface has locked up - since the EDT will not be able to in a timely manner update the GUI or react to other events.

    So as an example: if you have a button in your application, that button will likely have an ActionListener attached to it. That ActionListener code is invoked by the EDT. So if you would add code to that action listener which for example would import an XML file of 2GB, then that is going to take a long time to process and the GUI will be frozen since the EDT is being held up. As such you do not do the importing code in the action listener directly, you start a separate thread to do that work in the background and leave the EDT to do its own job.

    Does that perhaps clear anything up?
    Last edited by gimbal2; 02-03-2015 at 02:14 PM.
    "Syntactic sugar causes cancer of the semicolon." -- Alan Perlis

  8. #8
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    12,059
    Rep Power
    25

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by gimbal2 View Post
    - Some things must NOT happen "on the EDT", which ass Darryl says ...
    Thank you.

    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  9. #9
    gimbal2 is offline Just a guy
    Join Date
    Jun 2013
    Location
    Netherlands
    Posts
    5,114
    Rep Power
    12

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    I meant to say "assistant Darryl".
    "Syntactic sugar causes cancer of the semicolon." -- Alan Perlis

  10. #10
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Thank you for the explanation. I understand that it is not wise to bind lots of work to the EDT. But I think the current sample is different. There is no task beside the "PressMe"-Button. If pressed three action are run - one after another:
    - Choose File
    - set Cursor to indicate BUSY
    - load XML

    I can't see why it works with this sequence
    - set Cursor to indicate BUSY
    - Choose File
    - load XML

    or with this:
    - set Cursor to indicate BUSY
    - load XML

    but not with the first one. And in my example I have offloaded the work to separate threads (in my first approach to a "Runnable", now to SwingWorker. But I don't think it's the EDT-load preventing displaying the BUSY-Cursor.
    I have done the XML parsing directly under the ActionListener twice, one after another and set the "Cursor.WAIT_CURSOR" between the both tasks. It worked fine.

  11. #11
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by Ulrich View Post
    Thank you for the explanation. I understand that it is not wise to bind lots of work to the EDT. But I think the current sample is different. There is no task beside the "PressMe"-Button. If pressed three action are run - one after another:
    - Choose File
    - set Cursor to indicate BUSY
    - load XML

    I can't see why it works with this sequence
    - set Cursor to indicate BUSY
    - Choose File
    - load XML

    or with this:
    - set Cursor to indicate BUSY
    - load XML

    but not with the first one. And in my example I have offloaded the work to separate threads (in my first approach to a "Runnable", now to SwingWorker. But I don't think it's the EDT-load preventing displaying the BUSY-Cursor.
    I have done the XML parsing directly under the ActionListener twice, one after another and set the "Cursor.WAIT_CURSOR" between the both tasks. It worked fine.
    The documentation for setCursor says that one of the criteria for the command to have effect is that the component must "contain" the cursor (be in its window). When you click on the button, your are in the JPanel so if the first thing you do is set the cursor, it will have effect. If you wait for a file selection, you have moved your cursor over to another panel so it won't have effect.

    Try this experiment. Set up the app like you want. Then put in a delay of about 2 seconds using Thread.sleep. That will give you time to place the cursor over the panel before you set the cursor. Then it should remain that way until you finish your task and reset the cursor again.

    As has been stated before, I recommend you use threads to handle your tasks. You can use a MouseListener to determine when the cursor enters a JComponent and you can also fire events when tasks are finished. Java has a rich set of classes to help with threads. You should check them out.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  12. #12
    StormyWaters is offline Senior Member
    Join Date
    Feb 2009
    Posts
    312
    Rep Power
    11

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by Ulrich View Post
    Java Code:
    	class PressedListener implements ActionListener {
    		private String lastUsedPath="D:/xmls2/tec0052.filelist.xml";
    		private List<String[]> listfiles = new ArrayList();
    		public void actionPerformed(ActionEvent event){
    			try {
    				SwingWorker cw = new ChooserWorker(lastUsedPath);
    				cw.run();
    				lastUsedPath=(String) cw.get();
    				myLabel.setText("Starting");
    				myPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    				SwingWorker pw = new ParsingWorker(lastUsedPath);
    				pw.run();
    			} catch (InterruptedException | ExecutionException e) {
    				e.printStackTrace();
    			} finally {
    				myPanel.setCursor(Cursor.getDefaultCursor());
    			}
    		}
    
    	}
    Take a look at the way the actionPerformed() method is implemented here...

    As others have stated in this thread, it isn't a good idea to do long running tasks on the EDT as it halts it and prevents it from updating the GUI. The actionPerformed() method is called by the EDT, so is there something here that might be causing the thread to halt/wait...

    Take a look at the get() method for SwingWorker... SwingWorker (Java Platform SE 6)

    Looking at that, it states that if you call the get() method, it will wait until the Worker thread has finished and then return the value, so you are effectively halting the EDT on this line:
    Java Code:
    				lastUsedPath=(String) cw.get();
    Using that get() method on the EDT is no better than not using a SwingWorker at all.
    Last edited by StormyWaters; 02-03-2015 at 09:30 PM.

  13. #13
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by jim829 View Post
    Try this experiment. Set up the app like you want. Then put in a delay of about 2 seconds using Thread.sleep. That will give you time to place the cursor over the panel before you set the cursor. Then it should remain that way until you finish your task and reset the cursor again.
    Thanks, that was it. I can't find what you said about the documentation of setCursor in the JavaDoc (Component (Java Platform SE 7 )) - but works as you said.

  14. #14
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by StormyWaters View Post
    Using that get() method on the EDT is no better than not using a SwingWorker at all.
    This program was only meant to show my problem. I implemented the get() to force the sequence of processing. But thank you for your hint - it again sensitizes me to take care which kind of work to run under EDT.

  15. #15
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by Ulrich View Post
    Thanks, that was it. I can't find what you said about the documentation of setCursor in the JavaDoc (Component (Java Platform SE 7 )) - but works as you said.
    Even though it works I believe it was just coincidental as I don't believe my explanation is valid.

    Regards,
    Jim
    Last edited by jim829; 02-04-2015 at 04:36 AM.
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  16. #16
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    At last it seems that the problem can be solved by running the work under it's own thread. My first error was to start the workers with "run()" instead of "execute()". Only the second method starts the work under a new thread. Doing so (and removing the get()-invocation) solved it. My interpretation is, that it is a timing problem - the preceding request to set cursor to BUSY seems to be queued to the EDT - but when the thread it busy by work it can't execute this request. And Jim is probably right stating it was coincidence - maybe the additional coding let the EDT run the setCursor before the work.
    Does this sound reasonable?

  17. #17
    gimbal2 is offline Just a guy
    Join Date
    Jun 2013
    Location
    Netherlands
    Posts
    5,114
    Rep Power
    12

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    I'm not exactly sure, but I'm going to expand on an earlier example to try and explain how I would do things.

    Case: you have an import which is started from a button click
    Requirement: as long as the import is running the GUI must be responsive, but the import button must be disabled

    To solve:

    1. in action listener / EDT, disable button and start thread to do import
    2. Thread finishes doing import (or errors out)
    3. Thread uses SwingWorker or SwingUtilities.invokeLater() to let the EDT enable the button
    4. EDT enables button

    Point 3 is the interesting one as it shows a sort of ping pong between threads going on.
    "Syntactic sugar causes cancer of the semicolon." -- Alan Perlis

  18. #18
    Ulrich is offline Member
    Join Date
    Apr 2012
    Posts
    25
    Rep Power
    0

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    Quote Originally Posted by gimbal2 View Post
    3. Thread uses SwingWorker or SwingUtilities.invokeLater() to let the EDT enable the button
    It seems you see a difference between Thread and SwingWorker. From the docs I get, to use SwingWorker for long running tasks. You are using SwingWorker just for invoking Swing methods, don't you?

  19. #19
    gimbal2 is offline Just a guy
    Join Date
    Jun 2013
    Location
    Netherlands
    Posts
    5,114
    Rep Power
    12

    Default Re: Swing "Cursor.WAIT_CURSOR" doesn't work behind JFileChooser Dialog

    You are correct, my old school ways are interfering with me explaining myself properly. But the fact that you can call me out on it proves you get it ;)
    "Syntactic sugar causes cancer of the semicolon." -- Alan Perlis

Similar Threads

  1. Replies: 0
    Last Post: 12-07-2012, 08:29 AM
  2. Replies: 3
    Last Post: 10-30-2012, 03:06 PM
  3. JFileChooser doesn't work as it should!
    By fioan89 in forum AWT / Swing
    Replies: 1
    Last Post: 09-13-2011, 02:06 PM
  4. Replies: 1
    Last Post: 10-20-2008, 07:35 AM
  5. Open "Save Page As" Dialog Box
    By Anubha in forum JavaServer Pages (JSP) and JSTL
    Replies: 0
    Last Post: 12-12-2007, 09:27 PM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •