Wie kann man Funktionen im Tray Menü unabhängig voneinander ausführen?

  • Hallo liebe Helfer,

    habe soeben ein Skript erstellt, welches ein Tray-Menü anlegt. Das komplette Skript ist auch beigefügt. Unter dem Menüpunkt "Dezimal, ..." kann man eine Funktion _AsciiCode() aufrufen.

    (Codeauszüge entfernt, merlinuwe; vgl. meinen Folgebeitrag)

    Zwei Fragen:

    • Was muss ich tun, damit ich, obwohl diese Funktion _AsciiCode() noch weiterläuft, sofort das Menü "Über" anzeigen kann? (Zurzeit läuft zunächst die Funktion _AsciiCode() weiter. Erst sobald diese beendet ist, erscheint das (zuvor ausgewählte) "Über"-Fenster.)
    • Wie kann ich das gesamte Programm abbrechen, ohne den kompletten Durchlauf der Funktion _AsciiCode() abzuwarten?


    Ich möchte quasi die Menüpunkte (Funktionen) des Tray-Menüs unabhängig voneinander aufrufen können.
    Freue mich auf jede Hilfe (z. B. einen Hinweis auf ein existierendes Tutorial zum Thema TrayMenü).

    Freundliche Grüße

    merlinuwe

  • Abgesehen davon, könntest du versuchen dein Programm auf den Eventmodus für Traymenüs umzustellen (Opt("TrayOnEventMode", 1)). Dadurch läuft die Abfrage des Traymenüs unabhängig von der Hauptschleife und sollte nicht all zu sehr durch deine Zeitaufwändigen Funktionen beeinflusst werden ;).

  • hi name22,
    hi alpines,

    vielen Dank für eure Tipps.

    Habe das Problem erst einmal vereinfacht, damit man nicht von dem Gesamtskript erschlagen wird und dann versucht, die Lösung mit

    [autoit]


    Opt("TrayOnEventMode", 1)

    [/autoit]


    und der Hilfefunktion umzusetzen:

    [autoit]


    ##NoTrayIcon

    [/autoit][autoit][/autoit][autoit]

    Opt("TrayOnEventMode", 1)
    Opt("TrayMenuMode", 11) ; Standard Traymenüeinträge (Skript pausieren/beenden) werden nicht angezeigt.

    [/autoit][autoit][/autoit][autoit]

    ;TraySetClick(16) ; Nur wenn die zweite Maustaste gedrückt wird, wird das Traymenü anzeigt.

    [/autoit][autoit][/autoit][autoit]

    TrayCreateItem("Info1")
    TrayItemSetOnEvent(-1, "ShowInfo1")

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    TrayCreateItem("Info2")
    TrayItemSetOnEvent(-1, "ShowInfo2")

    [/autoit][autoit][/autoit][autoit]

    TrayCreateItem("")

    [/autoit][autoit][/autoit][autoit]

    TrayCreateItem("Beenden")
    TrayItemSetOnEvent(-1, "ExitScript")

    [/autoit][autoit][/autoit][autoit]

    TraySetState()

    [/autoit][autoit][/autoit][autoit]

    While 1
    Sleep(10) ; CPU-Last verhindern
    WEnd

    [/autoit][autoit][/autoit][autoit]

    Exit

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    ; Funktionen
    Func ShowInfo1()
    MsgBox(0, "Info1", "Tray OnEvent Demo")
    EndFunc ;==>ShowInfo

    [/autoit][autoit][/autoit][autoit]

    Func ShowInfo2()
    MsgBox(2, "Info2", "Tray OnEvent Demo")
    EndFunc ;==>ShowInfo

    [/autoit][autoit][/autoit][autoit]

    Func ExitScript()
    Exit
    EndFunc ;==>ExitScript

    [/autoit][autoit][/autoit][autoit][/autoit]

    Leider ist es immer noch nicht so, dass ich die Funktionen unabhängig voneinander aufrufen kann. Wenn ich Info1 aufrufe, erhalte ich das Messagefenster Info1. Wenn ich danach Info2 aufrufe (ohne das erste Fenster mit OK zu bestätigen) passiert (noch) nichts. Erst dann, wenn ich das Fenster Info1 mit "Ok" schließe, taucht das Fenster Info2 auf.

    Das Fenster Info2 soll aber angezeigt werden, auch wenn das Fenster Info1 noch nicht vom Anwender geschlossen wurde.

    Daraus schließe ich messerscharf, dass ich deine (name22) Problemlösung nicht richtig verstanden/umgesetzt habe.  :S

    Helft ihr mir bitte weiter?

    Freundliche Grüße

    merlinuwe

  • Bei mir funktioniert das Beispielsscript einwandfrei.

    Sind TV-Quizfragen zu einfach? A) Ja B) Harry Potter

    Spoiler anzeigen

    Ich gebe zu dieser Post hat wahrscheinlich nicht viel geholfen,
    aber ich versuche wenigstens zu helfen :rolleyes:

    • Offizieller Beitrag

    Messageboxen blockieren immer das Script. Solange eine MsgBox offen ist, wird das Script nicht weiter ausgeführt.

  • Hi PuReIroNie,

    du bist ja schneller mit deiner Antwort dabei, als ich meinen eigenen Beitrag fertig bearbeitet habe ... ;)

    Heißt das, bei dir laufen die Funktionen völlig unabhängig voneinander?

    Ich habe mit AutoIt 3.3.10.2 gearbeitet, womit hast du es denn laufen lassen?

    Liebe Grüße

    merlinuwe

  • Das Problem ist wie schon erwähnt wurde, dass sowohl msgbox() als auch sleep() (Script oben...) blockierende Funktionen sind. Außerdem hast du das Problem, dass Autoit kein Multithreading unterstützt, d.h. einzelne Funktionen oder Befehle können nicht paralell, sondern nur nacheinander ausgeführt werden. Echte paralelle Ausführung ist in Autoit nur durch separate Prozesse machbar.

    Du könntest dein Script also z.B. teilen:


    gui.exe (nur für die Anzeige und zum Start der Unterprogramme da)
    worker.exe (führt deine zeitintensive Aktion durch und kommuniziert das Ergebnis an die GUI, falls notwendig)

    Die GUI arbeitet so unabhängig vom Rest und bleibt reaktionsfähig. Es ist außerdem möglich mehrere worker zu starten, welche dann alle paralell arbeiten.


    Eine andere Lösung wäre, dass zeitintensive Funktionen nebenher und regelmässig guigetmsg oder traygetmsg überprüfen (z.B. als Teil der Rechenschleife), allerdings werden die hinterlegten anderen GUI Funktionen trotzdem nicht paralell sondern bestenfalls verschachtelt abwechselnd ausgeführt. Das funktioniert außerdem nur dann wenn auf blockierende Funktionen wie sleep oder msgbox verzichtet wird. Um eine laufende Funktion abbrechen zu können wäre das jedenfalls eine gangbare Lösung.

  • Das Problem ist die Sleep(5000) Funktion in deiner Funktion. Mit AdlibRegister kannst du diese Funktion in 5s Intervallen aufrufen, ohne dass das restliche Script für diese Zeit unterbrochen wird.

    Spoiler anzeigen
    [autoit]

    #include <Date.au3>
    #include <TrayConstants.au3>
    ;#include <MsgBoxConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    #NoTrayIcon

    [/autoit] [autoit][/autoit] [autoit]

    Opt("TrayOnEventMode", 1)
    Opt("TrayMenuMode", 11) ; Standard Traymenüeinträge (Skript pausieren/beenden) werden nicht angezeigt.

    [/autoit] [autoit][/autoit] [autoit]

    ;TraySetClick(16) ; Nur wenn die zweite Maustaste gedrückt wird, wird das Traymenü anzeigt.

    [/autoit] [autoit][/autoit] [autoit]

    TrayCreateItem("Info1")
    TrayItemSetOnEvent(-1, "ShowInfo1")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    TrayCreateItem("Info2")
    TrayItemSetOnEvent(-1, "ShowInfo2")

    [/autoit] [autoit][/autoit] [autoit]

    TrayCreateItem("ASCII")
    TrayItemSetOnEvent(-1, "_AsciiCode")

    [/autoit] [autoit][/autoit] [autoit]

    TrayCreateItem("")

    [/autoit] [autoit][/autoit] [autoit]

    TrayCreateItem("Beenden")
    TrayItemSetOnEvent(-1, "ExitScript")

    [/autoit] [autoit][/autoit] [autoit]

    TraySetState()

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(1000) ; CPU-Last verhindern
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Funktionen
    Func ShowInfo1()
    TrayTip("ShowInfo1", "Dies ist ShowInfo1",66,1)
    ;MsgBox(0, "Info1", "Tray OnEvent Demo")
    EndFunc ;==>ShowInfo

    [/autoit] [autoit][/autoit] [autoit]

    Func ShowInfo2()
    TrayTip("ShowInfo2", "Dies ist ShowInfo2",66,1)
    ;MsgBox(2, "Info2", "Tray OnEvent Demo")
    EndFunc ;==>ShowInfo

    [/autoit] [autoit][/autoit] [autoit]

    Func _AsciiCode()
    AdlibRegister("_GenerateCode_Increment", 5000)
    _GenerateCode_Increment()
    EndFunc ;==>_AsciiCode

    [/autoit] [autoit][/autoit] [autoit]

    Func _GenerateCode_Increment()
    Local Static $iInt = 32

    [/autoit] [autoit][/autoit] [autoit]

    $iOct = StringFormat("%o", $iInt); <== Conversion
    TrayTip("Kodierungen", _
    "Dez(imal): " & $iInt & @CRLF & _
    "Hex(adezimal): " & Hex($iInt) & @CRLF & _
    "Oktal: " & $iOct & @CRLF & _
    "HTML: " & "&#" & $iInt & ";" & @CRLF & _
    "Chr (ASCII): " & Chr($iInt) & @CRLF, 1)

    [/autoit] [autoit][/autoit] [autoit]

    $iInt += 1

    [/autoit] [autoit][/autoit] [autoit]

    If $iInt = 36 Then
    $iInt = 32
    ConsoleWrite(_NowTime() & " OK_03: ASCII-Codes wurden erzeugt." & @CRLF)
    AdlibUnRegister("_GenerateCode_Increment")
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func ExitScript()
    Exit
    EndFunc ;==>ExitScript

    [/autoit]
  • name22: DANKE, es läuft!

    Habe das Programm ein wenig umgebaut, um es besser zu verstehen. Der Trick liegt anscheinend darin, dass Local Static $iInt = 32 bei jedem erneuten Aufruf der Funktion _AsciiCodeB() um 1 erhöht vorgefunden wird. Man, hat das gebraucht, bis ich es erkannt, nachgeschlagen und kapiert habe ...

    Ich fasse mal zusammen, wie (ich glaube, dass) der Ablauf ist:

    1. Der Anwender wählt im Tray-Menü den Eintrag ASCII aus.
    2. Weil das Script im TrayOnEventMode läuft, hat es schon die ganz Zeit darauf gelauert das ein Menüpunkt ausgewählt wird und ruft _AsciiCodeA() auf.
    3. _AsciiCodeA() sorgt dafür, dass alle 5 Sekunden _GenerateCodeIncrement() aufgerufen wird.
    4. _GenerateCodeIncrement() ruft wiederum _AsciiCodeB() auf, welches die eigentlich gewollte Berechnung (hier: Kodierungen) nur für den Wert 32 durchführt und die Variable für den nächsten Aufruf der Funktion auf 33 erhöht.
    5. AdlibUnRegister("_GenerateCodeIncrement") wird aufgerufen, damit die Berechnung nicht erneut von 32 aus beginnt. (Wie funktioniert das?)
    6. Nun könnte der Anwender im Tray-Menü z. B. den Eintrag Info3 auswählen. Der TryTip wird angezeigt und danach fährt die Berechnung der Kodierungen an der Stelle fort, an der sie ausgesetzt wurde. (Warum?)

    Kannst du mir die Schritte 5 und 6 nochmal genau erklären (sofern ich die Schritte 1- 4 richtig verstanden habe :wacko: )?

    misterspeed:

    Habe den ersten Vorschlag umgesetzt, er funktioniert!
    Aber wenn ich Informationen aus den ausgelagerten .exe-Dateien zurück in das aufrufende Skript zurückbekommen möchte, um sie dort auszuwerten wirft das Folgeprobleme auf, denen ich mich (ggf.: noch) nicht gewachsen fühle.

    Dein zweiter Ansatz ist nachvollziehbar, von mir als Einsteiger jedoch (ggf.: noch) nicht umsetzbar.
    DANKE auch dir!

    Uuups... Dinner 4-1 verpasst... :party:

    Schönen Abend noch und einen guten Rutsch

    Freundliche Grüße

    merlinuwe

  • AdlibUnregister registriert eine Funktion, um sie in bestimmten Intervallen immer wieder aufzurufen. Mit AdlibUnregister wird diese Registrierung aufgehoben, so dass ab diesem Zeitpunkt kein automatischer Aufruf mehr stattfindet.
    Die Variable wird in der Funktion als Static deklariert, damit sie nach Beenden der Funktion weiter ihren Wert behält. Standardmäßig werden lokale Variablen zurückgesetzt wenn die Funktion beendet wird.
    Damit dieser Vorgang mehrere male funktioniert wird die Variable nach Erreichen des Maximalwertes auf den Ursprungswert zurückgesetzt und das automatische Aufrufen der Funktion gestoppt, bis das nächste Mal auf ASCII Code gedrückt wird.

    Wenn eine Funktion nach Ablauf des Intervalls durch die AdlibRegister Routine aufgerufen wird, dann wird das Script - egal an welchem Punkt es sich gerade befindet - pausiert um die Funktion auszuführen und danach wieder an der selben Stelle fortgesetzt. Somit scheint es als würden mehrere Prozesse parallel ablaufen.

    Und auch dir einen guten Rutsch ;).