Swift: How to use NSProgressIndicator?
Asked Answered
E

2

10

I want to use an NSProgressIndicator to show some progress. But I couldn't find a method which increases the bar of that control. I did also not find an example on the web.

let progressbar = NSProgressIndicator()
progressbar.frame = NSRect(x: 100, y: 20, width: 150, height: 10)
progressbar.minValue = 0
progressbar.maxValue = 10
self.window.contentView?.addSubview(progressbar)

for i in 0...10 {
    progressbar.incrementBy(1)  //has no effect
}
Edris answered 5/7, 2016 at 21:16 Comment(3)
What is appearing on screen? Is it indeterminate, circular, or otherwise incapable of showing progress? Or is it a determinate bar that just isn't showing any progress?Kisser
@Edris read the documentation developer.apple.com/library/mac/documentation/Cocoa/Reference/…Vittle
@Kisser Yes, it is a determinate bar which isn't showing any progress (it stays grey).Edris
A
11

You won't be able to demonstrate a progress bar in such a tight loop like that.

When you set the value of the progress indicator, the OS X display mechanism won't actually draw the difference until the next time through the event loop, which doesn't happen until after your method returns. In other words, you're setting it all the way to 10 before the progress indicator even gets a chance to redraw itself, so all you see is the final filled state.

You could theoretically force the progress indicator to display after each time through the loop (progressbar.display()), but I don't think you'd be able to distinguish the differences when they happen within, say, 0.01 seconds.

The solution then, is to introduce a small delay between calling incrementBy(1), so that the next event loop can happen and the display of the new value will take place. You can do that by adding something like the following to your code:

func delay(delay:Double, closure:()->()) {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
        Int64(delay * Double(NSEC_PER_SEC))),
                   dispatch_get_main_queue(), closure)
}

class AppDelegate: NSObject, NSApplicationDelegate {
    @IBOutlet weak var progressIndicator: NSProgressIndicator!

    func applicationDidFinishLaunching(aNotification: NSNotification) {
        let progressbar = NSProgressIndicator()
        progressbar.frame = NSRect(x:100, y:20, width:150, height:10)
        progressbar.minValue = 0
        progressbar.maxValue = 10
        self.window.contentView?.addSubview(progressbar)

        self.progressIndicator = progressbar
        progressIndicator.indeterminate = false

        for i in 0...10 {
            delay(1.0 * Double(i), closure: { 
                self.progressIndicator.incrementBy(1)
            })
        }
    }
}

This queues up the calling of incrementBy(1) to be at 1 second intervals.

Anyhow answered 5/7, 2016 at 22:24 Comment(2)
progressbar.indeterminate = false was missing in my code... I am downloading files in my loop, so the delay is not needed here. But I will remember your example for use in the future. Thanks a lot.Edris
Programmatically initializing & setting NSProgressIndicator properties does not work. Has anybody faced this issue?Mitsue
S
0

In my case. the progress did not work. adding :

self.progress_bar.indeterminate = false;

fix the problem.

Stallard answered 9/2, 2021 at 11:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.