Search code examples
javamultithreadingswingreturn-typejprogressbar

Return Values & JProgressbar


I got a problem with setting a value to a JProgressBar which i got from inside a type returning method. I know I have to do multi threading but I´m really new to this topic and really don´t know how to implement this.

I try to briefly explain my dilemma in code:

This is my data returning method to count lines in a String (e.g. from a JTextArea or whatsoever).

    public static int countLines(String s) {
        int count = 0;

        String[] words = s.split("\n");

        for(String i: words) {
            count++;
        }
        return count;
    }

What I want to add is a method inside this method that sets my JProgressBar that I created in my JFrame to the value count. E.g. setProgress(count);

Is this even possible? Because i tried several ways of doing this and no matter what, the progressbar only updates AFTER the return value has been sent out.

Do I have to run this method in an own Thread or just the progress setting method? or both?

Cheers!


Solution

  • Do I have to run this method in an own Thread or just the progress setting method? or both?

    Both tasks should run in separate threads: business logic (in this case word's count) must be performed in a background thread while progress bar update must run in the Swing thread, also known as Event Dispatch Thread (EDT).

    IMO the best way to accomplish this is by using a SwingWorker:

    • Move all count logic to doInBackground() implementation.
    • Attach a PropertyChangeListener to the swing worker to listen for progress property and update the progress bar within this listener.
    • Use setProgress() inside doInBackground to set the worker's progress and fire a property change event notifying your listener.

    There are a lot of examples here in SO, just take a look to tag. Also, consider this snippet:

    SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
    
        // Following code is performed in a background thread
    
        @Override
        protected Void doInBackground() throws Exception {
    
            String[] words = string.split(System.lineSeparator());
            int totalWords = words.length;
    
            for (int count = 0; count < totalWords; count++) {
                int progress = (count + 1) * 100 / totalWords;
                setProgress(progress);
            }
            return null;
        }
    };
    
    worker.addPropertyChangeListener(new PropertyChangeListener() {
    
        // Following code is performed in the EDT, as all event handling code is.
        // Progress bar update must be done here, NOT within doInBackground()
    
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
                Integer progress = (Integer)evt.getNewValue();
                progressBar.setValue(progress); 
            }
        }
    });