javaswingcursorswingworkerjprogressbar

Changing the default cursor to busy cursor does not work as expected


After many attempts trying to make a JProgressBar work as expected, I finally became successful at achieving my goal. I had used @MadProgrammer's advice and used a SwingWorker to finally get the program work as I want.

Now, I want the cursor to change into BUSY_CURSOR when my JProgressBar goes from 0% to 100%. I've googled and found out that

setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

is the code to do it. I've tried it but it does not work as expected.

Relevant piece of code:

JProgressBar progress;
JButton button;     
JDialog dialog;      //Fields of my GUI class

progress=new JProgressBar(JProgressBar.HORIZONTAL,0,100);
button=new JButton("Done");
dialog=new JDialog();             //Done from methods

progress.setValue(0);
progress.setStringPainted(true);
progress.setBorderPainted(true);  //Also done from methods

button.addActionListener(this);   //Also done from methods

dialog.setLayout(new FlowLayout(FlowLayout.CENTER));
dialog.setTitle("Please wait...");
dialog.setBounds(475,150,250,100);
dialog.setModal(true);            //Also done from methods

dialog.add(new JLabel("Loading..."));
dialog.add(progress);             //Also done from methods

And here is the actionPerformed method:

public void actionPerformed(ActionEvent e)
{
    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

    Task task=new Task();
    task.addPropertyChangeListener(this);
    task.execute();
    dialog.setVisible(true);
}

The propertyChange method:

public void propertyChange(PropertyChangeEvent evt) {
    if("progress" == evt.getPropertyName()){
        int progressnum = (Integer) evt.getNewValue();
        progress.setValue(progressnum);
    }
}

and the nested class Task:

   class Task extends SwingWorker<Void, Void> {
        /*
         * Main task. Executed in background thread.
         */
        @Override
        public Void doInBackground() {
            int progressnum = 0;
            setProgress(0);

            while (progressnum < 100) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ex) {
                    System.err.println("An error occured:"+ex);
                    ex.printStackTrace();
                }

                progressnum ++;
                setProgress(Math.min(progressnum, 100));
            }
            return null;
        }

        /*
         * Executed in event dispatching thread
         */
        @Override
        public void done() {
            //setCursor(null); //turn off the wait cursor
            setCursor(Cursor.getDefaultCursor()); //Is this one or the one above it right?
            dialog.dispose();
            progress.setValue(progress.getMinimum());
        }
    }

When I press button, the JDialog with the JProgressBar appears and the JProgressBar goes from 0% to 100%. During this time, the cursor needs to be changed into BUSY_CURSOR(busy cursor) and when the JProgressBar reaches 100%, the normal cursor(NORMAL_CURSOR ) needs to be restored.

The problem is, when I press button, the cursor changes to the busy cursor for a split second and then, changes back into the original cursor. I want the cursor to be busy until the JProgressBar reaches 100%.

I've added the code to convert the cursor into a busy cursor in the actionPerformed method and the restore the normal cursor in the done method of the nested class Task. Note that I've also included the necessary packages.


Solution

  • When you call setCursor() on the JFrame, it only has effect for the frame, not the dialog. Similarly, when you call setCursor() on the JDialog, it only has effect for the dialog, not the frame. There the problem: you did not set the cursor for the dialog, right?

    I'm not sure whether setCursor(null) is safer than setCursor(Cursor.getDefaultCursor()). :p