Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Drag Drop ListView kurz vor Verzweifelung (https://www.delphipraxis.net/87576-drag-drop-listview-kurz-vor-verzweifelung.html)

TUX_der_Pinguin 2. Mär 2007 13:12


Drag Drop ListView kurz vor Verzweifelung
 
Hallo,

ich habe in einer MDI-Anwendung 2 Fenster mit je einem ListView (vsRaport), ziehe ich jetzte eine Zeile von einem Fenster ins
andere, gehe ich mit der Maus über bestehende Einträge in dem Ziel ListView wird mir der Eintrag markiert wo ich mit der Maus
drauf stehe, lasse ich den neuen Eintrag "fallen", verschwindet die Markierung. Ziehe ich jetzt einen weiteren Eintrag über
das ListView und lasse den Eintrag ausserhalb des Fensters "fallen" weil ich den Falschen Eintrag gewählt habe, bleibt die
Markierung im Ziel ListView erhalten. Warum ist das so bzw. wie bekomme ich das weg? Ich habe keine Ahnnung wo ich ansetzen
muß.

Bin für jeden Tipp dankbar.

mfg

TUX

TUX_der_Pinguin 8. Mär 2007 07:33

Re: Drag Drop ListView kurz vor Verzweifelung
 
Habe ich das ganze so kompliziert beschrieben das es niemand es versteht oder hat niemand das gleiche
Problem. Ich komme einfach nicht weiter, es kann doch nicht sein das ein blöder eintrag als scheinbar
markiert stehen bleibt, aber eigentlich doch nicht markiert ist die Eigenschaft Selected ist nämlich 'False'
an der Stelle.

Hyperspacer 8. Mär 2007 20:02

Re: Drag Drop ListView kurz vor Verzweifelung
 
Moin,
Naja vielleicht wäre ein bissl Quelltext nicht verkehrt, oder? :zwinker:
Wenn ich das richtig verstanden habe bleibt in deinem Ziel-Listview der Eintrag markiert. Auch wenn das Listview neu gezeichnet wird?

mfg
Daniel

marabu 8. Mär 2007 20:31

Re: Drag Drop ListView kurz vor Verzweifelung
 
Hallo,

wahrscheinlich ist das keine schlechte Idee, wenn du ein wenig Quellcode zeigst, denn ich vermute, dass du das Phänomen mit deinem eigenen Code verursachst. Einfach zwei ListViews auf eine Form gezogen und ViewStyle = vsReport und DragMode = dmAutomatic und man erkennt, dass die Markierung eigentlich nicht bleibt:

Delphi-Quellcode:
procedure TDemoForm.ListViewDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  Accept := (Sender <> Source)
        and (Sender is TListView)
        and (Source is TListView);
  if Accept then
    with Sender as TListView do
      Accept := Assigned(GetItemAt(X, Y));
end;
Grüße vom marabu

TUX_der_Pinguin 9. Mär 2007 08:31

Re: Drag Drop ListView kurz vor Verzweifelung
 
Hi,

viel Quelltext kann ich ja nicht posten, da ja nur die Ereignisse DragOver und DragDrop verwendet werden.
Und das Beispiel war schon ganz gut aber das Problem ist nach wie vor da, was mich stört wenn ich über
eine Liste gehe bleibt ein Eintrag markiert auch wenn ich den Eintrag ausserhalb des Fenster fallen lasse
oder in einem anderen Fenster. Was ich will ist wenn ich mit der Maus aus dem ListView raus gehe ohne
den Eintrag in das ListView fallen zulassen, kein Eintrag mehr markiert bleibt.

mfg

TUX

marabu 9. Mär 2007 13:02

Re: Drag Drop ListView kurz vor Verzweifelung
 
Da ich dein Problem mit meinem Code nicht nachvollziehen kann, liegt der Verdacht nahe, dass du das ungewünschte Verhalten selbst programmiert hast. Kannst du ein kleines Testprojekt zum Herunterladen aufsetzen, an dem man dein Problem untersuchen kann? Zwei ListViews auf einer Form, ein paar Einträge über den OI und die Drag&Drop Events? Vielleicht ist der Fehler schon weg, wenn du das Testprojekt selbst ausführst...

Freundliche Grüße

TUX_der_Pinguin 9. Mär 2007 14:08

Re: Drag Drop ListView kurz vor Verzweifelung
 
Liste der Anhänge anzeigen (Anzahl: 1)
So ich habe dann mal ein kleines Testprojekt zusammen gehauen, wo genau das passiert was ich in meinem Hauptprogramm
auch passiert, mit dem Unterschied das in dem Testprojekt die 2 ListView Komponenten auf einem Formular sind und nicht
auf unterschiedlichen Formularen.

Mein Ziel ist es das ich in dem jeweiligen ListView per DragDrop Zeilen verschieben kann, um die Reihenfolge zu ändern.
Weiterhin soll man Zeilen von einem ListView in das andere kopieren können.

Ich habe bei dem Testprojekt nur das DragOver implementiert weil das mein Problem ist.

mfg

TUX

marabu 12. Mär 2007 16:45

Re: Drag Drop ListView kurz vor Verzweifelung
 
Hallo,

das ärgerliche Verhalten wird durch den virtuellen Modus der ListView verursacht - mit der Standard-ListView tritt es nicht auf. Leider habe ich für dein Problem momentan keine Lösung parat, bin aber zuversichtlich, dass es eine gibt. Vielleicht finde ich am Wochenende die Zeit um mich damit zu beschäftigen.

Edit: War gar nicht so schwer. Tracking-Artefakte beim Drag&Drop können zuverlässig beim EndDrag() beseitigt werden.

Delphi-Quellcode:
procedure TfrmMain.LVDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
  Accept := (Sender is TListView)
        and (Source is TListView)
        and Assigned((Sender as TListView).GetItemAt(X, Y));
end;

procedure TfrmMain.LVEndDrag(Sender, Target: TObject; X, Y: Integer);
begin
  with Sender as TWinControl do Invalidate;
  with Target as TWinControl do Invalidate;
end;
Freundliche Grüße

TUX_der_Pinguin 13. Mär 2007 11:26

Re: Drag Drop ListView kurz vor Verzweifelung
 
Hi,

soweit so gut ich habe das ganze ausprobiert funktioniert aber immer noch nicht ganz so wie ich will. Die Zugriffsverletztung
die ich zu erst bekam habe ich weg bekommen.

Delphi-Quellcode:
If Sender Is TListView Then TListView(Sender).Invalidate;
If Target Is TListView Then TListView(Target).Invalidate;
Jedoch bleiben die markierten Zeilen immer noch stehen ... :(

mfg

TUX

marabu 13. Mär 2007 19:18

Re: Drag Drop ListView kurz vor Verzweifelung
 
Leider hast du recht. Da muss sich doch noch jemand drum kümmern. Leider habe ich zur Zeit ein Handicap.

Irgendetwas versucht derzeit meine Augen aus meinem Kopf zu drücken - der Arzt nennt es Grippe.

Verschnupfte Grüße

TUX_der_Pinguin 14. Mär 2007 08:07

Re: Drag Drop ListView kurz vor Verzweifelung
 
Ich habe noch mal geschaut, einen Ansatz wie ich es schaffen könnte in den Fenster die stehen bleibenden Markierungen
zu entfernen habe ich jetzt nur das eigentliche "entfernen" der Markierung klappt nicht.

Hier bei gehts wieder um mein Eigentliches Programm eine MDI Anwendung, aber im Grunde vergleichbar mit dem Testprojekt.
Ich durchlaufe einfach alle Fenster und suche nach einem ListView im "Virtual-Mode". Jetzt fehlt nur noch der letzte schritt.

Ich habs mit Invalidate, Refresh etc. probiert nix, die Markierung bleibt erhalten. Das einzigste was etwas gebracht hat war
kurz ltv_List.Items.Count := 0 und dann wieder auf die korrekte Anzahl zu setzten. Jedoch bekomme ich dann nicht mehr hin
einen Eintrag normal zumarkieren weil dann OnEndDrag ausgelöst wird und mir die Selektion entfernt. Und bei großen Listen
würde wohl auch der Scrollbalken hin und her springen was auch nicht so toll wäre.

Delphi-Quellcode:
  //Alle Fenster nach TListView komponenten durchsuchen
  For i := 0 To frmMain.MDIChildCount-1 Do Begin
    For z := 0 To frmMain.MDIChildren[i].ComponentCount-1 Do Begin
      If frmMain.MDIChildren[i].Components[z] Is TListView Then Begin
        With TListView(frmMain.MDIChildren[i].Components[z]) Do Begin

          If OwnerData Then Begin
            //Die richtige Selektion stehen lassen und die Artefakte entfernen...

          End;

        End;{with}
      End;{if}
    End;{for}
  End;{for}
@marabu Gute Besserung ;-)


mfg

TUX

TUX_der_Pinguin 14. Mär 2007 13:42

Re: Drag Drop ListView kurz vor Verzweifelung
 
Ich habe meinen Vorherigen Quelltext noch mal überarbeitet und jetzt eine etwas "unsaubere" Lösung gefunden wie ich finde.
Lass mich gerne korregieren bzw. verbessern, nur ist mir nichts anderes eingefallen wie es funktionieren könnte.

Delphi-Quellcode:
  //Alle Fenster nach TListView komponenten durchsuchen
  For i := 0 To frmMain.MDIChildCount-1 Do Begin
    For z := 0 To frmMain.MDIChildren[i].ComponentCount-1 Do Begin
      If frmMain.MDIChildren[i].Components[z] Is TListView Then Begin
        With TListView(frmMain.MDIChildren[i].Components[z]) Do Begin

          If OwnerData Then Begin
            //Merken der Selektion sowie Scroll-Position
            SetLength(Sel, SelCount);
            Idx := 0;

            For c := 0 To Items.Count-1 Do Begin
              If Items[c].Selected Then Begin
                Sel[Idx] := c;
                Inc(Idx);
              End;
            End;{for}

            TopIt := TopItem.Index;

            //Reset der Listenelemente
            Count      := Items.Count;
            Items.Count := 0;
            Items.Count := Count;


            //Widerherstellen der Selektion sowie Scroll-Position
            For c := 0 To High(Sel) Do Begin
              Items[Sel[c]].Selected := True;
            End;

            //ShowMessage(fGetField(Scroller[TopIt], 'Ident'));
            While (TopIt > TopItem.Index) Do Scroll(0, 10);

          End;

        End;{with}
      End;{if}
    End;{for}
  End;{for}
Meine Lösung macht jetzt folgendes es wird geschaut welche Einträge ausgewählt wurden, dann wird ebenfalls gemerkt wo der
Scrollbalken steht bzw. welcher Eintrag als erstes Sichtbar ist. Dann wird die Liste gelöscht und gleich neu geladen.
Anschliessend werden die Einträge die zuvor markiert waren wieder markiert und die Liste wird an die ursprüngliche Position
gescrollt.

mfg

TUX

marabu 14. Mär 2007 19:17

Re: Drag Drop ListView kurz vor Verzweifelung
 
Hallo TUX,

ich glaube meine grauen Zellen arbeiten schon wieder besser. Ich habe mit dem Aufruf der folgenden Prozedur im Ereignis OnEndDrag() gute Erfolge erzielt:

Delphi-Quellcode:
procedure ResetDropHighlight(lv: TListView);
var
  i: Integer;
begin
  with lv do
  for i := 0 to VisibleRowCount do
    if i >= Items.Count then
      Exit else
    if Items[TopItem.Index + i].DropTarget then
    begin
      Items[TopItem.Index + i].DropTarget := False;
      Exit;
    end
end;
Ich habe mich gefragt, warum dein Problem bei virtuellen ListViews verschwindet, wenn das Ereignis OnDragDrop() ausgelöst wird. Den VCL-Autoren war aufgefallen, dass die Nachricht LVM_GetNextItem von virtuellen ListViews nicht erwartungsgemäß verarbeitet wird. Sie behandeln allerdings nur den ordnungsgemäß beendeten Drag-Vorgang, ein Abbruch bleibt unbehandelt. Das Testen überlasse ich dir.

Freundliche Grüße

TUX_der_Pinguin 16. Mär 2007 07:21

Re: Drag Drop ListView kurz vor Verzweifelung
 
Juhu es Funktioniert, also nach den ersten Test scheit es jetzt zu funktionieren wie es soll.
Hier noch mal der Quellcode:

Delphi-Quellcode:
procedure Tfrm_Parts_List.pResetDropHighlight(lv: TListView);
var
  i: Integer;

begin
  with lv do
  for i := 0 to VisibleRowCount-1 do
    if i >= Items.Count then
      Exit else
    if Items[TopItem.Index + i].DropTarget then
    begin
      Items[TopItem.Index + i].DropTarget := False;
      Exit;
    end

end;


procedure Tfrm_Parts_List.ltv_ListEndDrag(Sender, Target: TObject; X, Y: Integer);
var
  i,z  : Integer;

begin
  //Alle Fenster nach TListView komponenten durchsuchen
  For i := 0 To frmMain.MDIChildCount-1 Do Begin
    For z := 0 To frmMain.MDIChildren[i].ComponentCount-1 Do Begin
      If frmMain.MDIChildren[i].Components[z] Is TListView Then Begin
        With TListView(frmMain.MDIChildren[i].Components[z]) Do Begin

          If OwnerData Then Begin
            pResetDropHighlight(TListView(frmMain.MDIChildren[i].Components[z]));
          End;

        End;{with}
      End;{if}
    End;{for}
  End;{for}

end;
Es werden alle Fenster durchlaufen und nach einem virtuellen ListView gesucht und dort die fehlerhaften Markierungen entfernt.

Ich hatte zwar schon mal die Eigenschaft DropTarget entdeckt konnte damit aber nicht so recht was mit anfangen.
Also noch mals vielen Dank marabu. Ich denke das scheint eine gute Lösung zu sein, nicht mehr so brutal wie mein Ansatz ;-)

mfg

TUX


Edit: In der Prozedure pResetDropHighlight war noch ein kleiner Fehler, der eine Zugriffsverletztung herbei geführt hat und zwar
muß es VisibleRowCount-1 heißen, da sonst das Ereignis OnData ein Item zeichnen will was nicht existiert.

marabu 16. Mär 2007 13:32

Re: Drag Drop ListView kurz vor Verzweifelung
 
Zitat:

Zitat von TUX_der_Pinguin
Edit: In der Prozedure pResetDropHighlight war noch ein kleiner Fehler, der eine Zugriffsverletztung herbei geführt hat und zwar muß es VisibleRowCount-1 heißen, da sonst das Ereignis OnData ein Item zeichnen will was nicht existiert.

Nein, sonst wir ein partiell sichtbares Item am Ende nicht neugezeichnet. Der Zugriffsfehler soll durch die innere Abfrage verhindert werden.

Freundliche Grüße


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:10 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz