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 VST: Drag/Drop funktioniert nicht ganz (https://www.delphipraxis.net/117242-vst-drag-drop-funktioniert-nicht-ganz.html)

100nF 14. Jul 2008 19:46


VST: Drag/Drop funktioniert nicht ganz
 
Hallo,

Ich hab wiedermal ein VST-Problem :oops:

Also ich habe 2 VST auf einer Form. In der Rechten VST kann man nichts machen (Drag&Drop), man soll jedoch vom rechten VST markierte Einträge per Drag&Drop in den linken VST kopieren können. Ausserdem will ich im linken VST die Einträge innerhalb der Liste verschieben, also die Reihenfolge verändern können.
Beide Listen haben exakt die selben Eigenschaften, bis auf ein paar Ereignisse die der rechte VST zusätzlich besitzt.

Ich habe bei beiden Listen folgendes eingestellt:
Zitat:

ClipboardFormats: [Virtual Tree Data]
DragMode: dmAutomatic
DragType: dtOLE
Ich habe sehr lange rumprobiert, bis es shcliesslich (scheinbar) funktionierte:
Ach ja, Linke Liste = VST2, rechte Liste = VST1

Delphi-Quellcode:
type
  TArchiv = class(TComponent)
  private
    fFilename: String;
    fTitel: String;
    fInterpret: String;
    fAlbum: String;
    fGenre: String;
    fDauer: TTime;
    fBewertung: Integer;
    fCounter: Integer;
    fDatum: TDate;


    function getPlaylistname: String;
  published
    property Filename:    String read fFilename write fFilename;
    property Titel:       String read fTitel write fTitel;
    property Interpret:   String read fInterpret write fInterpret;
    property Album:       String read fAlbum write fAlbum;
    property Genre:       String read fGenre write fGenre;
    property Dauer:       TTime read fDauer write fDauer;
    property Bewertung:   Integer read fBewertung write fBewertung;
    property Counter:     Integer read fCounter write fCounter;
    property Datum:       TDate read fDatum write fDatum;

    property Playlistname: String read getPlaylistname;

  public

end;
pArchiv = ^TArchiv;

//......

procedure TForm1.VST2DragDrop(Sender: TBaseVirtualTree; Source: TObject;
  DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState;
  Pt: TPoint; var Effect: Integer; Mode: TDropMode);
var
  selnode: PVirtualNode;
  Archiv: TArchiv;
begin
  with Sender as TVirtualStringTree do
  begin
    selnode := VST1.GetFirstSelected;
    while Assigned(selnode) do
    begin
      Archiv := TArchiv(VST1.GetNodeData(selnode)^);
      VST2.AddChild(nil, Archiv); // Kann der Fehler vielleicht an dieser Zeile liegen?!?! Nur so ein Verdacht^^
      selnode := VST1.GetNextSelected(selnode);
    end;
  end;
end;

procedure TForm1.VST2DragOver(Sender: TBaseVirtualTree; Source: TObject;
  Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode;
  var Effect: Integer; var Accept: Boolean);
begin
  if source = VST1 then
    if Assigned(VST1.FocusedNode) then accept := true;
end;
Ich kann vom VST1 Einträge in den VST2 kopieren, so wie es sein soll. Jedoch gibt es beim Beenden des Programms eine Fehlermeldung.
Zitat:

Invalid pointer operation
NodeDataSize habe ich bei beiden VSTs gesetzt.

Was ist an meinem Code falsch, bzw. warum erscheint dieser Fehler?

Ausserdem habe ich keine Ahnung wie ich das rumschieben ermöglichen kann, könnt ihr mir da bisschen auf die Sprünge helfen?
Also eigentlich kann ich schon FAST Einträge rumschieben, es kommt einfach sofort ein "Invalid pointer operation"^^

Wäre echt dankbar für Antworten!

P.S. habe übrigens lange gesucht, das problem ist nur dass viele ein anderes Vorhaben haben oder dass es völlig andere Lösungsansätze gibt, wobei meiner am besten gefällt :stupid:

MFG

Phoenix 14. Jul 2008 20:20

Re: VST: Drag/Drop funktioniert nicht ganz
 
Du kopierst den Eintrag - aber nicht die Daten.
Du hängst also den Pointer des exakt gleichen Objektes in beide Trees.

Wahrscheinlich rufen aber beide Trees in ihrem Event das die Knoten aufräumt Free auf dem Objekt auf. Das heisst Du rufst bei Kopierten Einträgen auf dem selben Objekt zweimal free auf - einmal via Tree1 und einmal über den zweiten. Beim zweiten Zugriff knallt es dann.

Du solltest entweder das Objekt kopieren, oder vorher abprüfen dass das Objekt definitiv noch existiert bevor Du es aufräumst.

semo 14. Jul 2008 20:20

Re: VST: Drag/Drop funktioniert nicht ganz
 
Schau dir mal die Demos zum VST an.
Speziell das OLE-Demo-Projekt.
Dort solltest Du fündig werden.

100nF 14. Jul 2008 20:23

Re: VST: Drag/Drop funktioniert nicht ganz
 
ach soo, verstehe!

Zitat:

Du solltest entweder das Objekt kopieren, oder vorher abprüfen dass das Objekt definitiv noch existiert bevor Du es aufräumst.
was wäre die bessere lösung?
ich tendiere zur zweiten weils wohl einfacher ist, aber hat es auch nachteile?

Phoenix 14. Jul 2008 20:26

Re: VST: Drag/Drop funktioniert nicht ganz
 
Eigentlich hat Zweiteres eher Vorteile. Wenn es dasselbe Objekt ist, und Du z.B. den Text veränderst, dann betrifft das sofort beide Bäume. Ansonsten müsstest Du die Änderung zwischen beiden Objekten synchronisieren.

100nF 14. Jul 2008 20:35

Re: VST: Drag/Drop funktioniert nicht ganz
 
ok das wäre natürlich sehr gut!

hab es jetzt mal so probiert:
Delphi-Quellcode:
procedure TForm1.VST1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  Archiv: TArchiv;
begin
  if assigned(node) then
  begin
    Archiv := TArchiv(Sender.getnodedata(node)^);
    Archiv.free;
  end;
end;
Beiden VSTs ist dieses Ereignis zugeteilt.

Funktioniert jedoch nicht, kommt immernoch der selbe Fehler.
Wenn ich den gesamten code ausklammere, dann funktionierts!
Warum das?

Phoenix 14. Jul 2008 20:38

Re: VST: Drag/Drop funktioniert nicht ganz
 
Der Node ist immer assigned. Aber das NodeData Objekt nicht:

Delphi-Quellcode:
procedure TForm1.VST1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  Archiv: TArchiv;
begin
  if assigned(node) then
  begin
    Archiv := TArchiv(Sender.getnodedata(node)^);
    if Assigned(Archiv) then
      FreeAndNil(Archiv);
  end;
end;

100nF 14. Jul 2008 20:39

Re: VST: Drag/Drop funktioniert nicht ganz
 
hmm funktioniert aber auch nicht, kommt immernoch die selbe fehlermeldung :gruebel:

EDIT:
ach soo, kann es sein dass wenn das erste mal freeandnil() aufgerufen wurde, dass danach dieses objekt eigentlich nicht mehr bestehen dürfte, sich jedoch noch in der zweiten liste befindet?
dann könnte ich einfach das onFreeNode Ereignis der VST2 weglassen, oder? habs getestet, funktioniert wunderbar.
Doch was würde Passieren wenn sich im VST2 noch Objekte befinden, die im VST1 nicht enthalten sind?

Ausserdem wäre ich noch froh wenn ihr mir tipps geben könnt wie ich das mit dem verschieben innerhalb von VST2 machen kann :wink: werde aber morgen nochmal daran arbeiten...

100nF 20. Jul 2008 10:32

Re: VST: Drag/Drop funktioniert nicht ganz
 
also ich habe es soweis mal zum laufen gebracht, ein kleines problem habe ich aber noch...

beim VST1 habe ich "DragOperations" auf [doLink] gestellt. Wenn ich also Nodes vom VST1 in den VST2 ziehe erstellt es mir im VST2 die Verknüpfungen der markierten Nodes vom VST1.
das funktioniert einwandfrai.
nun speichere ich aber beide VSTs beim beenden des Programms ab, und lade Sie beim nächsten Start wieder.
Dazu verwende ich folgende Prozeduren:
Delphi-Quellcode:
procedure TForm1.VST1SaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  Archiv: TArchiv;
begin
  Archiv:=TArchiv(Sender.GetNodeData(node)^);
  Stream.WriteComponent(Archiv);
end;

procedure TForm1.VST1LoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  Archiv: TArchiv;
  p: pArchiv;
begin
  Archiv:=Stream.ReadComponent(nil) as TArchiv;
  p:=sender.GetNodeData(node);
  p^:=Archiv;
end;

//zum Laden:
VST1.LoadFromFile('blabla1.bla');
VST2.LoadFromFile('blabla2.bla');
// und zum speichern:
VST1.SaveToFile('blabla1.bla');
VST2.SaveToFile('blabla2.bla');
Funktioniert auch - nur das Problem ist jetzt dass die Verknüpfungen vom VST2 zum VST1 nicht mehr vorhanden sind! Wenn ich also im VST1 ein Node verändere, dann wird es im VST2 nicht angepasst.

Und nochwas habe ich gemerkt: Wenn ich ein Node vom VST1 in den VST2 "kopiere" (doLink!) und danach diesen Node im VST1 lösche, gibts kurz darauf eine Acces violation weil ein Link dieses Nodes sich noch im VST2 befindet. Im VST2 soll dieser Node aber weiterhin bestehen bleiben!!

Also was meint Ihr, soll ich besser "DragOperations" auf [doCopy] stellen und dann "von Hand" anpassen wenn Änderungen gemacht wurden? oder gibts da eine Lösung für mein problem?

mfg

EDIT: und übrigens, es befinden sich NICHT AUSSCHLIESSLICH verknüpfungen vom VST1 im VST2! Es können sich auch "eigenständige" Nodes im VST2 befinden!

hoika 20. Jul 2008 12:37

Re: VST: Drag/Drop funktioniert nicht ganz
 
Hallo,

ja, ist scon doof ;)

ich löse sowas, indem ich die Objekte in eine eigene Liste (z.B. TObjectList) eintrage.
OnFreeNode macht gar nix.

Beim Beenden des Forms wird die ObjectList "gefreed" und
löscht dann auch die Objekte.


Heiko

100nF 20. Jul 2008 13:38

Re: VST: Drag/Drop funktioniert nicht ganz
 
hmm okay dann werde ich wahrscheinlich auf "DragOperations" = [doCopy] umsteigen und danndie änderungen an einem Node "von Hand" den anderen Nodes mitteilen...

Ich denke das gibt nicht allzu viel Arbeit, und eigentlich dürfte ich dann bei onFreeNode wirklich ALLE Nodes freigeben oder?!
Sind ja dann alle Nodes sozusagen eigenständig...
Werde mich gleich dransetzen und ausprobieren!

Jetzt habe ich aber schon wieder ein Problem :D
Ich will per Button-Klick ALLE Nodes in einem VST per Zufall anordnen, also wild durcheinander mischen.
Sollte ja irgendwie mit Random() möglich sein, aber ich kriegs einfach nicht hin!
Also so hab ich mal begonnen:
Delphi-Quellcode:
procedure TForm1.ShufflePlaylist;
var
  node: pVirtualNode;
  i: integer;
begin
  node := VST2.GetFirst;
  while assigned(node) do
  begin
    randomize;
    vst2.MoveTo(node, was jetzt???);
    node := VST2.GetNext(node);
  end;  
end;
Jedoch geht das schonmal theoretishc nicht, da sich "Node" ja dann selber verschieben würde, und bei GetNext(node) ein Node an einem ganz anderen ort aufgerufen wird, sprich: die schlaufe bearbeitet nicht ein Node nach dem anderen ab!

Ausserdem will ich ja Nodes verschieben, doch bei MoveTo() brauch ich ja das "TargetNode" welches ich nicht habe. Und ein VST.GetNodeAtIndex(25) gibts ja leider nicht.

Habt Ihr mir da vielleicht irgendwelche Lösungsansätzt :?:

Erich07 27. Nov 2009 20:04

Re: VST: Drag/Drop funktioniert nicht ganz
 
Hab ein ähnliches Problem. Verwende die OLE-Demo als Vorlage und arbeite mit Objects und nicht mit Records.
Verschieben per DragDrop funktioniert bestens, beim kopieren sind die Daten weg.

Delphi-Quellcode:
  PNodeDataBasic = ^TNodeDataBasic;
  TNodeDataBasic = class
    Caption : string;
  end;

  NodeDataGroup = ^TNodeDataGroup;
  TNodeDataGroup = class(TNodeDataBasic)
    Filename : string;
  end;

  NodeDataFile = ^TNodeDataFile;
  TNodeDataFile = class(TNodeDataGroup)
    Status : integer;
    List   : TStringList;
  end;

  NodeDataTest = ^TNodeDataTest;
  TNodeDataTest = class(TNodeDataBasic)
    Nr    : integer;
    Count : integer;
    List  : TStringList;
  end;
Auch bei Rocords mit Objects besteht dieses Problem.

Delphi-Quellcode:
  PNodeData = ^TNodeData;
  TNodeData = record
    Caption: String;
    List: TStringList;
    Daten:string;
  end;
Wie werden die einzelen Knoten mit den Daten kopiert? Muss ich da LoadNode und SaveNode oder sonst noch was füttern.

Erich

generic 28. Nov 2009 00:39

Re: VST: Drag/Drop funktioniert nicht ganz
 
Die Daten sind weg (oder es kann zu Problemen kommen) wenn du in deinen Records Dinge ablegst, welche Zeiger nutzen.
z.B. lange Strings, Objekte, Zeigertypen etc.

Erich07 28. Nov 2009 08:48

Re: VST: Drag/Drop funktioniert nicht ganz
 
Zitat:

Die Daten sind weg (oder es kann zu Problemen kommen) wenn du in deinen Records Dinge ablegst, welche Zeiger nutzen.
z.B. lange Strings, Objekte, Zeigertypen etc.
Auf die Schnelle hab ich <List:TStringList> durch <List:string> ersetzt und muss nun jedesmal das entsprechende Element innerhalb des strings suchen.
Das Kopieren bei Drag and Drop funktioniert jetzt.
Die Daten musste ich allerdings streamen.
Delphi-Quellcode:
// Stream ----------------------------------------------------------------------
procedure TMainForm.vstLoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  Data: PNodeData;
  Len: Integer;
begin
 Data := Sender.GetNodeData(Node);
 if not assigned(Data) then exit;
 MemoMsg('LoadNode:'+Data^.Caption);

 Stream.Read(Data^.ID, SizeOf(Data^.ID) );                 //ID
 Stream.Read(Data^.ImageIndex, SizeOf(Data^.ImageIndex) ); //ImageIndex
 Stream.Read(Data^.NodeType, SizeOf(Data^.NodeType) );     //NodeType
 Stream.Read(Data^.Status, SizeOf(Data^.Status) );         //Status
 Stream.Read(Data^.Nr, SizeOf(Data^.Nr) );                 //Nr

 Stream.Read(Len, SizeOf(Len));                            //Caption
 SetLength(Data^.Caption, Len div 2);
 Stream.Read(Data^.Caption[1], Len);

 Stream.Read(Len, SizeOf(Len));                            //Data
 SetLength(Data^.Data, Len div 2);
 Stream.Read(Data^.Data[1], Len);

end;

procedure TMainForm.vstSaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  Data: PNodeData;
  Len: Integer;
begin
 Data := Sender.GetNodeData(Node);
 if not assigned(Data) then exit;
 MemoMsg('SaveNode:'+Data^.Caption);

 Stream.Write(Data^.ID, SizeOf(Data^.ID) );                //ID
 Stream.Write(Data^.ImageIndex, SizeOf(Data^.ImageIndex) ); //ImageIndex
 Stream.Write(Data^.NodeType, SizeOf(Data^.NodeType) );    //NodeType
 Stream.Write(Data^.Status, SizeOf(Data^.Status) );        //Status
 Stream.Write(Data^.Nr, SizeOf(Data^.Nr) );                //Nr

 Len := Length(Data^.Caption) * 2;                         //Caption
 Stream.Write(Len, SizeOf(Len) );
 Stream.Write(Data^.Caption[1], Len);

 Len := Length(Data^.Data) * 2;                            //Data
 Stream.Write(Len, SizeOf(Len) );
 Stream.Write(Data^.Data[1], Len);

end;
Das kann es doch nicht sein! Es gibt bestimmt einen eleganten Weg.
Bei "OnDragDrop" gibt es doch "DataObject: IDataObject". Mit diesem müsste sich doch was machen lassen.
Ich hab keine Ahnung wie das geht.

Erich


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:36 Uhr.

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