Rekursionen vermeiden

  • Hallo zusammen

    Ich habe vor Kurzem angefangen mit AutoIt zu scripten und bin auf ein Problem gestossen. Da ich eigentlich immer alle Lösungen zu meinen Problemen hier gefunden habe, hatte ich mir gedacht, ich melde mich mal an, da ich keine Antwort auf mein jetztiges Problem gefunden habe.

    Obwohl es momentan eher einfach unschön als ein Problem ist, könnte aber einmal eins werden.
    Ich rufe in meinem Script eine Funktion, die ein GUI erzeugt, rekursiv auf, was jedoch zu zuvielen Instanzen führen kann. Nun möchte ich wissen ob es eine Möglichkeit gibt, analog zu UNIX mit dem & am Schluss eines Befehles, dass die Funktion nicht abwartet, bis die aufgerufene Funktion beendet ist, sondern weiterläuft.
    Hier noch der Auszug aus meinem Code:

    Spoiler anzeigen
    [autoit]


    Func main()
    $arSections = IniReadSectionNames($INI) ;Liest alle Sections (Projekte) aus der INI-Datei in ein Array
    IF IsArray($arSections) Then ;Falls es Einträge hat, werden diese hiermit in das richtige
    $list = "" ; Format für die Liste konvertiert (Item1|Item2|...)
    For $i = 1 To $arSections[0]
    $list &= "|"
    $list &= $arSections[$i]
    Next
    StringTrimLeft($list,1)
    $newproject = $arSections[0]
    Else ;Ansonsten wird die Funktion zum erstellen eines Projektes aufgerufen
    Dim $arSections[1]
    $list = createProject($arSections)
    $arSections[0] = $list
    EndIF
    $mainForm = GUICreate("Projektverwalter", 382, 160, 193, 125) ;Erstellt das Fenster
    $mainBearbeiten = GUICtrlCreateButton("Bearbeiten", 184, 24, 75, 25, 0)
    $mainCombo1 = GUICtrlCreateList($arSections[0], 24, 24, 145, 100)
    GUICtrlSetData($mainCombo1, $list)
    $mainStart = GUICtrlCreateButton("Starten", 272, 24, 75, 25, 0)
    $mainClose = GUICtrlCreateButton("Beenden", 272, 104, 75, 25, 0)
    $mainMenuProject = GUICtrlCreateMenu("&Projekt")
    $mainMenuProjectNew = GUICtrlCreateMenuItem("Neues Projekt anlegen", $mainMenuProject)
    $mainMenuProjectExit = GUICtrlCreateMenuItem("Beenden", $mainMenuProject)
    $mainMenuAbout = GUICtrlCreateMenu("Über")
    GUICtrlCreateMenuItem("Dieses Tool", $mainMenuAbout)
    GUICtrlCreateMenuItem("Den Entwickler", $mainMenuAbout)
    GUICtrlCreateMenuItem("Hilfe", $mainMenuAbout)

    GUISetState(@SW_SHOW)
    #EndRegion ### END Koda GUI section ###

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

    While 1 ;Wartet auf Input=GUIGetMsg
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE ;Schliessen des Fensters per Symbol
    Exit
    Case $mainClose ;Button Beenden
    Exit
    Case $mainMenuProjectExit
    Exit
    Case $mainMenuProjectNew ;Menueintrag Projekt anlegen
    GUIDelete($mainForm) ;Fenster wird geschlossen
    $list = createProject($arSections)
    main() ;????Ruft eine weitere Instanz von sich auf???? ;Startet wieder das Hauptfenster
    Case $mainBearbeiten ;Button Bearbeiten speichert den Namen des ausgewählten Projekts,
    $project=GuiCtrlRead($mainCombo1) ; schliesst das Fenster und öffnet das Tasks-Fenser
    GuiDelete($mainForm)
    tasks($project)
    Case $mainStart ;Button Starten speichert den Projektnamen, schliesst das Fenster
    $project=GuiCtrlRead($mainCombo1) ; und startet das Start-Fenster
    GuiDelete($mainForm)
    start($project)
    EndSwitch
    WEnd
    EndFunc

    [/autoit]

    Ich verbleibe mit der Hoffnung, dass ich mich verständlich genug ausgedrückt habe und dass es dafür eine Lösung gibt.
    fg
    che

    Einmal editiert, zuletzt von c.unhund (8. Juni 2012 um 09:22)

  • So wie ich das verstanden habe geht es darum, dass er ein GUI in einer rekursiven Funktion erstellt. Momentan wird eine GUIGetMsg()-Abfrage verwendet, was dazu führt, dass das GUI aus der 'ersten' Instanz der Funktion nicht mehr reagiert... ;)
    So c.unhund damit dieses Problem nicht mehr auftritt solltest du dich mal mit dem sogenannten GUIOnEventMode beschäftigen, zu welchem es hier im Forum auch schon einige Erklärungen/Tutorials gibt... Damit du diesen, wenn du ihn verstanden hast, auch in deiner rekursiven Funktion verwenden kannst, musst du in den durch die Events aufgerufenen Funktionen eine Abfrage für das GUI-Handle einbauen, damit du auch weist auf welcher GUI-Instanz der Button X gedrückt wurde.
    :)

    LG
    Christoph :)

  • Erstmal vielen Dank für die schnellen Antworten.

    @m-obi
    Ich möchte, dass, wenn eine Funktion aufgerufen wird, die aufrufende Funktion nicht wartet, bis die aufgerufene Funktion abgearbeitet wird, sondern gleichzeitig weiter abgearbeitet wird.

    BinDannMalWeg
    Es stört mich nicht, dass die Funktion nicht mehr reagiert, ich brauche sie danach nicht mehr. Nur ist jede dieser Funktionen so lange aktiv, bis das Programm beendet wird und das könnte sich auf die Leistung auswirken.

    AspirinJunkie
    Es reicht nicht, das Fenster nur zu verstecken, da das Fenster eine Liste enthält, die bei jedem Start aktualisiert werden muss. Eine Möglichkeit, dass dies trotzdem gehen würde, wäre spontan ein asynchroner Aufruf (AJAX-like), hier weiss ich aber nicht ob und wie ich den umsetzten kann.

    fg
    che

  • Es reicht nicht, das Fenster nur zu verstecken, da das Fenster eine Liste enthält, die bei jedem Start aktualisiert werden muss. Eine Möglichkeit, dass dies trotzdem gehen würde, wäre spontan ein asynchroner Aufruf (AJAX-like), hier weiss ich aber nicht ob und wie ich den umsetzten kann.


    Dann erstelle deine GUI einmal am Anfang und aktualisiere die Controls mit GuiCtrlSetData. Hier ein kleines Demo zur Sortierfunktion in einer Listiew:

    Spoiler anzeigen
    [autoit]

    #include <GuiListView.au3>
    #include <GUIConstantsEx.au3>
    #include <ListviewConstants.au3>
    #include <array.au3>

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

    Dim $aNames[20][2]
    $aNames[0][0] = "Jürgen"
    $aNames[1][0] = "Peter"
    $aNames[2][0] = "Bert"
    $aNames[3][0] = "Christina"
    $aNames[4][0] = "Alex"
    $aNames[5][0] = "Astrid"
    $aNames[6][0] = "Roberto"
    $aNames[7][0] = "Heinz"
    $aNames[8][0] = "Iwan"
    $aNames[9][0] = "Robertina"
    $aNames[10][0] = "Hans"
    $aNames[11][0] = "Peter II."
    $aNames[12][0] = "Tina"
    $aNames[13][0] = "Michael"
    $aNames[14][0] = "Gunnar"
    $aNames[15][0] = "Kurt"
    $aNames[16][0] = "Gerald"
    $aNames[17][0] = "Alfred"
    $aNames[18][0] = "Stefanie"
    $aNames[19][0] = "Nicole"
    Dim $aItems[20]

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

    GUICreate("", 200, 400)
    $listview = GUICtrlCreateListView("Name|Status", 10, 10, 180, 350)
    For $i = 0 To 19
    $aItems[$i] = GUICtrlCreateListViewItem($aNames[$i][0] & "|Offline", $listview)
    Next
    _GUICtrlListView_SetColumnWidth($listview, 0, 140)
    _GUICtrlListView_SetColumnWidth($listview, 1, 40) ;0 = unsichtbar
    _GUICtrlListView_RegisterSortCallBack($listview)

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

    _RandomOnOff()

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

    GUISetState(@SW_SHOW)

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

    ;GUICtrlSetColor(-1, 0x22C21F)
    ;GUICtrlSetColor(-1, 0xAA0000)

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

    While 1
    $msg = GUIGetMsg()
    Switch $msg
    Case $GUI_EVENT_CLOSE
    _GUICtrlListView_UnRegisterSortCallBack($listview)
    Exit
    Case $listview
    _GUICtrlListView_SortItems($ListView, GUICtrlGetState($ListView))
    EndSwitch
    WEnd

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

    Func _RandomOnOff()
    _GUICtrlListView_BeginUpdate($listview)
    For $i = 0 To 19
    If Random(1, 3, 1) = 1 Then
    $aNames[$i][1] = "Off"
    Else
    $aNames[$i][1] = "On"
    EndIf
    Next
    For $i = 0 To 19
    $iItem = _GUICtrlListView_FindText($listview, $aNames[$i][0], -1, False, True)
    If $aNames[$i][1] = "Off" Then
    GUICtrlSetData($aItems[$iItem], "|Off")
    GUICtrlSetBkColor($aItems[$iItem], 0xAA0000)
    Else
    GUICtrlSetData($aItems[$iItem], "|On")
    GUICtrlSetBkColor($aItems[$iItem], 0x22C21F)
    EndIf
    Next
    If GUICtrlGetState($ListView) = 1 Then
    _GUICtrlListView_SortItems($listview, 0)
    _GUICtrlListView_SortItems($listview, 1)
    EndIf
    _GUICtrlListView_EndUpdate($listview)
    AdlibRegister("_RandomOnOff", Random(5000, 10000, 1))
    EndFunc ;==>_RandomOnOff

    [/autoit]

    mfg autoBert

  • Hi,
    Wenn du die main-Funktion rekursiv aufrufen musst, dann hast du ein Logik-Problem. Das folgende wäre eine Struktur ohne Rekursion:

    [autoit]

    Global $hGUI, $hButton, ...
    Func main()
    $aSettings = LoadSettings()
    createProject($aSettings)
    createGUI()
    updateGUI()
    While 1
    ; Message Loop
    If ... Then updateGUI()
    WEnd
    EndFunc

    [/autoit]
  • Vielen Dank nochmals für die anregenden Ideen.

    Ich habe aber gemerkt das es nicht nur diese Funktion war mit diesem Problem, sondern, dass ich auch andere Funktionen über mehrer Stufen so aufgerufen habe.
    In Stil von

    [autoit]


    Func main()
    manage()
    EndFunc

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

    Func manage()
    main()
    EndFunc

    [/autoit]

    Ich habe es nun mit Return-Arrays, einer Schleife und meherern Switches gelöst. Für Verbesserungsvorschläge bin ich dennoch immer offen.

    Spoiler anzeigen
    [autoit]


    $gui = "main"
    While 1

    Switch $gui

    Case "main"
    $arNextStep = main()
    Switch $arNextStep[0]
    Case "createProject"
    createProject($arNextStep[1])
    Case "manage"
    $gui = "manage"
    Case "startList"
    startList($arNextStep[1])
    $gui = "startList"
    EndSwitch

    Case "manage"
    $arNextStep = manage($arNextStep[1])
    Switch $arNextStep[0]
    Case "main"
    $gui = "main"
    Case "createTask"
    createTask($arNextStep[1])
    Case 0
    $gui = "manage"
    EndSwitch

    Case "startList"
    ...

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

    EndSwitch

    WEnd

    [/autoit]


    fg
    che