带有Applescript的进度条

问题描述 投票:0回答:1

有什么方法可以使正在加载的进度条当运行shell脚本或shell命令时?

我目前使用以下内容:

property theWindow : missing value
property parent : class "NSObject"
property customView : missing value
property myProgressBar : missing value

on hardwareData()

    set alert to current application's NSAlert's alloc's init()
        tell alert
            its setAccessoryView:customView
            its setMessageText:"Loading Informations"
            its setInformativeText: "Please Wait..."
            its setAlertStyle:1
            its addButtonWithTitle:"Cancel"
            its setShowsSuppressionButton:false
            its beginSheetModalForWindow:theWindow modalDelegate:me didEndSelector:(missing value) contextInfo:(missing value)
        end tell

delay 0.02
set hardwareData to do shell script "system_profiler SPHardwareDataType"

(*This loop loads the progress bar but only after the
shell command was executed and not at run time.*)
set c to 0
        repeat 100 times
            set c to c + 1
            delay 0.06
            tell myProgressBar to setDoubleValue_(c)
            if c > 99 then
                exit repeat
            end if
        end repeat
end hardwareData

我认为这曾经是伪造的进度条不能与shell脚本一起执行。

applescript-objc
1个回答
1
投票

例如,如果您没有给系统时间来处理事件,则用户界面将被阻止-例如,使用紧密的重复循环。如果需要循环,则可以定期调用处理程序以更新UI或手动处理系统事件。对于第三方可编写脚本的进度指示器后台应用程序,还有MacScripter常规程序之一的SKProgressBar

如果您打算使用Shell脚本,请注意,如果花费一些时间来完成操作,它也会阻塞用户界面,并且可能不会提供可用于其进度的反馈。需要花费时间才能完成的所有操作都应使用异步后台任务执行,但是AppleScriptObjC在这方面有一定的局限性。 NSTask提供了一种执行带有通知的后台任务的方法,因此您可能需要检查一下,因为它的使用和在通知周围排列您的应用程序是另一个主题。

您应该开始使用提供对新的基于块的警报方法的访问的Objective-C类别,但是要继续使用旧的不推荐使用的工作表方法,您需要对所需的任何按钮(例如取消)使用操作处理程序加上。以下Xcode项目(只需创建一个空白的AppleScriptObjC项目并复制到AppDelegate文件中)即可使用您的计数器来模拟进度:

# AppDelegate.applescript

script AppDelegate
    property parent : class "NSObject"
    property theWindow : missing value
    property alert : missing value  -- this will be the alert
    property myProgressBar : missing value -- this will be the progress indicator
    property alertCancel : false -- this will be a flag to indicate cancel

    to makeButton(title, x, y) -- make a button at the {x, y} position
        tell (current application's NSButton's buttonWithTitle:title target:me action:"buttonAction:")
            its setFrame:{{x, y}, {120, 24}}
            its setRefusesFirstResponder:true -- no highlight
            return it
        end tell
    end makeButton

    on buttonAction:sender -- perform the alert
        if alert is missing value then tell current application's NSAlert's alloc's init()
            set my alert to it
            its setMessageText:"Loading Informations"
            its setInformativeText:"Please Wait..."
            set cancelButton to its addButtonWithTitle:"Cancel"
            cancelButton's setTarget:me
            cancelButton's setAction:"cancelButton:"
            its setAccessoryView:(my makeIndicator())
        end tell
        set my alertCancel to false -- reset
        myProgressBar's setDoubleValue:0
        alert's beginSheetModalForWindow:theWindow modalDelegate:me didEndSelector:(missing value) contextInfo:(missing value)
        doStuff()
    end buttonAction:

    on cancelButton:sender -- mark alert as cancelled
        set my alertCancel to true
        current application's NSApp's endSheet:(alert's |window|)
    end cancelButton:

    to makeIndicator() -- make and return a progress indicator
        alert's layout()
        set theSize to second item of ((alert's |window|'s frame) as list)
        set width to (first item of theSize) - 125 -- match alert width
        tell (current application's NSProgressIndicator's alloc's initWithFrame:{{0, 0}, {width, 22}})
            set myProgressBar to it
            set its indeterminate to false
            set its maxValue to 100
            return it
        end tell
    end makeIndicator

    on doStuff() -- the main progress loop
        set c to 0
        repeat 100 times
            set c to c + 1
            delay 0.06 -- do something
            tell myProgressBar to setDoubleValue:c
            fetchEvents()
            if c > 99 or alertCancel then exit repeat
        end repeat
        current application's NSApp's endSheet:(alert's |window|)
    end doStuff

    on fetchEvents() -- handle user events
        repeat -- forever
            tell current application's NSApp to set theEvent to its nextEventMatchingMask:(current application's NSEventMaskAny) untilDate:(missing value) inMode:(current application's NSDefaultRunLoopMode) dequeue:true
            if theEvent is missing value then return -- none left
            tell current application's NSApp to sendEvent:theEvent -- pass it on
        end repeat
    end fetchEvents

    ##################################################
    #   Delegate methods
    ##################################################

    on applicationWillFinishLaunching:aNotification
        theWindow's contentView's addSubview:makeButton("Show Alert", 180, 30)
    end applicationWillFinishLaunching:

    on applicationShouldTerminate:sender
        return current application's NSTerminateNow
    end applicationShouldTerminate:

end script
© www.soinside.com 2019 - 2024. All rights reserved.