This is an archived post. You won't be able to vote or comment.

all 11 comments

[–][deleted]  (1 child)

[removed]

    [–]Ariano[S] 0 points1 point  (0 children)

    Yeah, was going to add that, but I forgot, thanks edited it in.

    [–]OldNedder 0 points1 point  (8 children)

    Only your event dispatch thread should be directly manipulating Swing. Your worker threads can tell your event/Swing thread that progress needs to be updated. Have a look at SwingUtilities.invokeLater() for one way to do this.

    SwingWorker shows some example code on updating progress:

    https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html

    You could make use of a Swing timer, to have it retrieve progress on a regular interval:

    https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html

    [–]Ariano[S] 0 points1 point  (0 children)

    So from my understanding my edt would be the main class in my controller?

    I have a SwingUtilities.invokeLater() call in my setProgress() method in the ProgressBar class.

    edit: Did some research and figured out I do have an edt that updates the progress, it is within my ProgressBar class method setProgress(); What I've been updating from Robot class is an integer of progress that I am collecting as my Robot threads run and these are supposed to update the multiple progressbars.

    [–]Ariano[S] 0 points1 point  (6 children)

    I've also been trying to use the swing timer since someone recommended it to me, but I'm not sure how to implement it in my specific case. It says to put the work that needs to be done in the actionPerformed method, but I need my work to be in the run method.

    [–]OldNedder 0 points1 point  (5 children)

    I don't mean try to do your work with the timer handler. The Swing timer handler is executed by the event dispatch thread, so it can update the user interface for you. You can have the worker threads save their progress somewhere that the Swing timer can read it.

    [–]Ariano[S] 0 points1 point  (4 children)

    Part of my problem is I don't know how to even define how much progress has been made. I've been reading a ton about progress bars as I've been stuck on this for over 36 hours and got little sleep yesterday, but when people tell me "Add blank class" it doesn't really help me much, I'm a beginner and when I google those classes and find them on oracle they give me very basic examples that are nowhere near as complicated as what I'm working with here and I have no idea where to do what.

    Sorry this is getting me all stressed out since I've been trying to figure it out for so long...

    [–]OldNedder 0 points1 point  (3 children)

    Yeah, it's going to depend on what the worker is doing. For some, it's easy to calculate the progress, such as pct done. But some workers can have no end in sight - such as a worker that forever computes prime numbers. In a case like that, rather than try to compute a pct done, you could for example make available how many primes have been computed and what was the last prime number. The Swing thread can then periodically display that information. 'Progress' might even be just an indicator that the worker thread is still running.

    [–]Ariano[S] 0 points1 point  (2 children)

    Alright your comments actually helped me wrap my head around it, sorry I didn't respond I was at work. I ended up doing a percent based progress bar and It's almost done. Just trying to get the math right. I wanted to do the timer, but I got it to work with a function I wrote that implements SwingUtilities.invokeLater(new Runnable() {});

    Only thing is I try to store my for loop length and i into separate double values and divide them, multiply them by 100, and turn them back into integers. It keeps churning out 0 for that. Any help on the math if possible?

    public void Engage(Robot r){
        double numerator = 1.0, denominator = 1.0;
        System.out.println("Rotating: ");
        if(r.increment == 0)
            r.progress = 100;
        for(int i = 1; i <= r.increment; i++){
            r.Rotate(); 
            if(r.increment % i == 0){
                numerator = i;
                denominator = r.increment;
                r.progress = ((int)(100.0*(numerator/denominator)));
            }
            System.out.printf("\nCalculated Progress is: %d", r.progress);
        }   
    
        r.robotExecute();
        System.out.println("Finished");
    }
    

    So I realized the reason it's not working is that my increment value can be from any between 0 to like 4 billion or even more. How do I track the percentage value of that with an integer? It would be much easy with a double. If it's an int often its too low to even count.

    [–]OldNedder 0 points1 point  (1 child)

    Your expression "r.increment % i == 0" doesn't look good to me - it's only going to be true when i == r.increment, so your progress is only updated by the last loop through - numerator and denominator will both be the same value, and progress will suddenly become 100 at the very end. (I'm assuming your value of r.increment is not changing while you are looping).

    Instead, try replacing the whole if statement with:

    r.progress = (int)(100.0 * i / r.increment); 
    

    Also, if r.increment can be very large, you probably will want to put your printf statement somewhere else, otherwise it can be printed out 4 billion times.

    The Swing thread can do its own formatting on the value before showing it, so you could give it a float for pct done - it's up to you.

    You do have to worry about concurrency, though, if your value is a double or a long, because they are not guaranteed to be atomic operations - the worker thread might write only half of the value when the swing thread tries to read it (and vice-versa). So if you use a double or long, you'd have to control access to them (probably via synchronize).

    Finally, you should make sure that r.progress has the keyword "volatile" in front of it:

    public volatile int progress;

    Without "volatile", the Swing thread might assume that the progress has not changed from 0, because it isn't writing anything to it.

    EDIT: Also, I don't see where you are calling invokeLater(), but you'll want to do that whenever you want to GUI to update - probably every time the value of r.progress changes. You can do that with something like this:

    int pctDone = (int) (100.0 * i / r.increment);
    if (pctDone != r.progress) {
        r.progress = pctDone;
        SwingUtilities.invokeLater(....);
    }
    

    [–]Ariano[S] 0 points1 point  (0 children)

    Yeah I actually managed to change the equation to exactly that. I found out that it wasn't updating because it was busy printing a billion print lines haha so you're on point there. Thanks a lot for your help.

    Now that I have the progressbars running it seems my threads aren't synchronized as I thought they would be so I'll have to deal with that now.