OnEvent Modus: Mehrere GUI Inputboxen gleichzeitig auf Veränderung prüfen

  • Hallo zusammen,

    ich schreibe zur Zeit eine Bücherverwaltungsoftware und habe dafür eine GUI erstellt.
    Darin enthalten ist ein Tab mit 3 Tabitems: Bücherliste, Suchen, Buch Details.

    Wenn man auf den Button "Buch bearbeiten" auf dem Tabitem "Bücherliste" klickt, werden die Details des ausgewählten Buchs aus einer SQLite DB in ein Array kopiert und dessen Inhalt auf die einzelnen Inputboxen des Tabitems "Buch Details" verteilt:

    [autoit]


    Func _btnListeBearbeitenClicked()
    Local $hQuery, $aBuch, $atest[1]
    _SQLite_Startup()
    If FileExists(@WorkingDir & "\Buchling.db") = 1 Then
    $hDB = _SQLite_Open(@WorkingDir & "\Buchling.db")
    $aString = _StringBetween(GUICtrlRead(GUICtrlRead($ListeBuchListe),2),"","|")
    If IsArray($aString) Then
    _SQLite_QuerySingleRow(-1,"SELECT * FROM Buchling WHERE Titel = '"&$aString[0]&"' LIMIT 1;",$aBuch)
    GUICtrlSetData($inpErfassenISBN,$aBuch[0])
    GUICtrlSetData($inpErfassenTitel,$aBuch[1])
    GUICtrlSetData($inpErfassenGenre,$aBuch[2])
    GUICtrlSetData($inpErfassenAutor,$aBuch[3])
    GUICtrlSetData($inpErfassenVerlag,$aBuch[4])
    GUICtrlSetData($inpErfassenErscheinungsjahr,$aBuch[5])
    GUICtrlSetData($inpErfassenAusgabe,$aBuch[6])
    GUICtrlSetData($inpErfassenTyp,$aBuch[7])
    GUICtrlSetData($inpErfassenAnzahlSeiten,$aBuch[8])
    GUICtrlSetData($txtErfassenKurzbeschreibung,$aBuch[9])
    GUICtrlSetData($txtErfassenLangbeschreibung,$aBuch[10])
    GUICtrlSetData($picErfassen,$aBuch[11])
    If $aBuch[12] = 0 Then
    GUICtrlSetState($chkErfassenVerliehen, $GUI_UNCHECKED)
    GUICtrlSetState($lblErfassenVerliehen_am, $GUI_DISABLE)
    GUICtrlSetState($lblErfassenVerliehen_an, $GUI_DISABLE)
    GUICtrlSetState($dateErfassenVerliehen_am, $GUI_DISABLE)
    GUICtrlSetState($cmbErfassenVerliehen_an, $GUI_DISABLE)
    Else
    GUICtrlSetState($chkErfassenVerliehen, $GUI_CHECKED)
    GUICtrlSetState($lblErfassenVerliehen_am, $GUI_ENABLE)
    GUICtrlSetState($lblErfassenVerliehen_an, $GUI_ENABLE)
    GUICtrlSetState($dateErfassenVerliehen_am, $GUI_ENABLE)
    GUICtrlSetState($cmbErfassenVerliehen_an, $GUI_ENABLE)
    EndIf
    GUICtrlSetData($dateErfassenVerliehen_am,$aBuch[13])
    GUICtrlSetData($cmbErfassenVerliehen_an,$aBuch[14])
    GUICtrlSetData($inpErfassenLagerort,$aBuch[15])
    GUICtrlSetState($tabErfassen, $GUI_SHOW)
    EndIf
    _SQLite_Close(-1)
    EndIf
    EndFunc

    [/autoit]

    Wie ihr seht, wechselt die Funktion dann auch zum Tabitem "Buch Details".
    Jetzt zu meiner eigentlichen Frage:

    Wie schaffe ich es, festzustellen, ob die Inputboxen verändert wurden?
    Ich möchte bei Änderungen den aktuell deaktivierten Button "Speichern" aktivieren.

    Ich habe mehrere Ansätze versucht:

    AdlibRegister <- Problem: ich kann Adlib keine Parameter (wie das vorher erstellte Array $aBuch mitgeben
    Beispiel:

    [autoit]


    ..
    AdlibRegister("_ISBNChange")
    ...
    Func _ISBNChange()
    If GUICtrlRead($inpErfassenISBN,1) <>"" Then
    GUICtrlSetState($btnErfassenSave, $GUI_ENABLE)
    Else
    GUICtrlSetState($btnErfassenSave, $GUI_DISABLE)
    EndIf
    EndFunc

    [/autoit]

    Das funktioniert, aber eben nur "Feld leer" oder "Feld nicht leer"

    Do ... Until - Schleife:

    [autoit]


    Func _inpErfassenChanged($aBuch)
    Dim $aBuchChange[UBound($aBuch)]
    Do
    $aBuchChange[0] = $inpErfassenISBN
    $aBuchChange[1] = $inpErfassenTitel
    $aBuchChange[2] = $inpErfassenGenre
    $aBuchChange[3] = $inpErfassenAutor
    $aBuchChange[4] = $inpErfassenVerlag
    $aBuchChange[5] = $inpErfassenErscheinungsjahr
    $aBuchChange[6] = $inpErfassenAusgabe
    $aBuchChange[7] = $inpErfassenTyp
    $aBuchChange[8] = $inpErfassenAnzahlSeiten
    $aBuchChange[9] = $txtErfassenKurzbeschreibung
    $aBuchChange[10] = $txtErfassenLangbeschreibung
    $aBuchChange[11] = $picErfassen
    $aBuchChange[12] = $chkErfassenVerliehen
    $aBuchChange[13] = $dateErfassenVerliehen_am
    $aBuchChange[14] = $cmbErfassenVerliehen_an
    $aBuchChange[15] = $inpErfassenLagerort
    For $i=0 to UBound($aBuch)-1
    If GUICtrlRead($aBuchChange) <> $aBuch[$i] Then
    GUICtrlSetState($btnErfassenSave, $GUI_ENABLE)
    Else
    GUICtrlSetState($btnErfassenSave, $GUI_DISABLE)
    EndIf
    Sleep(250)
    Next
    Until 0
    EndFunc

    [/autoit]

    Mein Problem ist hier das "Until".
    Ich möchte, das die Schleife beendet wird, wenn der User entweder:
    - den Tab wechselt
    - einen neuen Datensatz beginnt
    - die aktuellen Änderungen speichert

    Ich muss also meiner Meinung nach herausfinden, ob ein Button oder ein anderer Reiter angeklickt wurde.
    Ich steh echt auf dem Schlauch ... ;(
    Vielleicht denke ich da mal wieder zu kompliziert um 23 Ecken oder hab ganz profan nen Denkfehler...?
    Kann mir da wer helfen oder einen Schubser in die richtige Richtung geben?

    Einmal editiert, zuletzt von Rhodan (15. September 2011 um 13:46)

  • Hi,

    folgendes in dein Skript einbauen und damit experimentieren ...

    Spoiler anzeigen
    [autoit]


    ; $IDC_EDIT = GuiCtrlCreateInput (...)

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

    GuiRegisterMsg ($WM_COMMAND, "OnCommand")

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

    ; ...

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

    Func OnCommand ($hwnd, $message, $wParam, $lParam)

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

    ; $lParam enthält Handle des Eingabefeldes,
    ; LOWORD($wParam) enthält ID des Eingabefeldes
    If ($lParam and LOWORD($wParam) == $IDC_EDIT) Then

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

    Switch (HIWORD($wParam))

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

    Case $EN_CHANGE
    ConsoleWrite (StringFormat (">> Nachricht EN_CHANGE\nHandle des Eingabefeldes: 0x%X\nHandle des Eingabefeldes: %d\n\n", $lParam, $wParam))
    Case $EN_UPDATE
    ConsoleWrite (StringFormat ("> Nachricht EN_UPDATE\nHandle des Eingabefeldes: 0x%X\nHandle des Eingabefeldes: %d\n\n", $lParam, $wParam))

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

    Case $EN_ERRSPACE
    ContinueCase
    Case $EN_MAXTEXT
    MsgBox (BitOR ($MB_OK, $MB_ICONHAND), _
    "", "Kapazitätsgrenze erreicht.")
    EndSwitch
    EndIf

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

    EndFunc

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

    Func LOWORD($DWORD)
    Return BitAND($DWORD, 0xFFFF)
    EndFunc

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

    Func HIWORD($DWORD)
    Return BitShift($DWORD, 16)
    EndFunc

    [/autoit]

    EDIT:
    Deine Funktion zum Prüfen der Eingabefelder natürlich deaktivieren ...


    Gruß
    Greenhorn


    Einmal editiert, zuletzt von Greenhorn (14. September 2011 um 23:16)

  • thx :)
    Aber bevor ich mich an´s experimentieren mache:
    Funktioniert das auch im OnEvent-Modus?
    (Sorry, hatte vergessen das zu erwähnen)

  • So, hatte jetzt die Zeit gefunden mir dein Script anzuschauen und habe folgendes festgestellt:

    Ich versteh nur Bahnhof... :(

    Wann und wo rufe ich die Funktion denn auf?
    Woher weiß ich, wie und mit was ich die Parameter von OnCommand fülle?
    ---> $hwnd, $message, $wParam, $lParam

    Und vor allem:
    Was macht dein Skript da eigentlich? :D
    Kannst du mir das mal zerpflücken und erläutern?
    Danke für die Mühe :)

  • warum so kompliziert?
    Greenhorn's Ansatz ist eher ein professioneller ... :D

    Eine Schleife innnerhalb einer Funktion ist recht ungünstig.

    Für Dein Problem hattest Du doch schon den richtigen Ansatz.
    Verwende AdlibRegister ('PrüfeInputBoxen', 250)

    Wenn Du jetzt noch Deine Inputboxen als Array deklarierst, kannst Du recht einfach mit einer For Schleife
    die Werte der DB (die Du ja ausgelesen hast und auch in einem Array gleicher Größe vorhalten solltest)
    mit denen der Inputboxen.
    Wenn <> dann GuiCtrlSetState ...

    ein deaktivieren brauchst Du eigentlich nicht, da es den Zustand nur beim Start gibt.
    Das deaktivieren würde ich mit dem Einlesen eines neuen Datensatzes koppeln.

    Bei Fragen ...

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    ein paar Infos ...

    Wer mehr als "nur" Hilfe benötigt, kann sich gern im Forum "Programmieranfragen" an uns wenden. Wir helfen in allen Fällen, die die Forenregeln zulassen.

    Für schnelle Hilfe benötigen wir ein ! lauffähiges ! Script, dass wir als Demonstration des Problems testen können. Wer von uns erwartet ein Teilscript erstmal lauffähig zu bekommen, der hat
    1. keine wirkliche Not
    2. keinen Respekt vor Menschen die ihm in ihrer Freizeit Ihre Hilfe anbieten
    3. oder ist einfach nur faul und meint wir coden das für ihn

    In solchen Fällen erlaube ich mir, die Anfrage einfach zu ignorieren. ;)

  • Es fehlt auch noch "Return $GUI_RUNDEFMSG" als Rückgabewert der Funktiion "OnCommand".

    Du must nur die Funktion GuiRegisterMsg in deinem Skript ausführen.

    Deine Input-Box ist ein Fenster genauso wie das Hauptfenster. Es sieht eben nur anders aus und hat eine bestimmte Aufgabe.
    Tippst Du nun in dem Edit-Fenster herum, dann sendet das Edit-Fenster eine WM_COMMAND Nachricht an das Hauptfenster, bzw. das Elternfenster.
    Diese Nachricht kannst Du nun auswerten und darauf reagieren.

    In AutoIt kannst Du dir diese Nachrichten übergeben lassen, indem Du eben GuiRegisterMsg - möglichst kurz nach Erzeugen des Hauptfensters - in deinem Skript ausführst. Von da an bekommst Du die Nachricht an eine von Dir definierte Funktion geliefert.
    Der erste Parameter($hwnd), ist das Handle des Elternfensters.
    Der zweite Parameter ($message), ein vorzeichenloser Integer, enthält die Nachricht. (WM_XXXXX)
    Der dritte Parameter ($wParam), ist ein UINT_PTR und kann Daten enthalten, die mit der Nachricht gesendet werden sollen.
    Der vierte Parameter ($lParam), ein LONG_PTR -> s. dritten Parameter.

    Was wParam und lParam nun enthalten kannst Du den Dokumentationen entnehmen.
    In diesem Falle die MSDN: Edit Control Notifications

    Vielleicht verstehst Du es besser wenn Du auch das hier liest: About Edit Controls
    Und Using Messages and Message Queues


    Gruß
    Greenhorn


  • Hi Schnuffel :)

    Daran hatte ich auch gedacht, bin aber daran gescheitert, das Array, was ja nur Local in der vorherigen Funktion existiert, der Adlib mitzugeben

  • mal ein kleines Beispiel quick & dirty... :D

    Spoiler anzeigen
    [autoit]

    #include <GUIConstants.au3>

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

    #region - GUI Create
    GUICreate('')
    Dim $vorgabe[5]
    $vorgabe[0] = 4
    $vorgabe[1] = 'test1'
    $vorgabe[2] = 'test2'
    $vorgabe[3] = 'test3'
    $vorgabe[4] = 'test4'

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

    Dim $input[5]
    $input[0] = 4
    $input[1] = GUICtrlCreateInput("",10, 10,200, 20)
    $input[2] = GUICtrlCreateInput("",10, 40,200, 20)
    $input[3] = GUICtrlCreateInput("",10, 70,200, 20)
    $input[4] = GUICtrlCreateInput("",10,100,200, 20)
    $speichern = GUICtrlCreateButton("Speichern", 10,200,80,40)
    GUICtrlSetState(-1, $GUI_DISABLE)
    For $i = 1 To 4
    GUICtrlSetData($input[$i], $vorgabe[$i])
    Next

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

    GUISetState()
    #endregion

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

    AdlibRegister("test", 250)

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

    #region - GUI SelectLoop
    While 1
    $msg = GUIGetMsg()
    Select
    Case $msg = $GUI_EVENT_CLOSE
    Exit

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

    EndSelect
    WEnd
    #endregion

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

    Func test()
    AdlibUnRegister("test")
    For $i = 1 To $input[0]
    If GUICtrlRead($input[$i]) <> $vorgabe[$i] Then GUICtrlSetState($speichern, $GUI_ENABLE)
    Next
    AdlibRegister("test", 250)
    EndFunc

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

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    ein paar Infos ...

    Wer mehr als "nur" Hilfe benötigt, kann sich gern im Forum "Programmieranfragen" an uns wenden. Wir helfen in allen Fällen, die die Forenregeln zulassen.

    Für schnelle Hilfe benötigen wir ein ! lauffähiges ! Script, dass wir als Demonstration des Problems testen können. Wer von uns erwartet ein Teilscript erstmal lauffähig zu bekommen, der hat
    1. keine wirkliche Not
    2. keinen Respekt vor Menschen die ihm in ihrer Freizeit Ihre Hilfe anbieten
    3. oder ist einfach nur faul und meint wir coden das für ihn

    In solchen Fällen erlaube ich mir, die Anfrage einfach zu ignorieren. ;)

  • ich hab Dir Greenhorn's Ansatz mal vereinfacht "nur" auf Veränderung...

    Spoiler anzeigen
    [autoit]

    #include <GUIConstants.au3>

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

    #include<WindowsConstants.au3>
    #include<EditConstants.au3>
    #include<Constants.au3>

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

    #region - GUI Create
    GUICreate('')
    Dim $vorgabe[5]
    $vorgabe[0] = 4
    $vorgabe[1] = 'test1'
    $vorgabe[2] = 'test2'
    $vorgabe[3] = 'test3'
    $vorgabe[4] = 'test4'

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

    Dim $input[5]
    $input[0] = 4
    $input[1] = GUICtrlCreateInput("",10, 10,200, 20)
    $input[2] = GUICtrlCreateInput("",10, 40,200, 20)
    $input[3] = GUICtrlCreateInput("",10, 70,200, 20)
    $input[4] = GUICtrlCreateInput("",10,100,200, 20)
    $speichern = GUICtrlCreateButton("Speichern", 10,200,80,40)
    GUICtrlSetState(-1, $GUI_DISABLE)
    $IDC_EDIT = $input[1]
    For $i = 1 To 4
    GUICtrlSetData($input[$i], $vorgabe[$i])
    Next
    GuiRegisterMsg ($WM_COMMAND, "OnCommand"); erst jetzt erstellt, damit die Erstellung nicht gewertet wird
    GUISetState()
    #endregion

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

    #region - GUI SelectLoop
    While 1
    $msg = GUIGetMsg()
    Select
    Case $msg = $GUI_EVENT_CLOSE
    Exit

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

    EndSelect
    WEnd
    #endregion

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

    Func OnCommand($hwnd, $message, $wParam, $lParam)
    If $input[1] >= ($lParam and LOWORD($wParam)) And ($lParam and LOWORD($wParam)) <= $input[4] Then
    If GUICtrlRead(LOWORD($wParam)) <> $vorgabe[LOWORD($wParam)-2] Then GUICtrlSetState($speichern, $GUI_ENABLE); die '-2' ist der Versatz von Control-ID zum ArrayWert
    If (HIWORD($wParam)) = $EN_CHANGE Then ConsoleWrite(GUICtrlRead(LOWORD($wParam)) & @CRLF); Ausgabe in der Console zum Testen
    EndIf
    Return $GUI_RUNDEFMSG
    EndFunc

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

    Func LOWORD($DWORD)
    Return BitAND($DWORD, 0xFFFF)
    EndFunc

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

    Func HIWORD($DWORD)
    Return BitShift($DWORD, 16)
    EndFunc

    [/autoit]

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    ein paar Infos ...

    Wer mehr als "nur" Hilfe benötigt, kann sich gern im Forum "Programmieranfragen" an uns wenden. Wir helfen in allen Fällen, die die Forenregeln zulassen.

    Für schnelle Hilfe benötigen wir ein ! lauffähiges ! Script, dass wir als Demonstration des Problems testen können. Wer von uns erwartet ein Teilscript erstmal lauffähig zu bekommen, der hat
    1. keine wirkliche Not
    2. keinen Respekt vor Menschen die ihm in ihrer Freizeit Ihre Hilfe anbieten
    3. oder ist einfach nur faul und meint wir coden das für ihn

    In solchen Fällen erlaube ich mir, die Anfrage einfach zu ignorieren. ;)