Objective c 如何正确显示";“进展”;在使用Grand Central Dispatch处理某件事情时,是否以MODALY方式创建工作表?
我试图在包含单个进度条的窗口上显示一个工作表,以显示使用Grand Central Dispatch异步运行的某个长函数的进度。我几乎已经找到了它,但无法使工作表显示在焦点位置,可能是因为我没有使用Objective c 如何正确显示";“进展”;在使用Grand Central Dispatch处理某件事情时,是否以MODALY方式创建工作表?,objective-c,cocoa,grand-central-dispatch,Objective C,Cocoa,Grand Central Dispatch,我试图在包含单个进度条的窗口上显示一个工作表,以显示使用Grand Central Dispatch异步运行的某个长函数的进度。我几乎已经找到了它,但无法使工作表显示在焦点位置,可能是因为我没有使用runModalForWindow:或类似工具 这大概就是我目前正在做的,它是由于按下主窗口上的按钮而发生的: // Prepare sheet and show it... [NSApp beginSheet:progressSheet modalForWindow:window
runModalForWindow:
或类似工具
这大概就是我目前正在做的,它是由于按下主窗口上的按钮而发生的:
// Prepare sheet and show it...
[NSApp beginSheet:progressSheet modalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
[progressSheet makeKeyAndOrderFront:self];
[progressBar setIndeterminate:NO];
[progressBar setDoubleValue:0.f];
[progressBar startAnimation:self];
// Start computation using GCD...
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (int i = 0; i < 1000; i ++) {
// Do some large computation here
// ...
// Update the progress bar which is in the sheet:
dispatch_async(dispatch_get_main_queue(), ^{
[progressBar setDoubleValue:(double)i];
});
}
// Calculation finished, remove sheet on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[progressBar setIndeterminate:YES];
[NSApp endSheet:progressSheet];
[progressSheet orderOut:self];
});
});
//准备工作表并显示它。。。
[NSApp beginSheet:progressSheet modalForWindow:window modalDelegate:nil DiEndSelector:NULL上下文信息:NULL];
[progressSheet MakeKeyandDerfront:self];
[进度条设置不确定:否];
[progressBar setDoubleValue:0.f];
[progressBar startAnimation:self];
//使用GCD开始计算。。。
调度异步(调度获取全局队列(0,0)^{
对于(int i=0;i<1000;i++){
//在这里做一些大型计算
// ...
//更新工作表中的进度条:
dispatch\u async(dispatch\u get\u main\u queue()^{
[progressBar setDoubleValue:(double)i];
});
}
//计算完成,移除主螺纹上的薄板
dispatch\u async(dispatch\u get\u main\u queue()^{
[进度条设置不确定:是];
[NSApp尾页:进度页];
[progressSheet orderOut:self];
});
});
这是可行的,除了主窗口仍处于焦点、工作表失焦以及进度条没有动画(除非我在其上使用setUseSThreadAnimation:YES
)
我想我遇到的问题是,在开始异步计算之前,我不确定如何在不阻塞主线程的情况下以模式运行工作表?正如Brad所说,它应该可以工作 为了进行快速测试,我以编程方式创建了一个工作表(通常,您可能会使用nib文件,但它们很难粘贴到此文本中)。如果我从普通Cocoa窗口中的按钮调用下面的代码,它将按预期工作。请注意,工作表上的文本字段是first responder,如果在键盘打开时键入,它将接受输入
#define maxloop 1000
- (IBAction)startTask:(id)sender
{
// Prepare sheet and show it...
breakLoop = NO;
NSRect sheetRect = NSMakeRect(0, 0, 400, 114);
NSWindow *progSheet = [[NSWindow alloc] initWithContentRect:sheetRect
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered
defer:YES];
NSView *contentView = [[NSView alloc] initWithFrame:sheetRect];
NSProgressIndicator *progInd = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(143, 74, 239, 20)];
NSTextField *inputField = [[NSTextField alloc] initWithFrame:NSMakeRect(145, 48, 235, 22)];
NSButton *cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(304, 12, 82, 32)];
cancelButton.bezelStyle = NSRoundedBezelStyle;
cancelButton.title = @"Cancel";
cancelButton.action = @selector(cancelTask:);
cancelButton.target = self;
[contentView addSubview:progInd];
[contentView addSubview:inputField];
[contentView addSubview:cancelButton];
[progSheet setContentView:contentView];
[NSApp beginSheet:progSheet
modalForWindow:self.window
modalDelegate:nil
didEndSelector:NULL
contextInfo:NULL];
[progSheet makeKeyAndOrderFront:self];
[progInd setIndeterminate:NO];
[progInd setDoubleValue:0.f];
[progInd startAnimation:self];
// Start computation using GCD...
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (int i = 0; i < maxloop; i++) {
[NSThread sleepForTimeInterval:0.01];
if (breakLoop)
{
break;
}
// Update the progress bar which is in the sheet:
dispatch_async(dispatch_get_main_queue(), ^{
[progInd setDoubleValue: (double)i/maxloop * 100];
});
}
// Calculation finished, remove sheet on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[progInd setIndeterminate:YES];
[NSApp endSheet:progSheet];
[progSheet orderOut:self];
});
});
}
- (IBAction)cancelTask:(id)sender
{
NSLog(@"Cancelling");
breakLoop = YES;
}
#定义maxloop 1000
-(iAction)startTask:(id)发送方
{
//准备表格并展示它。。。
breakLoop=NO;
NSRect sheetRect=NSMakeRect(0,0,400,114);
NSWindow*程序表=[[NSWindow alloc]initWithContentRect:sheetRect
样式掩码:NSTitledWindowMask
backing:NSBackingStoreBuffered
延期:是];
NSView*contentView=[[NSView alloc]initWithFrame:sheetRect];
NSPROGESSINDICATOR*progInd=[[NSPROGESSINDICATOR alloc]initWithFrame:NSMakeRect(143,74,239,20)];
NSTextField*inputField=[[NSTextField alloc]initWithFrame:NSMakeRect(145,48,235,22)];
NSButton*cancelButton=[[NSButton alloc]initWithFrame:NSMakeRect(304,12,82,32)];
cancelButton.bezelStyle=NSRoundedBezelStyle;
cancelButton.title=@“取消”;
cancelButton.action=@选择器(cancelTask:);
cancelButton.target=self;
[contentView addSubview:progInd];
[contentView addSubview:inputField];
[内容视图添加子视图:取消按钮];
[progSheet setContentView:contentView];
[NSApp开始页:程序页
modalForWindow:self.window
莫代尔德莱盖特:零
DiEndSelector:空
contextInfo:NULL];
[程序表MakeKeyandDerfront:self];
[progInd SetUndeterminate:否];
[progInd setDoubleValue:0.f];
[progInd startAnimation:self];
//使用GCD开始计算。。。
调度异步(调度获取全局队列(0,0)^{
对于(int i=0;i
为难看的表单道歉,但除此之外,此代码按预期工作,因此您看到的问题可能与GCD无关。我遇到了完全相同的问题。经过反复试验,我找到了解决办法。确保工作表的窗口是(a)NSWindow而不是NSPanel(这可能无关紧要),并且该窗口不会显示标题栏(因为它是您正在使用的工作表)
出于这个原因,我关闭了标题栏,但不知何故,它是正确实现焦点所必需的。勾选标题栏复选框将显示我的进度条工作表焦点。为窗口模式运行工作表不应阻止主线程(否则,将不会执行方法开头的
-beginSheet:
位之后的任何内容)。我在这里的应用程序中使用了与此几乎相同的东西(模式表和您一样显示,上面有一个进度条),并且它在后台运行GCD块时可以很好地进行更新。工作表向下滑动的窗口上的控件变灰,表示该窗口对工作表失去了焦点,因此这看起来也很正常。在主线程上是否还有其他东西在排队等待大量操作?@BradLarson我能想到的唯一可能导致问题的另一件事是作为主计算一部分的dispatch\u apply
,但是