[gelöst] Zellen eines Listview-Steuerelements anwählbar machen



  • Hallo miteinander.

    Ich habe in ein Programm eine Listview eingebaut. Das Ganze funktioniert auch, allerdings entstand jetzt die Anforderung, dass die einzelnen Zellen anwählbar sein sollen und nicht die ganze Zeile. Ich kann dazu keinerlei Beispiele finden.

    Bisher läuft die Listview mit der Einstellung:

    SendMessage(lbObjects, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, (LPARAM) LVS_EX_FULLROWSELECT);
    

    Gibt es eine Möglichkeit, dass von FULLROW auf Zellenauswahl zu bringen?

    Gruß
    Kai





  • Nein, das WinAPI-Control unterstützt das nicht, nur die erste Spalte kann selektierbar gemacht werden (nicht explizit jede Spalte in der Detail-Ansicht des ListViewControls).

    Im .NET-Framework wird daher dann meist das DataGridView (WinForms) benutzt.



  • Es ist schon möglich jedes Element in einer Listview anwählbar zu machen, jedoch musst du das selbst realisieren.

    als erstes musst du den Doppel Mausklick abfangen, der auf eine Zeile & Spalte getätigt wurde.

    daraufhin das Rechteck der Zeilen spalte holen.

    Dann ein Edit Ctrl erstellen, dass du auf das Rechteck der Zeilen spalte setzt.

    den Text aus der Zeilen spalte holen und in das Edit Ctrl setzen.

    Jetzt kannst du den text dort bearbeiten.

    danach musst du es so realisieren, dass wenn du in eine andere Zeilen spalte oder
    aber ins nirgendwo der ListView klickst, das EditCtrl wieder verschwindet.

    zuvor aber holst du den geänderten Text aus dem EditCtrl und setzt ihn in die Zeilen spalte für das du das EditCtrl erstellt hast.

    Wenn du dich auf CodeProject ein wenig umkuckst, findest du dort ein Haufen Beispiele wo das realisiert wurde.



  • Das hört sich ja schon einmal gut an. Ich muss eigentlich nur wissen, welche Zelle genau (Reihe, Spalte) angeklickt wurde, um dann eine individuelle Aktion zu starten. Der Inhalt ist irrelevant.



  • Dabei hilft dir LVM_SUBITEMHITTEST



  • Ich rufe das so auf:

    SendMessage(lbObjects, LVM_SUBITEMHITTEST, 0, (LPARAM) &lvHitTestInfo);
    

    Allerdings scheint die übergebene Struktur nicht gefüllt zu werden. Ich bekomme zum Beispiel für das Element iGroup nur eine Riesenzahl (scheint gar nicht gesetzt zu werden) und für iSubItem immer nur -1.
    Ich denke mal, dass ich da ein paar Flags über das Element flags setzen muss. Allerdings weiß ich nicht welches ich aus dieser Fülle an möglichen Flagwerten setzen soll.



  • du musst dort keine Flaggen setzen, bevor du den Hittest aufrufst. die werden von der LVM_SUBITEMHITTEST gesetzt. Und sind dafür, dass du darauf reagieren kannst. oder weist wohin in der Listview geklickt wurde.

    du übergibst eine Punkt Struktur an das Mitglied (pt) der LVHITTESTINFO Struktur.
    die Koordinaten dafür erhälst du von jedem Benachrichtigungsfall (WM_*) der die Maus betrifft.

    zb. WM_LBUTTONDBLCLK

    ⚠ aber bedenke, du brauchst die Clientkoordinaten des ListViews und nicht die des Desktops. bzw. des Dialoges in dem die LV verankert ist ⚠

    wenn du deine Listview geSubClassed hast sollte das kein Problem darstellen, dann kannst du die Koordinaten direkt aus der Nachrichtenschleife der ListView übergeben, andernfalls brauchst du ScreenToClient wenn du WM_LBUTTONDBLCLK aus der Nachrichtenschleife der Anwendung bzw. des Dialoges aufrufst in dem die Listview verankert ist.



  • Also, ich habe ScreenToClient mal so angewendet:

    ScreenToClient(lbObjects, &pt);
    x=pt.x;
    y=pt.y;
    

    lbObjects ist mein Listview-Fenster.

    Das liefert mir für x und y aber auch keine richtigen Werte. Über ein WM_LBUTTONDOWN kann ich ja keine Koordinaten holen. Befinde ich mich auf der Listview, dann löst das ja nicht mehr aus, weil die ein anderes Fenster ist als das Parent-Window.



  • warum sollte WM_LBUTTONDOWN nicht durch die ListView ausgelöst werden?
    wenn du deine Listview richtig gesubclassed hast, kommt die Nachricht auch dort an. das tut sie jedenfalls bei mir. 🕶

    ...Über ein WM_LBUTTONDOWN kann ich ja keine Koordinaten holen...

    dann lies bitte mal alles was unter WM_LBUTTONDOWN steht, insbesondere was dir der LPARAM Parameter liefert. Die Makros die du dafür benötigst werden auch gleich mitgeliefert. Umsonst schreib ich das ja nicht 😉

    und ScreenToClient braucht Koordinaten um arbeiten zu können. Wie Initialisierst du die POINT Struktur (pt).

    ScreenToClient macht im Prinzip nichts anderes als die Desktop Koordinaten von den Koordinaten der Listview auf dem Desktop abziehen. Das was übrig bleibt, sind die Koordinaten innerhalb der ListView. Wenn du nichts an ScreenToClient übergibst, kann nur müll dabei rauskommen.



  • Das die Koordinaten bei gewissen Nachrichten im hoch- und niederwertigen Wort von lParam stehen weiß ich ja.
    Allerdings habe ich keine Subklasse von syslistview32 angelegt. Dieses Fenster habe ich lediglich über ein CreateWindow in mein Fenster gesetzt und fange Nachrichten daran über WM_NOTIFY-Meldungen an mein Fenster ab.

    Ausschnitt:

    case WM_NOTIFY:	switch(((LPNMHDR) lParam)->code)
    			{
    			case NM_DBLCLK:	ScreenToClient(lbObjects, &pt);
    				        break;
                                            ...
    

    Kann es sein, dass ich auf diese Weise entweder
    - die evtl. Möglichkeit besitze, die Koordinaten über die NM-Messages an das Listenfenster abzufragen
    - oder, die WndProc des Listenfensters auf eine eigene umbiegen, sodass ich darin auf WM_LBUTTONDOWN reagieren kann.

    Oder die Sache mit der Subklasse. Meinst du das so, dass ich mir eine WNDCLASS erstelle und das Member lpszClassName mit dem Namen der Listview definiere?



  • sorry aber ich muss jetzt echt mal ganz blöd fragen, liest du dir eigentlich durch was da unter NM_DBLCLK steht?

    oder probierst du einfach mal so ins blaue?
    oder verstehst du Englisch nicht? wenn das dein Problem ist jag das ganze doch mal durch nen übersetzter. 🙄

    Pointer to an NMITEMACTIVATE structure that contains additional information about this notification. The iItem, iSubItem, and ptAction members of this structure contain information about the item.

    heist auf deutsch...
    Ein Zeiger auf die NMITEMACTIVATE Struktur enthält Informationen über diese Benachrichtigung. Das iItem, iSubItem, und ptAction Mitglied dieser Struktur enthält Informationen über das item (das angeklickte Element in der Listview)

    was willst du dann noch mit ScreenToCient? Du hast dort alles was du brauchst. 😉
    du must nichtmal nen hittest machen ⚠



  • Das mit der Notify-Message NM_DBLCLK habe ich in einem der Windows-Header gefunden und mal abgefangen, damit ich überhaupt einen Auslöser habe, unter dem ich dann die Koordinaten ermitteln kann.

    Diesen Satz den du zitierst, sehe ich zum ersten Mal (was das Übersetzen etwas schwierig gemacht hätte).

    Das man darunter was mit einer NMITEMACTIVATE-Struktur anfangen kann, habe ich nicht gewußt. Manche Nachrichten kann ich auch garnicht abfangen. Das Programm verzweigt dann gar nicht in den CASE-Zweig unter der Nachricht. Das fängt schon bei so was trivialen an wie der Nachricht WM_LBUTTONDBLCLK an das Hauptfenster.

    Ich danke dir auf jeden Fall für deine bisherige Hilfe. Dann versuche ich morgen mal mein Glück mit der "neuen" Struktur.



  • Das hat funktioniert. Scheiße, wenn man den ganzen Tag in die falsche Richtung schwimmt. Das mit der NMITEMACTIVATE-Struktur hat dann auf Anhieb geklappt.

    Danke dir vielmals.

    Gruß
    Kai



  • Du bist keines falls in die falsch Richtung geschwommen. Es gibt die unterschiedlichsten Ansätze wie man ein Problem lösen kann, und alle führen nach Rom. 🕶

    Du siehst halt nur (noch) nicht die Dinge die vor deiner Nase liegen und weist damit nichts anzufangen, weil dir wahrscheinlich (noch) das grundlegende Verständnis dazu fehlt.

    WM_LBUTTONDBLCLK, WM_LBUTTONDOWN usw. werden an eine ListView gesendet, nur setzt du die Voraussetzungen dafür nicht richtig...SubClass...

    Nutze einfach die MSDN Library (deutsche Version)(dieser link stammt aus dem Forum, ganz oben.) Ich weis am Anfang ist das ein Buch mit sieben Siegeln, je öfters du es benutzt um so weniger Siegel hat es mit der zeit 😉

    Benutze Google für das was du suchst, eine suche nach WM_LBUTTONDBLCLK, NMITEMACTIVATE oder NM_DBLCLK führt dich direkt zur entsprechenden MSDN Seite, meistens in englisch manchmal auch in deutsch.

    Mein Englisch ist auch nicht sooo perfekt dass ich auf Anhieb verstehe was die MSDN da manchmal schreibt, aber die Übersetzungsprogramme sind mittlerweile so gut, das man sich den Rest selbst zusammen reimen kann.

    MSDN schrieb:

    Pointer to an NMITEMACTIVATE structure that contains additional information about this notification. The iItem, iSubItem, and ptAction members of this structure contain information about the item.

    mit googel übersetzt: schrieb:

    Zeiger auf ein ITEMACTIVATE Struktur, die zusätzliche Informationen zu dieser Mitteilung enthält. Die Artikel, SubItem und ptAction Mitgliedern dieser Struktur enthalten Informationen über das Produkt.

    mit Bing übersetzt: schrieb:

    Zeiger auf eine NMITEMACTIVATE-Struktur, die zusätzliche Informationen über diese Benachrichtigung enthält. Die iItem, iSubItem und PtAction-Member der Struktur enthalten Informationen zum Element.



  • Im Großen und Ganzen kann ich ja was mit dem was da überall geschrieben steht was anfangen. Eigentlich ist das mit dem Englisch ja kein Problem, nur dass das manchmal etwas zu einfach dar gelegt wird. Wenn ich beispielsweise zu SreenToClient in der englischen MSDN geschrieben sehe: "Konvertiert Bildschirmkoordinaten in Koordinaten des Clientfensters", dann frage ich mich halt noch, "was soll denn da rauskommen".

    Hätte ich mir mal unter der MSDN angeschaut, was da unter NM_DBLCLK geschrieben steht, dann wäre ich ja mal eher drauf gekommen. Habe ich total verpeilt.

    Ich danke dir auf jeden Fall vielmals für deine Hilfe, hast mir echt geholfen.

    Gruß
    Kai



  • _Bongo schrieb:

    "Konvertiert Bildschirmkoordinaten in Koordinaten des Clientfensters", dann frage ich mich halt noch, "was soll denn da rauskommen".

    LowFly schrieb:

    ScreenToClient macht im Prinzip nichts anderes als die Desktop Koordinaten von den Koordinaten der Listview auf dem Desktop abzuziehen. Das was übrig bleibt, sind die Koordinaten innerhalb der ListView.

    Desktop Koordinaten = Bildschirmkoordinaten.
    Listview Koordinaten = Clientfensters Koordinaten.

    Wenn du das richtig anwendest funktioniert das auch.


Log in to reply