我想做的事情似乎很简单,但实施却让我失望。在更改标签后,如何强制标签刷新?
我刚创建了一个简单的进度窗口。由于主应用程序正在执行某些操作,因此我会弹出进度窗口,并且我希望在循环执行时更新标签和进度条的值。
我创建了一个新的NSWindow和XIB文件,其中包含标签和进度条的插座,我正在加载它:
_pbWindow = [[ProgressBar alloc] initWithWindowNibName:@"ProgressBar"];
[_pbWindow showWindow:self];
我打电话的时候:
_pbWindow.lblProgress1.stringValue = @"Doing this now...";
我无法在新窗口中实际刷新标签。
我在这里搜索过谷歌并且似乎找不到任何东西告诉我如何在另一个窗口中执行此操作,只是如果它在主窗口中它只会刷新(如无论如何,一直是我的经历。)
我想也许是因为窗户没有焦点所以我尝试以模态打开它:
[[NSApplication sharedApplication] beginSheet:[_pbWindow window]
modalForWindow:[[NSApplication sharedApplication] mainWindow]
modalDelegate:_pbWindow
didEndSelector:nil
contextInfo:nil];
但它仍然没有用。
答案 0 :(得分:2)
当您设置文本字段stringValue
时,文本字段会将自己标记为需要显示(-setNeedsDisplay...
方法之一)。它不会立即显示出来。稍后,在主事件循环期间,应用程序将告诉每个窗口-displayIfNeeded
,并且实际上将在屏幕上绘制文本字段的新内容。
但是,由于您处于长时间运行的循环中,因此您不允许运行主事件循环,并且如果需要,窗口也无法显示。
一种解决方法是在更改-displayIfNeeded
后在文本字段上直接调用stringValue
:
_pbWindow.lblProgress1.stringValue = @"Doing this now...";
[_pbWindow.lblProgress1 displayIfNeeded];
但是,不让主事件循环运行还有其他问题。解决这个问题仍然是其他问题。例如,您的应用程序将在活动监视器中显示为无响应,当鼠标悬停在窗口上时,系统将显示旋转的色轮光标。您应该考虑寻找另一种方法来构建您的应用。
例如,您可以将进度窗口作为主线程上的模态窗口运行(使用-[NSApplication runModalForWindow:]
)并在后台线程上进行工作。工作完成后,调用其中一个-[NSApplication stopModal...]
方法或-[NSApplication abortModal]
(但请阅读文档以查看应在何种情况下使用哪些方法,尽管在{10}中取消了对-stopModal...
的一些限制) 。主线程将被允许返回主事件循环,但模态窗口将阻止用户对操作进行时不应允许他们执行的UI的其余部分执行任何操作。
或者,也许操作不应该实际上垄断整个应用程序。也许它应该只是单个窗口的模态。在这种情况下,您可以将进度窗口显示为窗口上的工作表,该窗口应在操作期间禁用。使用-[NSWindow beginSheet:completionHandler:]
开始工作表,然后在后台开始操作。操作完成后,在主线程上调用其中一个-[NSWindow endSheet:...]
方法。
如果您在后台线程上运行工作,请务必使用GCD和dispatch_get_main_queue()
或-performSelectorOnMainThread:...
将所有会影响GUI的更改分流到主线程。