如何在长期运行循环中更新Cocoa中的进度条? [英] How do I update a progress bar in Cocoa during a long running loop?

查看:178
本文介绍了如何在长期运行循环中更新Cocoa中的进度条?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 while 循环,运行了很多秒,这就是为什么我想在进程中更新进度条(NSProgressIndicator),但它只更新一次循环结束后。如果我想更新标签文本,同样会发生。

I've got a while loop, that runs for many seconds and that's why I want to update a progress bar (NSProgressIndicator) during that process, but it updates only once after the loop has finished. The same happens if I want to update a label text, by the way.

我相信,我的循环会阻止应用程序的其他事情发生。必须有另一种技术。这与线程或东西有关吗?我在正确的轨道上吗?有人可以给我一个简单的例子,如何优化我的应用程序?

I believe, my loop prevents other things of that application to happen. There must be another technique. Does this have to do with threads or something? Am I on the right track? Can someone please give me a simple example, how to "optimize" my application?

我的应用程序是一个Cocoa应用程序(Xcode 3.2.1) Example_AppDelegate.m

My application is a Cocoa Application (Xcode 3.2.1) with these two methods in my Example_AppDelegate.m:


// This method runs when a start button is clicked.
- (IBAction)startIt:(id)sender {
    [progressbar setDoubleValue:0.0];
    [progressbar startAnimation:sender];
    running = YES; // this is a instance variable

    int i = 0;
    while (running) {
        if (i++ >= processAmount) { // processAmount is something like 1000000
            running = NO;
            continue;
        }

        // Update progress bar
        double progr = (double)i / (double)processAmount;
        NSLog(@"progr: %f", progr); // Logs values between 0.0 and 1.0
        [progressbar setDoubleValue:progr];
        [progressbar needsDisplay]; // Do I need this?

        // Do some more hard work here...
    }
}

// This method runs when a stop button is clicked, but as long
// as -startIt is busy, a click on the stop button does nothing.
- (IBAction)stopIt:(id)sender {
    NSLog(@"Stop it!");
    running = NO;
    [progressbar stopAnimation:sender];
}



我真的很新的Objective-C,Cocoa和应用程序与UI。非常感谢任何有用的答案。

I'm really new to Objective-C, Cocoa and applications with a UI. Thank you very much for any helpful answer.

推荐答案

如果你正在修建雪豹,最简单的解决方案是我认为使用块和Grand Central Dispatch。

If you are building for Snow Leopard, the easiest solution is in my opinion to use blocks and Grand Central Dispatch.

以下代码显示了当您使用 startIt: GCD。

The following code shows you how your startIt: method would look like when using GCD.

您的 stopIt:方法应该像您写的那样正常工作。之所以它之前没有工作的原因是鼠标事件发生在主线程上,因此按钮没有响应你,因为你在主线程上做工作。这个问题现在应该已经解决,因为工作已经放在不同的线程现在与GCD。尝试代码,如果它不工作,让我知道,我会看到,如果我犯了一些错误。

Your stopIt: method should work fine as you wrote it. The reason why it wasn't working before is that mouse events happen on the main thread and thus the button didn't respond to you because you were doing work on the main thread. This issue should have been resolved now as the work has been put on a different thread now with GCD. Try the code, and if it doesn't work, let me know and I will see if I made some errors in it.

// This method runs when a start button is clicked.
- (IBAction)startIt:(id)sender {

    //Create the block that we wish to run on a different thread.
    void (^progressBlock)(void);
    progressBlock = ^{

    [progressbar setDoubleValue:0.0];
    [progressbar startAnimation:sender];
    running = YES; // this is a instance variable

    int i = 0;
    while (running) {
        if (i++ >= processAmount) { // processAmount is something like 1000000
            running = NO;
            continue;
        }

        // Update progress bar
        double progr = (double)i / (double)processAmount;
        NSLog(@"progr: %f", progr); // Logs values between 0.0 and 1.0

        //NOTE: It is important to let all UI updates occur on the main thread,
        //so we put the following UI updates on the main queue.
        dispatch_async(dispatch_get_main_queue(), ^{
            [progressbar setDoubleValue:progr];
            [progressbar setNeedsDisplay:YES];
        });

        // Do some more hard work here...
    }

    }; //end of progressBlock

    //Finally, run the block on a different thread.
    dispatch_queue_t queue = dispatch_get_global_queue(0,0);
    dispatch_async(queue,progressBlock);
}

这篇关于如何在长期运行循环中更新Cocoa中的进度条?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆