Autor |
Beitrag |
LonghornUser
      
Beiträge: 796
|
Verfasst: Di 21.02.06 00:22
Hallo,
ich habe heute mal ein Listview auf meine Form geschoben, um mal etwas damit herumzuprobieren. Und zwar möchte ich zur Laufzeit Komponenten erstellen. Realisieren möchte ich dies mit einem PopupMenü, was die Befehle "Neuer Ordner" (Zweig), "Neuer Eintrag" (Kein Zweig) haben soll. Dies stellte sich aber als schwerer heraus als gedacht. Deswegen habe ich mal ein paar Fragen:
1.) Wie kann ich Icons bei Zweigen so einstellen, dass bei einem offnen Zweig das eine und bei geschlossenem das andere gezeigt wird ?
2.) Wie kann ich erkennen, wo die Maus beim Öffnen des Popupmenüs war ? Also, wenn ein "Neuer ordner" erstellt wird, WO das passiert (bis jetzt funzt es nur so, dass es immer im in der ersten Ebene (Root) erstellt wird.
Danke schonmal.
Ciao LHUser
|
|
Lannes
      
Beiträge: 2352
Erhaltene Danke: 4
Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
|
Verfasst: Di 21.02.06 00:48
Hallo,
kann es sein das Du ein TreeView meinst 
_________________ MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Di 21.02.06 01:38
Nein, ich meine schon TListView mit der Eigenschaft ViewStyle := vsList. Oder geht das, was ich machen will auch mit einem TreeView ?
|
|
Lannes
      
Beiträge: 2352
Erhaltene Danke: 4
Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
|
Verfasst: Di 21.02.06 09:37
Hallo,
vorrausgesetzt wir reden hier von Standard-ListViews/TreeViews.
Ich weis jetzt nicht was Du mit offnen bzw. geschlossenen Zweig bei einer ListView mit ViewStyle = vsList meinst. Mit der Einstellung vsList werden die Items in Spalten angeordnet, da gibt es doch keine offnen bzw. geschlossenen Zweig. Desweiteren sprichst du von Ordnern und Ebenen(Root), Ordner-Strukturen können in einem TreeView angezeigt werden, deshalb meine Annahme, das es sich um ein TreeView handelt.
Bei einem TreeView kann man bei den Eigenschaften Item.ImageIndex und Item.SelectedIndex unterschiedliche Images zuweisen, die dann entsprechend dem Zustand des Items(Knoten) anzeigt werden.
LonghornUser hat folgendes geschrieben: |
2.) Wie kann ich erkennen, wo die Maus beim Öffnen des Popupmenüs war ? Also, wenn ein "Neuer ordner" erstellt wird, WO das passiert (bis jetzt funzt es nur so, dass es immer im in der ersten Ebene (Root) erstellt wird. |
Ohne Code kann man da so nichts zu sagen.
_________________ MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Di 21.02.06 17:18
Lannes hat folgendes geschrieben: | Hallo,
vorrausgesetzt wir reden hier von Standard-ListViews/TreeViews.
Ich weis jetzt nicht was Du mit offnen bzw. geschlossenen Zweig bei einer ListView mit ViewStyle = vsList meinst. Mit der Einstellung vsList werden die Items in Spalten angeordnet, da gibt es doch keine offnen bzw. geschlossenen Zweig. Desweiteren sprichst du von Ordnern und Ebenen(Root), Ordner-Strukturen können in einem TreeView angezeigt werden, deshalb meine Annahme, das es sich um ein TreeView handelt. |
Stimmt, du hast Recht. Mit einem Listview geht das nicht. Ich habe das ganze jetzt mal in ein Treeview getan, wie du es gesagt hast. Mit Zweig meine ich übrigends das:
[Bild im Anhang]
Zitat: |
Bei einem TreeView kann man bei den Eigenschaften Item.ImageIndex und Item.SelectedIndex unterschiedliche Images zuweisen, die dann entsprechend dem Zustand des Items(Knoten) anzeigt werden.
|
Naja, Selected ist ein Knoten ja nicht immer, wenn er offen ist. Er kann auch geöffnet sein, aber nicht selektiert. Wie kann ich das prüfen ?
Und bei der zweiten Frage: Es geht mir einfach darum. Ich möchte eine Art Ordnerstruktur machen. Also mit Ordner, Unterordner erstellen, Datei in Ordner erstellen. Aber leider weiß ich nicht, wie man vom Popupklick her weiß, ob gerade innerhalb Ordner1 oder innerhalb Ordner2 geklickt wurde. Weißt du, wie man das machen könnte ?
Einloggen, um Attachments anzusehen!
|
|
Lannes
      
Beiträge: 2352
Erhaltene Danke: 4
Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
|
Verfasst: Di 21.02.06 17:54
Hallo,
folgendes bezogen auf den ersten Eintrag in einem TreeView.
-feststellen ob Knoten expandiert ist:
Delphi-Quelltext 1: 2:
| if Treeview1.Items[0].Expanded then | - hat der Eintrag Unterordner(Children)
Delphi-Quelltext 1: 2:
| if Treeview1.Items[0].HasChildren then |
zum Thema Popup und welcher Eintrag wurde angeklickt, schau Dir mal GetNodeAt und getHitTestInfoAt an.
_________________ MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Di 21.02.06 18:39
Cool, danke. Jetzt geht alles wunderbar 
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Di 21.02.06 20:26
Hallo nochmal,
ich hätte da doch nochmal ein Problem bezüglich des TreeViews. Ich möchte ja eine Art Datei-Übersicht für ein Installationserstellungsprogramm machen, was so aussieht (Siehe Anhang). Ich möchte praktisch, dass dynamisch Ordner über das TreeView hingefügt werden können und dass folgendes geht:
Jedem Ordner sollen bestimmte Dateien zugewiesen werden können. Das habe ich bis jetzt über ein Stringgrid realisiert (In dieses werden die Dateien geschrieben, die dann beim Wechseln der Selektion im Treeview, im ListView aktualisiert werden). Dabei teste ich allerdings den Index im TreeView. Nun folgendes Problem. Der User hat Dateien hinzugefügt und erstellt dann einen neuen Ordner im Treeview zwischen 2 bestehenden Ordnern, dann ändert sich doch auch der Index der nachfolgenden Ordner und schwups, die Zuordnung stimmt nicht mehr.
Hätte da jemand eine Idee, wie ich das realisieren kann ?
|
|
Lannes
      
Beiträge: 2352
Erhaltene Danke: 4
Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
|
Verfasst: Di 21.02.06 20:39
Hallo,
und wo ist der Anhang?
An jeden Item kann man ein Objekt hängen,
schau Dir mal TTreeNode.Data bzw. TTreeNodes.AddObject an.
_________________ MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Di 21.02.06 21:00
Aha. Das Bidl hatte ich vergessen.
Ich gucke mir mal die beiden funktionen an.
Einloggen, um Attachments anzusehen!
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Di 21.02.06 21:31
Mhm, ich bekomme es irgendwie net hin. Ist schon ein bissel kryptisch.
Ich habe jetzt mal testweise ein TreeView mit 2 Items auf der Form. Es soll dem aktuellen TNode ein Wert (von Edit1.text) zugewiesen werden. Und denen möchte ich nun etwas zuweisen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.SpeedButton1Click(Sender: TObject); var z:integer; begin z := TreeView1.Selected.Index; showmessage(pchar(TreeView1.Items[z].Data)); end;
procedure TForm1.SpeedButton2Click(Sender: TObject); var z:integer; begin z := TreeView1.Selected.Index; TreeView1.Items[z].Data:=PChar(edit1.text); end; |
Das klappt überhaupt nicht. Wenn ich Speedbutton2 klicke, ist die Message entweder leer oder es steht nur alles bis auf das letzte im Edit befindliche Zeichen da. Woran kann das liegen ?
Moderiert von Gausi: Code- durch Delphi-Tags ersetzt
|
|
Lannes
      
Beiträge: 2352
Erhaltene Danke: 4
Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
|
Verfasst: Mi 22.02.06 01:27
Hallo,
Data ist ein Zeiger auf Daten,
darauf setzt du einen Zeiger(Pchar) auf Edit1.Text,
deshalb hast Du dann immer den inhalt von Edit1.Text.
So müsste es richtig sein:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.SpeedButton1Click(Sender: TObject); var z:integer; begin z := TreeView1.Selected.Index; showmessage(string(pchar(TreeView1.Items[z].Data))); end;
procedure TForm1.SpeedButton2Click(Sender: TObject); var z:integer; begin z := TreeView1.Selected.Index; TreeView1.Items[z].Data := StrNew(PChar(edit1.text)); end; |
! den mit NewStr reservierten Speicher freigeben:
Delphi-Quelltext 1:
| StrDispose(PChar(TreeView1.Selected.Data)); |
Für Dein Vorhaben bieten sich eigentlich StringListen an,
dann kannst Du mehrere Strings an einen Knoten hängen.
Beispielsweise so:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| function TForm1.TVKnotenData(aNode: TTreeNode) : TStringList; var s : string; begin Result := TStringList.Create; Result.Add(aNode.Text); Result.Add(CheckListBox3.Items[CheckListBox3.ItemIndex]); Result.Add(Edit1.Text); end;
procedure TForm1.SetTVKnotenData; begin TreeView1.Selected.Data := TVKnotenData(aNode); end;
procedure TForm1.TV1DataFree; var i : Integer; begin if TreeView1.Items.Count 0 then for i := 0 to TreeView1.Items.Count-1 do if TreeView1.Items.Item[i].Data <> nil then begin TStrings(TreeView1.Items.Item[i].Data).Free; end; end; |
Zugreifen auf die Stringlisten geht dann so:
- Anzahl Einträge?
Delphi-Quelltext 1:
| TStrings(TreeView1.Items.Item[i].Data).Count |
- String hinzufügen:
Delphi-Quelltext 1:
| TStrings(TreeView1.Items.Item[i].Data).Add(''); |
- ersten String in der StringList des selectierten Knoten
Delphi-Quelltext 1:
| showmessage(TStrings(TreeView1.Selected.Data)[0]); |
//Edit: ist ja schon fast ein Tut geworden 
_________________ MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 22.02.06 08:55
Ich habe hier auch noch etwas Code:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101:
| type TShowType = (online, away, dnd);
type TUser = packed record Username: string[255]; ID: string[255]; OnlineType: TShowType; Groups: TStringList; end; PUser = ^TUser;
TUsers = array of PUser;
procedure TForm1.Button1Click(Sender: TObject); var Users : TUsers; i : Integer; j : Integer; cnt : Integer; RootNode : TTreeNode; ChildNode : TTreeNode; begin setlength(Users, 3); new(Users[0]); Users[0]^.Username := 'Freddy'; Users[0]^.ID := '12597'; Users[0]^.OnlineType := online; Users[0]^.Groups := TStringlist.Create; Users[0]^.Groups.Add('Freunde'); Users[0]^.Groups.Add('Schule');
new(Users[1]); Users[1]^.Username := 'Hans-Peter'; Users[1]^.ID := '598756'; Users[1]^.OnlineType := away; Users[1]^.Groups := TStringlist.Create; Users[1]^.Groups.Add('Firma'); Users[1]^.Groups.Add('Freunde');
new(Users[2]); Users[2]^.Username := 'Karl-Heinz'; Users[2]^.ID := '789534'; Users[2]^.OnlineType := dnd; Users[2]^.Groups := TStringlist.Create; Users[2]^.Groups.Add('Schule'); Users[2]^.Groups.Add('Fussball'); Users[2]^.Groups.Add('Freunde');
for i := 0 to length(Users) - 1 do begin RootNode := Treeview1.Items.AddObject(nil, PUser(Users[i])^.Username, TObject(Users[i])); if PUser(Users[i])^.OnlineType = online then begin RootNode.ImageIndex := 0; RootNode.SelectedIndex := 0; end else if PUser(Users[i])^.OnlineType = away then begin RootNode.ImageIndex := 1; RootNode.SelectedIndex := 1; end else if PUser(Users[i])^.OnlineType = dnd then begin RootNode.ImageIndex := 2; RootNode.SelectedIndex := 2; end; cnt := PUser(Users[i])^.Groups.Count; for j := 0 to cnt - 1 do begin ChildNode := Treeview1.Items.AddChild(RootNode, PUser(Users[i])^.Groups.Strings[j]); ChildNode.ImageIndex := 3; ChildNode.SelectedIndex := 3; end; end; end;
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode); var ID : string; begin if Assigned(PUser(Treeview1.Selected.Data)) then ID := PUser(Treeview1.Selected.Data)^.ID; Label1.Caption := ID; end;
procedure TForm1.Button2Click(Sender: TObject); var i : Integer; begin if Treeview1.Items.Count > 0 then for i := Treeview1.Items.Count - 1 downto 0 do begin if Assigned(PUser(Treeview1.Items[i].Data)) then begin FreeAndNil(PUser(Treeview1.Items[i].Data).Groups); Dispose(PUser(Treeview1.Items[i].Data)); end; end; Treeview1.Items.Clear; end; |
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Mi 22.02.06 17:44
@ Lannes. Aber irgendwie klappt das noch immer nicht so richtig.
Ich nutze das TreeView und auch dasd Erstellen von eigenen Typen noch nicht so lange. Deswegen bin ich ein bissel verwirrt.
Könntest du nochmal ein Beispiel schreiben, wie ich ganz einfach einem Item in einem TreeView eine Stringlist zuordne und diese mittels einem Button füllen kann (mit einzelnen Strings). ABER: Das Problem ist: Wenn ich noch andere Items einfüge, dann soll die Stringlist trotzdem übernommen werden (also wenn sich der ItemIndex des Nodes ändert). Also so wie in meinem 2. Bild. Geht sowas ?
|
|
Lannes
      
Beiträge: 2352
Erhaltene Danke: 4
Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
|
Verfasst: Mi 22.02.06 18:18
Hallo,
na gut  , jetzt ganz einfach:
- dem ersten Eintrag(Index 0) der TreeView eine StringList zuweisen:
Delphi-Quelltext 1: 2: 3: 4:
| procedure TForm1.Button1Click(Sender: TObject); begin TreeView1.Items[0].Data := TStringList.Create; end; |
- Strings in die Stringlist schreiben:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TForm1.Button2Click(Sender: TObject); begin TStrings(TreeView1.Items[0].Data).Add('Ein String'); TStrings(TreeView1.Items[0].Data).Add('Noch ein String'); TStrings(TreeView1.Items[0].Data).Add('Noch einer'); end; |
Die Zugriffsmöglichkeiten auf die Stringlisten und die Freigabe derselben hab ich im letzten Post beschrieben.
LonghornUser hat folgendes geschrieben: | ABER: Das Problem ist: Wenn ich noch andere Items einfüge, dann soll die Stringlist trotzdem übernommen werden (also wenn sich der ItemIndex des Nodes ändert). |
Data ist ein Zeiger auf Daten, in diesem Fall die erzeugte Stringlist. Über Data wird die Stringlist an den Node gebunden. Das ist unabhängig an welchem Index sich der Node befindet. Es macht also nichts wenn der Node durch das einfügen neuer Nodes verschoben wird.
_________________ MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Mi 22.02.06 18:40
Danke für die Geduld  Jetzt gehts langsam  Ich werde mal weiter testen 
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Do 23.02.06 23:10
@Lannes:
Hallo mal wieder. Ich habe mal ein bissel weitergemacht, aber irgendwie habe ich Probleme beim Speichern und Laden. Es soll ja möglich sein, seine Änderungen zu speichern (Wie die Dateiliste verändert wurde). Aber ich habe keine AHnung, wie man das machen könnte.
Könntest du vielleicht mal gucken, wie man das machen könnte und ob meine Lösung bis jetzt gut ist ? Das wäre echt super. Danke schonmal.
Einloggen, um Attachments anzusehen!
|
|
Lannes
      
Beiträge: 2352
Erhaltene Danke: 4
Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
|
Verfasst: Fr 24.02.06 23:16
Hallo,
hab mir den Code mal angeschaut, da sind mir ein paar Sachen aufgefallen.
Deine Funktion ExtractFileName erübrigt sich, sie ist in SysUtils schon vorhanden.
Das verhindern der Bearbeitung der TreeView-Nodes der ersten Ebene kann man einfacher realisieren.
Der Code:
Delphi-Quelltext 1: 2: 3: 4:
| if (Treeview1.Selected.Text='[INSTALLDIR]') or (Treeview1.Selected.Text='[WINDIR]') or (Treeview1.Selected.Text='[FONTSDIR]') or (Treeview1.Selected.Text='C:\') then |
ist funktionell identisch mit:
Delphi-Quelltext 1: 2:
| if Node.Level = 0 then |
Der Parameter Node wird Dir vom Ereignis OnEditing geliefert und Level ist die Indexierung der Tree-Ebenen.
Beispiel:
Quelltext 1: 2: 3:
| Root = Level 0 +-Eintrag = Level 1 +--Eintrag = Level 2 |
Die Freigabe der Stringlisten fehlt noch.
Die Verwaltung der Stringlisten in einem Array ist IMHO insgesamt schwieriger, auch im Hinblick auf Speicher- und Ladevorgänge, als mein Vorschlag die Stringlisten direkt an die Knoten der TreeView zu binden.
Bindest Du die Stringlisten direkt an,
kannst Du über verschachtelte Schleifen speichern und Laden:
Quelltext 1: 2: 3:
| for i := 0 to treeView.Count-1 do for j := 0 to TStrings(TreeView1.Items[i].Data).Count-1 do //mach was mit.z.B showmessage(TStrings(TreeView1.Items[i].Data)[j]); |
Zum speichern hast Du verschiedene Möglichkeiten,
ist aber abhängig davon was sonst noch alles(Einstellungen...) gespeichert werden muss,
und ob alles mit einer Datei abgedeckt werden soll.
Da bietet sich eine Ini an,
oder Du speicherst den TreeView-Baum mit TreeView.SaveToFile,
die Stringlisten sammelst Du in einer Stringliste die dann mit StringList.SaveToFile gespeichert wird.
In dieser "Sammel"-Stringliste muss dann auch die Zugehörigkeit der jeweiligen Stringlisten zu den Knoten der TreeView gespeichert werden, damit sie beim Laden wieder der TreeView zugeordnet werden können.
_________________ MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
|
|
LonghornUser 
      
Beiträge: 796
|
Verfasst: Fr 24.02.06 23:20
Cool. Danke für Hilfe. Ich probiers mal. 
|
|
|