Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JButton stays in pressed state

In my Java GUI app I have a JButton and when clicked it calls a function to connect to a database, then calls a function to clear a table in the DB, then calls a function that reads text from one file and loads variables, which calls a function that reads text from another file, compares the data from both and then calls a function to either update or insert data in the DB, all of that works fine.

However my question is related to the JButton, when its clicked I want to run a Indeterminate progress bar just so the user knows work is being done and then right before it leaves the the action listener setIndeterminate to false and set the value of the progress bar to 100(complete), but in my case when you click the button it stays in the clicked state and the progress bar freezes.

What should I implement to prevent this? threading possibly? but Im quite new to threading in java. here is my action listener:

    private class buttonListener implements ActionListener
        {
            public void actionPerformed(ActionEvent e)
            {
                if( e.getSource() == genButton )
                {
                    progressBar.setIndeterminate(true);
                    progressBar.setString(null);
                    try 
                    {
                        dbConnect(); //connects to DB
                        clearSchedules(); // deletes data in tables
                        readFile(); // reads first file and calls the other functions
                        dbClose();// closes the DB
                        progressBar.setIndeterminate(false);
                        progressBar.setValue(100);
                    } 
                    catch (Exception e1){
                        System.err.println("Error: " + e1.getMessage());
                    }
                }
            }
        }

On a side note, I would like to have the action bar actually move as the the program progresses but I wasnt sure how to monitor its progress.

Thanks, Beef.

UPDATE here is my example of SwingWorker and how I used it:

Declared globally

 private functionWorker task;


    private abstract class functionWorker extends SwingWorker { 

        public void execute() {
            try {
                dbConnect();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            clearSchedules();
            try {
                readFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
            dbClose();
        }
    }

Inside my actionPerformed method

if( e.getSource() == genButton )
            {

                progressBar.setIndeterminate(true);
                progressBar.setString(null);
                try 
                {
                    task.execute();

                    progressBar.setIndeterminate(false);
                    progressBar.setValue(100);
                } 
                catch (Exception e1){
                    System.err.println("Error: " + e1.getMessage());
                }
            }
like image 895
Beef Avatar asked Sep 23 '11 14:09

Beef


3 Answers

The problem is probably related to connecting to doing expensive operations in the UI thread (connecting to a database, reading from a file, calling other functions). Under no circumstances should you call code that uses excessive CPU time from the UI thread, as the entire interface can't proceed while it is executing your code, and it results in a 'dead' looking application, with components remaining in their state at the time before an expensive operation until completion. You should execute another thread, do the expensive work in that, and then use a SwingUtilities.invokeLater(Runnable doRun) with a passed runnable where you'd update the progress.

There may be synchronisation issues relating to the states of components, but you can fix these later.

like image 150
Chris Dennett Avatar answered Nov 08 '22 02:11

Chris Dennett


Could I create the new thread when the action is performed and call the new functions in the thread, or should I do the threading within the actual function itself?

You can start a SwingWorker from your button's handler, as shown here. A related example implementing Runnable is seen here.

like image 27
trashgod Avatar answered Nov 08 '22 02:11

trashgod


One method to handle progressbars are to extend SwingWorker in a class. SwingWorker takes care of running background tasks for you and so you do not have to implement your own threading that can end up in unknown issues. To begin with, your class that takes care of progress bar UI should implement PropertyChangeListener And implement public void propertyChange(PropertyChangeEvent evt) { - to update the progressbar status based on a global variable.

The background task class should look like the following(this could be an inner class) :

class ProgressTask extends SwingWorker<Void, Void> {
        @Override
        public Void doInBackground() {
             //handle your tasks here
             //update global variable to indicate task status.
        }
        @Override
        public void done() {
             //re-enabled your button
        }
}

on your button's event listener :

 public void actionPerformed(ActionEvent evt) {
    //disable your button
    //Create new instance of "ProgressTask"
    //make the task listen to progress changes by task.addPropertyChangeListener(this);
    //calll task.execute();
 }

I have tried to water down code example, you would have to read some tutorial to understand how all these pieces fit together. However, the main point is do not code your Threads, instead use SwingWorker

like image 5
ring bearer Avatar answered Nov 08 '22 02:11

ring bearer