【问题标题】:Objective-C, how to display determinate progress bar?Objective-C,如何显示确定的进度条?
【发布时间】:2012-06-04 23:04:46
【问题描述】:

我想在我的应用程序中将进度条显示为确定的而不是不确定的。但是在将其设置为确定时它不起作用(对于不确定的工作就很好)。我有read someother 对此的回答,尽管它们没有奏效。任何帮助将不胜感激 - 谢谢!

@interface AppDelegate : NSObject <NSApplicationDelegate> {

    IBOutlet NSProgressIndicator *showProgress;

}

- (IBAction)someMethod:(id)sender {

    [showProgress setUsesThreadedAnimation:YES];   // This works
    [showProgress startAnimation:self];            // This works
    [showProgress setDoubleValue:(0.1)];           // This does not work
    [showProgress setIndeterminate:NO];            // This does not work

    [self doSomething];
    [self doSomethingElse];
    [self doSomethingMore];
    ....

    [barProgress setDoubleValue:(1.0)];            // This does not work
    [barProgress stopAnimation:self];              // This works

}

更新的代码[工作]:

- (IBAction)someMethod:(id)sender {

    [showProgress setUsesThreadedAnimation:YES];
    [showProgress startAnimation:self];
    [showProgress setIndeterminate:NO];

    [showProgress setDoubleValue:(0.1)];
    [showProgress startAnimation:nil];

    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(backgroundQueue, ^{

        for (NSUInteger i = 0; i < 1; i++) {

            dispatch_async(dispatch_get_main_queue(), ^{
                [barProgress incrementBy:10.0];
            });
        }

    [self doSomething];

            [showProgress incrementBy:...];

        dispatch_async(dispatch_get_main_queue(), ^{

            [showProgress stopAnimation:nil];

        });
    });

    [showProgress setDoubleValue:(1.0)];
}

【问题讨论】:

    标签: objective-c methods progress-bar


    【解决方案1】:

    您的doSomething 方法阻塞了主线程,导致run loop 不循环,进而导致UI 重绘被阻塞。解决方法是在后台队列中的 doSomething 中执行长时间运行的工作,并定期回调主队列以更新进度条。

    我不知道你的 doSomething 方法是做什么的,但为了解释起见,我们假设它运行一个包含 100 步的 for 循环。你会像这样实现它:

    - (void)doSomething
    {
        [showProgress startAnimation:nil];
        dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(backgroundQueue, ^{
            for (NSUInteger i = 0; i < 100; i++) {
                // Do whatever it is you need to do
    
                dispatch_async(dispatch_get_main_queue(), ^{
                    [showProgress incrementBy:1.0];
                });
            }
            // Done with long running task
            dispatch_async(dispatch_get_main_queue(), ^{
                [showProgress stopAnimation:nil];
            });
        });
    }
    

    请记住,您仍然需要将进度指示器设置为确定,初始化其值并设置适当的 minValue 和 maxValue。

    如果您必须在主线程上完成doSomething 中的工作,则可以安排在每个运行循环周期中完成该工作的一小部分,或者在您执行时定期手动旋转运行循环工作,但如果你可以使用它,Grand Central Dispatch (GCD) 将是我的首选。

    【讨论】:

    • ——很棒的例子。我用您的代码示例更新了我的问题以反映工作版本;让我知道我是否遗漏任何内容或您发现任何问题。再次 ;-)
    • 嗨——我有一个关于这个的快速问题。当进度条与启动动画的按钮相关联时,它工作正常。但是我不再需要按钮,即使使用 [showProgress startAnimation:self]; 等参数,动画也不再启动有什么想法吗?
    • 你必须发布你的新代码让我给出任何建议。你又阻塞了主线程?我建议用你的新代码发布一个新问题。
    • 不,代码一点也不新——它只是消除了 (IBAction) 而不是 void (这是您展示的方法)。我将其切换为 void,现在进度条不再显示(或进度)。有什么特别的东西我可能会错过吗?谢谢。您只能每 5 秒编辑一次评论。(单击此框可关闭)
    • IBAction 只是 void 的 #define(参见 AppKit/NSNibDeclarations.h),所以如果这真的是您所做的唯一更改,那么您编译的可执行文件将完全相同相同.如果不是通过按钮,您现在如何调用该方法?更改方法的调用方式很可能是新行为的原因。更改 IBAction -> void 本身没有任何意义。
    猜你喜欢
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多