如何强制刷新 NSTextField 标签
How To Force A NSTextField Label To Refresh
我想做的事情看起来很简单,但是实现却让我很吃力。如何在更改标签值后强制刷新标签?
我刚刚创建了一个简单的进度 window。当主应用程序正在做某事时,我弹出了进度 window,我想在循环执行时更新标签和进度条的值。
我创建了一个新的 NSWindow 和 XIB 文件,其中包含标签和进度条的出口,我正在加载它:
_pbWindow = [[ProgressBar alloc] initWithWindowNibName:@"ProgressBar"];
[_pbWindow showWindow:self];
当我打电话时:
_pbWindow.lblProgress1.stringValue = @"Doing this now...";
我无法让标签在新 window 中实际刷新。
我在这里和 google 进行了搜索,但似乎找不到任何可以告诉我如何在不同的 window 中执行此操作的信息,只有当它位于主要 window 它只会刷新(无论如何,这一直是我的经验)。
我想可能是因为 window 没有焦点,所以我尝试以模态方式打开它:
[[NSApplication sharedApplication] beginSheet:[_pbWindow window]
modalForWindow:[[NSApplication sharedApplication] mainWindow]
modalDelegate:_pbWindow
didEndSelector:nil
contextInfo:nil];
还是不行。
当您设置文本字段的 stringValue
时,文本字段会将自己标记为需要显示(-setNeedsDisplay...
方法之一)。它不会立即显示自己。稍后,在主事件循环期间,应用程序将把它的每个 windows 告诉 -displayIfNeeded
,文本字段的新内容将实际绘制在屏幕上。
但是,由于您处于 运行 长循环中,因此您不允许主事件循环进入 运行 并且 windows 不会得到如果需要,有机会展示。
一种解决方法是在更改 stringValue
:
后直接在文本字段上调用 -displayIfNeeded
_pbWindow.lblProgress1.stringValue = @"Doing this now...";
[_pbWindow.lblProgress1 displayIfNeeded];
但是,不让主事件循环还有其他问题运行。只是解决这个问题仍然存在其他问题。例如,您的应用程序将在 Activity 监视器中显示为无响应,并且当鼠标悬停在其 windows 上时,系统将显示旋转的色轮光标。您应该考虑寻找另一种方式来构建您的应用程序。
例如,您可以 运行 您的进度 window 作为模态 window 在主线程上(使用 -[NSApplication runModalForWindow:]
)并在后台线程上完成工作.工作完成后,调用 -[NSApplication stopModal...]
方法或 -[NSApplication abortModal]
之一(但请阅读文档以了解在什么情况下应该使用哪个,尽管在 10.9 中取消了对 -stopModal...
的一些限制) .主线程将被允许返回到主事件循环,但是模式 window 会阻止用户对 UI 的其余部分做任何他们不应该做的事情 while手术继续进行。
或者,也许该操作实际上不应该垄断您的整个应用程序。也许它应该只是单个 window 的模态。在这种情况下,您可以在 window 上将进度 window 显示为 sheet,在操作期间应将其禁用。使用 -[NSWindow beginSheet:completionHandler:]
开始 sheet 并在后台启动操作。操作完成后,在主线程上调用 -[NSWindow endSheet:...]
方法之一。
如果您 运行 在后台线程上工作,请始终确保使用 GCD 和 dispatch_get_main_queue()
或 [将影响 GUI 的任何更改分流到主线程=23=].
我想做的事情看起来很简单,但是实现却让我很吃力。如何在更改标签值后强制刷新标签?
我刚刚创建了一个简单的进度 window。当主应用程序正在做某事时,我弹出了进度 window,我想在循环执行时更新标签和进度条的值。
我创建了一个新的 NSWindow 和 XIB 文件,其中包含标签和进度条的出口,我正在加载它:
_pbWindow = [[ProgressBar alloc] initWithWindowNibName:@"ProgressBar"];
[_pbWindow showWindow:self];
当我打电话时:
_pbWindow.lblProgress1.stringValue = @"Doing this now...";
我无法让标签在新 window 中实际刷新。
我在这里和 google 进行了搜索,但似乎找不到任何可以告诉我如何在不同的 window 中执行此操作的信息,只有当它位于主要 window 它只会刷新(无论如何,这一直是我的经验)。
我想可能是因为 window 没有焦点,所以我尝试以模态方式打开它:
[[NSApplication sharedApplication] beginSheet:[_pbWindow window]
modalForWindow:[[NSApplication sharedApplication] mainWindow]
modalDelegate:_pbWindow
didEndSelector:nil
contextInfo:nil];
还是不行。
当您设置文本字段的 stringValue
时,文本字段会将自己标记为需要显示(-setNeedsDisplay...
方法之一)。它不会立即显示自己。稍后,在主事件循环期间,应用程序将把它的每个 windows 告诉 -displayIfNeeded
,文本字段的新内容将实际绘制在屏幕上。
但是,由于您处于 运行 长循环中,因此您不允许主事件循环进入 运行 并且 windows 不会得到如果需要,有机会展示。
一种解决方法是在更改 stringValue
:
-displayIfNeeded
_pbWindow.lblProgress1.stringValue = @"Doing this now...";
[_pbWindow.lblProgress1 displayIfNeeded];
但是,不让主事件循环还有其他问题运行。只是解决这个问题仍然存在其他问题。例如,您的应用程序将在 Activity 监视器中显示为无响应,并且当鼠标悬停在其 windows 上时,系统将显示旋转的色轮光标。您应该考虑寻找另一种方式来构建您的应用程序。
例如,您可以 运行 您的进度 window 作为模态 window 在主线程上(使用 -[NSApplication runModalForWindow:]
)并在后台线程上完成工作.工作完成后,调用 -[NSApplication stopModal...]
方法或 -[NSApplication abortModal]
之一(但请阅读文档以了解在什么情况下应该使用哪个,尽管在 10.9 中取消了对 -stopModal...
的一些限制) .主线程将被允许返回到主事件循环,但是模式 window 会阻止用户对 UI 的其余部分做任何他们不应该做的事情 while手术继续进行。
或者,也许该操作实际上不应该垄断您的整个应用程序。也许它应该只是单个 window 的模态。在这种情况下,您可以在 window 上将进度 window 显示为 sheet,在操作期间应将其禁用。使用 -[NSWindow beginSheet:completionHandler:]
开始 sheet 并在后台启动操作。操作完成后,在主线程上调用 -[NSWindow endSheet:...]
方法之一。
如果您 运行 在后台线程上工作,请始终确保使用 GCD 和 dispatch_get_main_queue()
或 [将影响 GUI 的任何更改分流到主线程=23=].