1

我正在尝试编写一个简单的 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!")

一切似乎都正常工作,但用户界面有些小故障。进度条不仅会平滑增加,而且会在每一步消失并显示片刻,然后再次消失。中的文本lblStatus确实会顺利更改。

当我从循环中删除时,事情会完全丢失delay:在循环完成之前,不会进行 UI 更改(即使脚本运行正常)。因此,当循环完成时,进度条会消失并重新出现。

这是闪烁 UI 的youtube 视频

我究竟做错了什么?如何让 xcode 顺利绘制进度条?

请注意,这是我第一次编写 Xcode 应用程序,而且我对 Applescript 的了解有些粗略。

编辑:

我发现调用处理相同函数的函数在从菜单项(或绑定到该菜单项的组合键)中调用时没有闪烁的 UI。

4

1 回答 1

1

我不确定为什么进度条会隐藏起来。您是否将它的可见属性绑定到可能使其隐藏的东西?

当我从循环中删除延迟时,事情完全丢失了:没有进行 UI 更改

一般来说,当“没有进行 UI 更改”时,这是因为应用程序在主线程上太忙而无法实时更新界面项。您的所有代码都在主线程上运行。您需要在后台线程上进行一些操作。因此,我有 2 条建议供您尝试。

首先尝试使用进度条的方法“setUsesThreadedAnimation:”。将其添加到您的重复循环上方...

barStatus's setUsesThreadedAnimation_(true)

其次,如果这没有帮助,请尝试将您的重复循环工作移到后台线程(使用 NSThread 的 detachNewThreadSelector :)...但让界面更新发生在主线程上。我不知道 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_

如果您使用后台线程方法,您可能必须在后台线程工作时使界面中的按钮处于非活动状态(因此用户无法按下它们并开始新任务)。因此,只需在调用“detachNewThreadSelector:”之前将其 enabled 属性设置为 false,并在工作完成后再次启用它们。您可以通过另一个启用它们的处理程序并从后台线程代码的末尾调用它来做到这一点。

于 2012-12-21T12:49:30.973 回答