我正在尝试编写一个简单的xcode cocoa-applescript程序,该程序在文件夹的每个子文件夹上执行一个bash脚本,并在执行它时显示一个进度键。
我设置了一个NSProgressIndicator
,要链接到barStatus
,并且将NSTextField
链接到lblStatus
,以显示一些有益的文本:
property barStatus : missing value
property lblStatus : missing value
这是发生主要动作的循环:
tell application "Finder" to set subfolders to every folder of folder macPath
barStatus's setIndeterminate_(false)
barStatus's setDoubleValue_(0)
barStatus's setMaxValue_(count of subfolders)
repeat with eachFolder in subfolders
set posixPath to (POSIX path of (eachFolder as text)) as text
-- set text of progress indicator text
lblStatus's setStringValue_("Resizing '" & ( do shell script "basename "" & (posixPath) & "" | sed "s/^.*_//"" ) & "'...")
delay 0.5
-- do the shell script
do shell script "bash ~/.uploader/image.sh "" & posixPath & """
-- step the indicator
barStatus's incrementBy_(1)
end repeat
lblStatus's setStringValue_("Done!")
似乎都可以正常工作,但是UI有些故障。进度栏在每个步骤上都消失了,而不仅会平稳地增加,而且显示了一小段时间,然后再次出现。lblStatus
中的文字确实会顺利更改。
当我从循环中删除delay
时,事情会完全丢失:没有进行UI更改(即使脚本可以正确运行),直到循环完成为止。因此,进度栏只是在循环完成后填写出来的出现。
这是闪烁UI的YouTube视频。
我在做什么错?如何使Xcode平滑绘制progressbar?
请注意,这是我第一次编写Xcode应用,我对AppleScript的了解有些粗略。
编辑:
我发现调用相同函数的函数时,当称为菜单项时没有闪烁UI(或键入该菜单项的键组合)。
我不确定为什么进度栏会隐藏自身。您是否将其可见属性绑定到可能使其隐藏的东西?
当我从循环中删除延迟时,事情完全丢失了:没有UI 更改
一般而言,尽管当"不进行UI更改"时,这是因为该应用程序在主线程上太忙了,无法实时更新接口项目。您的所有代码都在主线程上运行。您需要在背景线程上进行一些事情。因此,我有2个建议可以尝试。
首先尝试使用Progress Bar的方法" setUsesthreadEdanimation:"。将其添加在您的重复循环上方...
barStatus's setUsesThreadedAnimation_(true)
第二,如果这无济于事,请尝试将重复循环工作移至背景线程(使用NSTHREAD的distachNewThreadSelector:)...但是使接口更新发生在主线程上。我不知道AppleScriptObjc语言,因此以下代码可能完全错误。您必须正确编写它,但它将向您展示这个主意...
[NSThread detachNewThreadSelector:@selector(processFolderListOnBacgroundThread_) toTarget:self withObject:subfolders];
-- this will happen on the main thread
on updateProgressBarByOne_()
barStatus's' incrementBy_(1)
end updateProgressBarByOne_
-- this will happen on the main thread
on updateStatusTextWithText_(statusText)
lblStatus's' setStringValue_(statusText)
end updateInterfaceItemsOnMainThreadWithObject_
-- this will happen on a background thread
on processFolderListOnBacgroundThread_(subFolders)
repeat with eachFolder in subfolders
set posixPath to (POSIX path of (eachFolder as text)) as text
-- set text of progress indicator text
my updateStatusTextWithText_("Resizing '" & ( do shell script "basename "" & (posixPath) & "" | sed "s/^.*_//"" ) & "'...")
-- do the shell script
do shell script "bash ~/.uploader/image.sh "" & posixPath & """
-- step the indicator
my updateProgressBarByOne_()
end repeat
my updateStatusTextWithText_("Done!")
end processFolderListOnBacgroundThread_
如果使用背景线程方法,则可能必须在背景线程正常工作时使接口中的按钮不活跃(因此用户不能按下它们并启动新任务)。因此,只需在调用" distachnewthreadselector:"之前将其启用属性设置为false:然后在工作完成后再次启用它们。您可以通过拥有另一个启用它们并从背景线程代码末尾调用的处理程序来做到这一点。