Search code examples
swingconcurrencyjprogressbar

JProgress Bar Indeterminate mode not updating


I have a JNI function that can take a while to complete, and I want a JProgress bar in indeterminate mode running while it is finishing the function. I have read the tutorials provided by Oracle, but the nature of their tutorials doesn't seem to help me understand how to do it. I realize that I should be running this function in a background thread, but I'm not quite sure how to do it.

Here is relevant code. I have a button (runButton) that will call the function, mainCpp(), when pressed:

public class Foo extends javax.swing.JFrame 
                         implements ActionListener,
                                    PropertyChangeListener{

    @Override
    public void actionPerformed(ActionEvent ae){
        //Don't know what goes here, I don't think it is necessary though because I do not intend to use a determinate progress bar
    }

    @Override
    public void propertyChange(PropertyChangeEvent pce){
        //I don't intend on using an determinate progress bar, so I also do not think this is necassary
    }

class Task extends SwingWorker<Void, Void>{

    @Override
    public Void doInBackground{
         Foo t = new Foo();
         t.mainCpp();

         System.out.println("Done...");
    }
    return null;
}

/*JNI Function Declaration*/
public native int mainCpp(); //The original function takes arguments, but I have ommitted them for simplicity. If they are part of the problem, I can put them back in.

...//some codes about GUI

private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {

    ProgressBar.setIndeterminate(true);
    Task task = new Task();
    task.execute();    
    ProgressBar.setIndeterminate(false);

}


/*Declarations*/
private javax.swing.JButton runButton;
}

Any help would be appreciated.

EDIT: Editted in an attempt to do what kiheru suggested, but still does not work.


Solution

  • Assuming you have a SwingWorker like this:

    class Task extends SwingWorker<Void, Void>{
        @Override
        public Void doInBackground() {
            // I'm not sure of the code snippets if you are already in a
            // Foo instance; if this is internal to Foo then you obviously do
            // not need to create another instance, but just call mainCpp().
            Foo t = new Foo();
            t.mainCpp();
            return null;
        }
    
        @Override
        public void done()
            // Stop progress bar, etc
            ...
        }
    }
    

    You can either keep an instance in a field of the containing object, and then using it would work like this:

    private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // Start progress bar, disable the button, etc.
        ...
        // Task task has been created earlier, maybe in the constructor 
        task.execute();
    }
    

    , or you can create a worker in place:

    private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // Start progress bar, disable the button, etc.
        ...
        new Task().execute();
    }