ListViewItemClick-UDF (Klicks auf ListViews)

  • Hi,

    eines der Grundprinzipien von schönem Programmieren ist, Code-Wiederholungen zu vermeiden, auch wenn es um mehrere Projekte geht.
    Ich habe öfters den Fall, dass ich auch Doppelklicks auf ListViews auswerten muss. Und jedes mal musste ich den selben Code per GUIRegisterMsg (WM_NOTIFY) nehmen. Unschön.

    Das Problem, wieso sich sowas schlecht in allgemeine Funktionen auslagern lässt, ist, dass AutoIt nur einen Message-Handler pro Message zulässt. Wenn ich also bei einer UDF auf Basis von GUIRegisterMsg WM_NOTIFY noch für etwas anderes brauche, ist die UDF hinfällig. Ich habe jetzt eine allgemeine Funktion auf Basis der Windows-Internen Funktion SetWindowLong bzw. SetWindowLongPtr geschrieben.
    Dabei wird die WndProc (die Funktion, welche das Message-Handling übernimmt (geschieht in AutoIt intern)) des Parent-Fensters durch eine andere, selbstgeschriebene Funktion ausgetauscht, welche dann die Überwachung von WM_NOTIFY vornimmt. Gegebenenfalls wird dann eine festgelegte Callback-Funktion zur Verarbeitung aufgerufen. Danach wird dann die originale WndProc ausgeführt.

    WICHTIG: Um die Message-Verwaltung nicht unnötig schlecht zu beeinflussen, sollte in der Callback-Funktion von verzögernden Aktionen (Sleeps, User-Interaktionen...) abgesehen werden!!!


    Am besten erkennt man das an dem schönen Beispiel. Auch sieht man dort ein kleines Gimmik:
    Die Parameter der Callback-Funktion können je nach Bedarf variiert werden - ganz, wie der Programmierer es braucht. Das Prinzip sollte ja z.B. von mehreren Konstruktoren einer Klasse bekannt sein.
    Dabei ist die Anzahl der Parameter entscheidend:

    Bei x Parametern wird die Funktion mit diesen Werten in dieser Reihenfolge aufgerufen


    2 Parameter -> Func(Item-Nummer, Klick-Art)
    3 Parameter -> Func(Item-Nummer, SubItem-Nummer, Klick-Art)
    4 Parameter -> Func(Item-Nummer, SubItem-Nummer, Klick-Art, ListView-Handle)

    Die Klick-Art sagt einfach aus, was für ein Klick erfolgt ist: Linksklick, Rechtsklick, Doppellinksklick, Doppelrechtsklick.
    Zur Überprüfung stehen 4 Konstanten zur Verfügung:

    [autoit]

    $LVIC_CLICK
    $LVIC_RCLICK
    $LVIC_DOUBLE
    $LVIC_RDOUBLE

    [/autoit]

    Alles, was jetzt noch unverständlich klingt, erklärt das Beispiel, hoffe ich:

    Spoiler anzeigen
    [autoit]

    #include "ListViewItemClick.au3"
    #include <GuiListView.au3>

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

    $sDisplayClicked_Format = "Item mit der Nummer %i wurde geklickt: %s"

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

    ;init
    $hWnd = GUICreate("ListViewItemClick Beispiel", 600, 400)
    $hListView = _GUICtrlListView_Create($hWnd, "", 0, 0, 400, 400)
    _GUICtrlListView_SetExtendedListViewStyle($hListView, $LVS_EX_FULLROWSELECT)

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

    $cDisplayClicked = GUICtrlCreateLabel("", 410, 10, 180, 40)

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

    ;data
    _GUICtrlListView_AddColumn($hListView, "My Random Number", 383)
    For $i = 1 To 25
    _GUICtrlListView_AddItem($hListView, Random(0, 100, True))
    Next

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

    GUISetState()

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

    ;Funktion registrieren
    _LVIC_RegisterClickFunc($hListView, ClickFunc)

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

    While True
    Switch GUIGetMsg()
    Case -3
    Exit
    EndSwitch
    WEnd

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

    ;Beliebigen Funktionsheader verwenden!

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

    ;~ Func ClickFunc($iItem, $iAction) ; <-- Wäre hier ausreichend
    ;~ Func ClickFunc($iItem, $iSub, $iAction)
    Func ClickFunc($iItem, $iSub, $iAction, $hListView)

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

    Local $sAction
    Switch $iAction
    Case $LVIC_CLICK
    $sAction = "Linksklick"
    Case $LVIC_RCLICK
    $sAction = "Rechtsklick"
    Case $LVIC_DOUBLE
    $sAction = "Doppelklick"
    Case $LVIC_RDOUBLE
    $sAction = "Doppelrechtsklick (Wer tut sowas?)"
    EndSwitch

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

    GUICtrlSetData($cDisplayClicked, StringFormat($sDisplayClicked_Format, $iItem, $sAction))
    EndFunc

    [/autoit]

    Die UDF selber besteht im wesentlichen nur aus einer Funktion: _LVIC_RegisterClickFunc
    Diese Funktion benötigt zwei Parameter... Das ListView-Handle und die Callback-Funktion. Ganz einfach. ^^

    Code
    _LVIC_RegisterClickFunc ( hListView, sCallBack )


    Wenn zum Erstellen der interne Befehl (GUICtrlCreateListView) genutzt wird, dann muss vorher das Handle per GUICtrlGetHandle ermittelt werden.

    So, die UDF selber ist im Anhang.
    Lob, Kritik und Wünsche sind natürlich erwünscht. ^^

    Gruß

    • Offizieller Beitrag
    Zitat

    Wenn zum Erstellen der interne Befehl (GUICtrlCreateListView) genutzt wird, dann muss vorher das Handle per GUICtrlGetHandle ermittelt werden.


    Warum hast du die Abfrage, ob Standard- oder UDF-Listview nicht gleich in deine UDF eingebaut?
    Eine UDf soll ja so flexiebel wie möglich sein ;)