CListCtrl - Drag & Drop



  • Siehe
    C++-Grundlagen->virtuelle Funktionen



  • was ne virtuelle Funktion ist weiß ich. Aber ich bekomm den Event gar nicht. Ich weiß nicht wie ich mein Dialog, die Liste und das COleDropTarget unter einen Hut bekomme. In der FAQ steht was von OnLButtonUp da komm ich rein aber nur wenn ich die Maus nicht über meiner Liste loslasse.
    Gib deinem Herz einen Stoß 🙄 und gib mir einen Tip.



  • Der Tip war ok, Du hast ihn nur nicht verstanden!

    Du bekommst doch den Event. Denn ab der Registrierung Deines CDropTarget in der 2. Liste werden alle DragEnter/DragOver/DragLeave/Drop-Ereignisse an die virtuellen Funktionen des COleDropTarget weitergeleitet!

    Du musst dazu WM_LBUTTONUP nicht verarbeiten.



  • ich habs soweit glaub ich verstanden wie es theoretisch gehen soll. Aber den Event bekomm ich nicht.
    Ich hab in meinem Dialog 2 CListCtrl Objekte als Membervariablen und eine Membervariable m_Drop (Objekt von COleDropTarget). Um die zu registrieren mach ich in OnInitDlg m_Drop.Register(&m_LstRechts). In der Hilfe steht wenn Register erfolgreich war kommt ein Wert <> 0 zurück (bei mir 1 also wohl OK). Dann hab ich noch in meinem Dialog die Funktion:
    CDialog::OnLvnBegindragLinks(NMHDR *pNMHDR, LRESULT *pResult) da komm ich rein aber wenn ich die Maustaste wieder loslasse passiert einfach nix. 😕
    Bitte helft mir nochmal.



  • Also in BeginDragLinks erstellst Du (mit new) ein neues COleDataSource-Objekt, welchem Du das Item mitgibst, welches gerade unter der Maus liegt.
    Dann rufst Du von diesem OleDataSource-Objekt DoDragDrop auf.
    Damit springt er dann in eine Schleife, die solange ausgeführt wird, bis LBUTTONUP empfangen wird.
    Bewegst Du jetzt die Maus auf Deine rechte Liste, ruft DoDragDrop OnDragEnter/OnDragOver des OleDropTargets auf. Dort werden dann normalerweise die Daten innerhalb der OleDataSource abgeprüft, ob sie für dieses Fenster gültig sind. Je nachdem gibt man dann eine der Konstanten
    DROPEFFECT_NONE
    DROPEFFECT_COPY
    DROPEFFECT_MOVE
    DROPEFFECT_LINK
    DROPEFFECT_SCROLL
    zurück.

    Sollte der letzte bekannte Wert nun != DROPEFFECT_NONE sein, wenn die Maus losgelassen wird, wird die virtuelle Funktion OnDrop aufgerufen, in der dann das eigentliche Droppen passiert, also das ListCtrl-Item wieder aus der DataSource extrahiert und dann in die neue Liste eingefügt wird.
    Danach wird das mit new angelegte DataSource-Objekt automatisch gelöscht.

    [ Dieser Beitrag wurde am 05.03.2003 um 15:39 Uhr von RenéG editiert. ]



  • W A H N S I N N ich habs geschaft Vielen Dank.

    Wenn du aber trotzdem noch etwas Lust hast, dann könntest du vielleicht noch etwas über dieses abgefahrene Objekt COleDataSource erzählen, z.B. wie man da Daten reinschreiben kann und wieder rausbekommt.

    Ich habs mal so probiert:

    COleDataSource* data = new COleDataSource;
        HGLOBAL hgData = GlobalAlloc(GPTR,sizeof(int)); 
        hgData = &pNMLV->iItem;
        data->CacheGlobalData(CF_TEXT,hgData);
    

    und um die Daten rasuzuholen hab ich :

    HGLOBAL hgData = pDataObject->GetGlobalData(CF_TEXT);
    

    aber da fliegt er gnadenlos raus



  • Erstens darfst Du den mit GlobalAlloc erstellten Pointer nicht einfach so mit &iItem überschreiben, zweitens ist iItem kein CF_TEXT-Format und drittens darfst Du auch niemals einen nur im m_LstLinks definierten Index-Integerwert an irgendein Objekt weitergeben, welches schlimmstenfalls in einem anderen Prozess definiert ist.

    Die Idee mit dem CacheGlobalData war aber schon nicht schlecht.

    Als erstes definierst Du Dir ein eigenes Clipboard-Format mit RegisterClipboardFormat. Einer der beiden Werte, entweder der String-Parameter oder der Rückgabewert von RegisterClipboardFormat müssen dann auch dem rechten ListCtrl bzw. dem COleDropTarget bekannt gemacht werden.
    Als nächstes lässt Du Dir ein Übergabeformat für ListCtrl-Items einfallen. Schlimmstenfalls haben diese mehrere Spalten, Icons oder Checkboxes. Je nachdem, wie komplex das ist, kannst Du natürlich auch das Handle des ListCtrls übergeben. Dazu muss allerdings dann das COleDropTarget wissen, dass es sich bei dem Handle um ein ListCtrl handelt, nehmen wir das mal in Deinem Fall an.

    Jetzt ein Beispiel:

    // global
    const UINT CF_MYLISTRCTRL = RegisterClipboardFormat( _T("Mein ListCtrl"));
    
    // in OnLvnBegindragLinks
    COleDataSource* data = new COleDataSource;
    HGLOBAL hgData = GlobalAlloc(GPTR,sizeof(HWND)); 
    HWND* pData = (HWND*)GlobalLock( hgData);
    *pData = pNMLV->hdr.hwndFrom;
    GlobalUnlock( pData);
    data->CacheGlobalData(CF_MYLISTCTRL, hgData);
    
    // In OnDrop
    HGLOBAL hgData = pDataObject->GetGlobalData(CF_MYLISTCTRL);
    HWND hWndListLinks = *(HWND*)GlobalLock( hgData);
    GlobalUnlock( hgData);
    if( !::IsWindow( hWndListLinks))
      return FALSE;
    CListCtrl list;
    list.Attach( hWndListLinks);
    // hier dann die Selektion aus dem ListCtrl holen
    // ...
    list.Detach();
    return TRUE;
    // fertig
    


  • Ich hab das ausprobiert wie du es hier beschrieben hast. Aber er fliegt raus
    und zwar hier
    CListCtrl list;
    list.Attach( hWndListLinks); //fliegt raus
    Ich hab ein wenig rumprobiert und hab dann die 2 Zeilen durch die ersetzt:
    CListCtrl* list = (CListCtrl*)list->FromHandle(hWndListLinks);
    Kann man das so machen??
    Muß ich hier auch list->Detach machen ?? Wenn ich die Hilfe richtig verstanden habe dann brauch ich das nicht.

    Zum Abschluß muß ich wohl noch sagen, dass du wohl der absolute C++ Gott bist den ich kenne. 🙂
    Vielleicht sollte das hier in die FAQ
    Vielen Dank nochmal.

    [ Dieser Beitrag wurde am 06.03.2003 um 10:25 Uhr von dscho editiert. ]



  • Ja, muss man wohl so machen mit dem FromHandle.
    Da ich in der letzten Zeit mehr mit der WTL/ATL arbeite, habe ich vergessen, dass das so geht 😉

    Wenn ich die Hilfe richtig verstanden habe dann brauch ich das nicht.

    Du hast die Hilfe richtig verstanden, da *list ja ein Zeiger ist und somit der CWnd-Destruktor nicht aufgerufen wird.

    Zum Abschluß muß ich wohl noch sagen, dass du wohl der absolute C++ Gott bist den ich kenne.

    Danke, aber diese Ehre gebührt mir nicht. In C++ bin ich gar nicht soooo gut. Kenne mich nur mit bestimmten Windows-APIs ganz gut aus.



  • Ok, is was für die FAQ !


Anmelden zum Antworten