Progress Bar with Applescript

纵然是瞬间 提交于 2021-02-11 15:48:36

问题


Is there any way to make a progress bar that is loading as a shell script or shell command runs?

I currently use the following:

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

I think this is a fake progress bar once which does not execute together with the shell script.


回答1:


The user interface will be blocked if you don't give the system time to handle events - by using a tight repeat loop, for example. If a loop is needed, you can periodically call a handler to update the UI, or manually handle system events. For a third party scriptable progress indicator background application there is also the SKProgressBar from one of the MacScripter regulars.

If you are planning to use a shell script, note that it will also block the user interface if it takes time to complete, and may not provide feedback that you can use for its progress. Anything that will take time to to complete should be performed with an asynchronous background task, but AppleScriptObjC is a bit limited in that regard. NSTask provides a way to perform background tasks with notifications, so you might want to check that out, as its use and arranging your app around the notifications is another subject.

You should start using an Objective-C category that provides access to the new block-based alert methods, but to keep using the old deprecated sheet method you will need to use action handlers for any buttons (such as a cancel) you want to add. The following Xcode project (just create a blank AppleScriptObjC project and copy to the AppDelegate file) uses your counter to simulate the progress:

# 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


来源:https://stackoverflow.com/questions/59096595/progress-bar-with-applescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!