AppleScript-Fortschrittsbalken-Fehler: Wie kann verhindert werden, dass der Fortschrittsdialog verweilt?

Der Fehler:

Wenn auf den Fortschrittsdialog von AppleScript ein Dialog folgt, bleibt der Fortschrittsdialog bestehen – obwohl alle Fortschrittsschritte abgeschlossen wurden und der Fortschrittsbalken voll ist. Es bleibt bestehen, bis das Skript abgebrochen wurde, bis das Skript abgeschlossen ist oder bis keine weiteren Dialogfelder im Skript vorhanden sind.

Dieser Fehler kann nicht beobachtet werden, während der Code in Script Editor.app ausgeführt wird, da im Script Editor kein Fortschrittsdialogfeld angezeigt wird. Stattdessen ist unten im Skriptfenster eine tortenförmige Fortschrittsanzeige integriert.


So reproduzieren Sie den Fehler:

Speichern Sie den folgenden AppleScript -Code als .app-Datei:

(Die Datei muss eine .app-Datei sein, da .scpt-Dateien keine Fortschrittsdialoge anzeigen können.)

set n to 5

set progress total steps to n
set progress description to "Script Progress"
set progress additional description to "Additional description"

repeat with i from 1 to n
    delay 0.1
    set progress completed steps to i
end repeat

display dialog "The progress dialog should be gone at this point."

Nach dem Start der Anwendung sehen Sie Folgendes:


Die Frage:

Gibt es eine Problemumgehung, um das Schließen des Fortschrittsdialogs zu erzwingen, sobald er abgeschlossen ist, sodass zusätzliche Dialoge nach dem Fortschrittsdialog platziert werden können, ohne dass der Fortschrittsdialog noch sichtbar ist?


Was ich versucht habe:

Ich habe versucht, das Problem anzugehen, indem ich den Fortschrittsdialog einfach als "Fenster" der App interpretierte.

Wenn Sie den folgenden Code in einer separaten AppleScript-Datei ausführen, während beide Dialoge von ProgressBarTest.app auf dem Bildschirm angezeigt werden (wie im obigen Screenshot):

tell application "System Events"
    set allWindows to name of window of processes whose visible is true
end tell 

return allWindows

Sie werden erfahren, dass ProgressBarTest.app 2 offene "Fenster" hat. Die Titel dieser Fenster lauten:

{"", "ProgressBarTest.app"}

Das erste Fenster in dieser Liste bezieht sich auf den display dialogDialog. Das zweite Fenster in dieser Liste mit dem Titel ProgressBarTest.appist der Fortschrittsdialog.

Ich habe dann versucht, dieses Fortschrittsdialog-"Fenster" mit AppleScript zu schließen (wie man es für jedes Standardanwendungsfenster tun kann). Aber folgender Code:

tell application "System Events" to tell process "ProgressBarTest.app"
    if exists window "ProgressBarTest.app" then
        close window "ProgressBarTest.app"
    end if
end tell

gibt dem Benutzer einen Fehler. Der Text dieses Fehlerdialogs lautet:

Skriptfehler

Bei Systemereignissen ist ein Fehler aufgetreten: Das Fenster „ProgressBarTest.app“ des Prozesses „ProgressBarTest.app“ versteht die Meldung „Schließen“ nicht.

Mir wurde schnell klar, dass Sie den Fortschrittsdialog nicht einmal manuell schließen können, wenn Ihr Bildschirm den gleichen Standpunkt wie der des obigen Screenshots hat. Dies liegt daran, dass der display dialogDialog Vorrang vor dem Fortschrittsdialog hat; der display dialogDialog "graut aus" (dh deaktiviert) alle Schaltflächen im Fortschrittsdialog.

Um dies zu berücksichtigen, habe ich im Code von ProgressBarTest.app ein delay 5direkt über der display dialog "The progress dialog should be gone at this point."Zeile hinzugefügt. Ich wollte sehen, ob ich den Fortschrittsdialog erfolgreich schließen kann, wenn der Fortschrittsdialog der einzige aktive Dialog der Anwendung ist.

Ich habe folgenden Code ausprobiert:

tell application "System Events" to tell process "ProgressBarTest.app"
    if exists window "ProgressBarTest.app" then
        click button 1 of window "ProgressBarTest.app"
    end if
end tell

Bezieht sich im obigen Code button 1auf die StopSchaltfläche, die sich im Fortschrittsdialog befindet. (Sie können alternativ button -4oder verwenden button 0, um auf dieselbe Schaltfläche zu verweisen.)

Die gute Nachricht ist, dass dieser Code den Fortschrittsdialog erfolgreich geschlossen hat!

Die schlechte Nachricht ist jedoch, dass beim Drücken der StopSchaltfläche des Fortschrittsdialogs nicht nur der Fortschrittsdialog geschlossen wird, sondern das gesamte Skript abgebrochen wird. Dies ist offensichtlich unerwünscht.

Die Wurzel des Problems liegt darin, dass der Fortschrittsdialog kein rotes „x“ enthält; Die kreisförmige Schaltfläche ganz links in der oberen Leiste dieses Dialogfelds ist immer ausgegraut. Mit anderen Worten, es gibt keine Möglichkeit, den Fortschrittsdialog manuell zu schließen, ohne auch das Skript vorzeitig zu beenden.

Dieses Problem ist also schwieriger zu lösen, als ich dachte.

Es scheint, dass mein gewünschtes Ergebnis unmöglich zu erreichen ist.


OS X El Capitan, Version 10.11.6.


Bist du jemals zu einer Lösung dafür gekommen? Sie haben das Thema perfekt dargestellt; Es scheint ein ziemlicher Designfehler zu sein, dass Apple keinen Schalter für die Sichtbarkeit des Fortschrittsbalkens bereitgestellt hätte.
@IvanX habe ich nicht.
@IvanX Ich habe einen Code in einer Antwort mit einer Lösung gepostet

Antworten (1)

Funktioniert für mich auf der neuesten Version von macOS Big Sur

AKTUALISIEREN

BESTE LÖSUNG

Wenn Sie den display dialogBefehl innerhalb von platzieren und den Befehl dann um diesen Befehl System Events tell blockwickeln , führt der seine Aufgabe aus, ohne darauf zu warten, dass das Fenster geschlossen wird.ignoring application responsesdisplay dialogprogress indicatordisplay dialog

Der ignoring application responsesBefehl funktioniert nur, wenn er innerhalb einer Anwendung platziert wirdtell block

set n to 50

set progress total steps to n
set progress description to "Script Progress"
set progress additional description to "Additional description"

repeat with i from 1 to n
    delay 0.1
    set progress completed steps to i
end repeat

tell application "System Events"
    activate
    ignoring application responses
        display dialog "The progress dialog should be gone at this point."
    end ignoring
end tell

Geben Sie hier die Bildbeschreibung ein



ALTE LÖSUNG 1

set n to 5

set progress total steps to n
set progress description to "Script Progress"
set progress additional description to "Additional description"

repeat with i from 1 to n
    delay 0.1
    set progress completed steps to i
end repeat
return
quit

on quit
    activate
    display dialog "The progress dialog should be gone at this point."
    continue quit -- allows the script to quit
end quit

Hier ist eine Möglichkeit, einige Wiederholungsschleifen auszuführen, bevor das Skript beendet wird

set n to 5

set progress total steps to n
set progress description to "Script Progress"
set progress additional description to "Additional description"

repeat with i from 1 to n
    delay 0.1
    set progress completed steps to i
end repeat
return
quit

on quit
    activate
    display dialog "The progress dialog should be gone at this point."
    repeat 5 times
        my get_my_IP()
        my screenCaptureToDesktop()
        delay 1
    end repeat
    continue quit -- allows the script to quit
end quit


on get_my_IP()
    activate
    tell current application to display dialog (do shell script "curl ifconfig.co") with icon 2 buttons "OK" default button 1 with title "Your Current IP Address Is.." giving up after 5 -- "curl ifconfig.io"    -- alternate
end get_my_IP

on screenCaptureToDesktop()
    do shell script "/usr/sbin/screencapture \"" & ¬
        POSIX path of (path to desktop as string) & ¬
        "Screen Shot " & (current date) & ".png\""
end screenCaptureToDesktop

ALTE LÖSUNG 2

Als ich an einem meiner eigenen Projekte arbeitete, hatte ich eines dieser "EUREKA!" Momente. Hier ist ein völlig anderer Ansatz als mein Code in LÖSUNG 1. Der Ansatz hier bestand darin, den größten Teil meines Codes in Skriptobjekte oder Handler einzuschließen und diese Objekte dann nach Bedarf aufzurufen. In dieser Lösung habe ich dieses Skript als geöffnet bleibende Anwendung mit expliziten Run- und Idle-Handlern gespeichert. Ein Teil des Codes wird ausgeführt, wenn die Anwendung gestartet wird, aber die meisten Befehle werden tatsächlich innerhalb des Idle-Handlers ausgeführt.

Ich denke, diese Lösung ist vielversprechender als LÖSUNG 1.

global allFiles, thisFile, theFileCount, ProgressBar, mainFolder, backupFolder, theDate

on run
    run ProgressBar
end run

on idle
    delay 0.2
    activate
    set theButton to button returned of (display dialog ¬
        "The progress dialog should be gone at this point." buttons {"QUIT", "CONTINUE"} ¬
        default button ¬
        "CONTINUE" with title ¬
        "BACKUP UTILITY" with icon 0 ¬
        giving up after 10)
    if theButton = "QUIT" then
        quit
    else if theButton = "" then
        quit
    else if theButton = "CONTINUE" then
        try
            run ProgressBar
        end try
    end if
    return 1
end idle

on quit
    --  Executed when the script quits
    continue quit -- allows the script to quit
end quit

script ProgressBar
    set mainFolder to choose folder with prompt ¬
        "PLEASE CHOOSE YOUR SOURCE FOLDER TO BACKUP"
    set backupFolder to choose folder with prompt ¬
        "PLEASE CHOOSE YOUR BACKUP DESTINATION FOLDER"
    set theDate to (current date) - (14 * days)
    
    tell application "Finder"
        set allFiles to entire contents of folder mainFolder as alias list
    end tell
    
    set theFileCount to count of allFiles
    
    set progress total steps to theFileCount
    set progress completed steps to 0
    set progress description to "Processing Files..."
    set progress additional description to "Preparing to process."
    
    repeat with theName from 1 to number of items in allFiles
        set this_item to item theName of allFiles
        tell application "Finder"
            duplicate this_item to backupFolder ¬
                with replacing
        end tell
        set progress additional description to ¬
            "Duplicating File " & theName & " of " & theFileCount & ¬
            " to folder " & backupFolder
        set progress completed steps to theName
    end repeat
    
    -- Reset the progress information
    set progress total steps to 0
    set progress completed steps to 0
    set progress description to ""
    set progress additional description to ""
end script
Alle anderen Befehle, die Sie ausführen möchten, fügen Sie sie einfach in den Quit-Handler vor dem Befehl "Continue Quit" ein
Wow, ich gebe Ihnen großen Dank dafür, dass Sie diese Problemumgehung entdeckt haben. Ihre Methode löst tatsächlich meine Frage. Praktisch in meinen realen Anwendungen implementiert, hat diese Methode ihre Grenzen. Da es keine Möglichkeit gibt, das on quitUnterprogramm zu verlassen, sobald es einmal eingegeben wurde, ist es beispielsweise nicht mehr möglich, das gesamte Skript in eine repeatSchleife zu packen. Auf jeden Fall glaube ich nicht, dass ich eine bessere Problemumgehung als Ihre Methode finden werde! Danke!
@rubik'ssphere Möglicherweise können Sie nicht das gesamte Skript in eine Wiederholungsschleife einschließen, aber ich habe den Code aktualisiert, um ein Beispiel dafür zu zeigen, wie Sie einige Wiederholungsschleifen innerhalb des Quit-Handlers ausführen können. Sie können die anderen Handler mit ihren eigenen Wiederholungsschleifen und Unterroutinen enorm machen
Sehr coole Abhilfe. (Und immer noch eine bizarre Designentscheidung von Apple.)
Beim Testen unter macOS Catalina hatte ich folgende Probleme: 1. Obwohl ich der Test.app die Berechtigung erteilte, ihr die Kontrolle über den Finder zu erlauben, zeigte sie den Anzeigedialog nicht an, bis ich den Block vorübergehend ignoring application responses auskommentiert , erneut gespeichert und ausgeführt hatte, um die Erlaubnis erneut zu erteilen und dann den Block auskommentieren, erneut speichern, erneut ausführen und erneut die Erlaubnis geben, und erst nach all dem Tanz würde der Anzeigedialog normal angezeigt. 2. Die Verwendung von Finder ist ärgerlich, da es jedes offene Finder - Fenster nach vorne bringt .
Um das Problem mit dem Finder - Fenster zu umgehen, habe ich stattdessen Systemereignisse verwendet, und dies hat keine anderen geöffneten Fenster beeinträchtigt . Sie könnten dies im Code Ihrer Antwort ändern.
@ user3439894 Guter Fang. Jetzt überarbeiten. Übrigens, ich musste nur den gleichen Song und Tanz durchgehen wie du, um es zum Laufen zu bringenSystem Events
Ja, ich musste auch den Tanz mit System Events und Finder machen . Es ist keine große Sache, aber es war erwähnenswert, falls andere auch ein Problem haben.