Autor Beitrag
DeadlyAppearance
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Sa 24.07.04 03:04 
Hi, also folgendes Problem.

Ich habe 3 Felder die verpackt werden müssen. Der Höchste Punkt nennt sich Planet. Der 2. nennt sich Datum und der letzte Zeit.
Nehmen wir als Beispiel den Planeten Erde, das Datum 06.07.2004 und als Uhrzeit 19:36:13. So sollte das ganze so aussehen:
ausblenden Quelltext
1:
2:
3:
Erde
  06.07.2004
    19:36:13


Nun kann es sein, das wir an diesem Datum eine weitere Uhrzeit haben, wie z.B. 19:30:00. So sollte das ganze dann aussehen:
ausblenden Quelltext
1:
2:
3:
4:
Erde
  06.07.2004
    19:36:13
    19:30:00


Haben wir für den Planeten noch weitere Berichte an anderen Daten wie dem 07.07.2004, so soll ein weitere Unterpunkt angelegt werden.
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
Erde
  06.07.2004
    19:36:13
    19:30:00
  07.07.2004
    19:36:13
    19:30:00


Haben wir einen neuen Planeten, so wird ein neuer Hauptpunkt angelegt und diese dann erneut verschachtelt. Das ganze könnte dann so aussehen:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Erde
  06.07.2004
    19:36:13
    19:30:00
  07.07.2004
    19:36:13
    19:30:00
Mars
  27.07.2004
    21:36:13
    19:21:00


Bis zum 2. Beispiel funzt meine Methode noch, aber ab dann hängt er die Uhrzeiten erneut unter den ersten Datumspunkt.
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
Erde
  06.07.2004
    19:36:13
    19:30:00
    19:28:13
    19:29:00
  07.07.2004
    (19:28:13) anstatt hier
    (19:29:00) anstatt hier


Und hier meine Methode:
ausblenden volle Höhe Die Methode
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:
procedure TForm2.AddFiles;
var
  i : Integer;
  IniFile : TIniFile;
  Planet, lastPlanet, Datum, lastDatum, Zeit, lastZeit : String;
  MyTreeNode1,MyTreeNode2 : TTreeNode;
begin
  AllFiles.Sort;
  TreeView1.Items.Clear;  
  for i := 0 to AllFiles.Count -1 do  //Stringliste allen Dateien wie z.B. [Erde]06.07.2004(0,81681712962963).ini
  begin
    IniFile := TIniFile.Create(AllFiles.Strings[i]);
    Planet := IniFile.ReadString('Daten','Planet','Planet'); //Für jeden Bericht gibts ne IniDatei. Ich lese aus dieser den korrekten Planeten aus

    Datum := IniFile.ReadString('Daten','Datum','Datum');
    Datum := Trim(copy(Datum,0,pos(' ',Datum))); //Auslesen des Datums

    Zeit := IniFile.ReadString('Daten','Datum','Datum');
    Zeit := Trim(copy(Zeit,pos(' ',Zeit)+1,length(Zeit))); //Auslesen der Zeit

    with TreeView1.Items do
    begin
      if lastPlanet <> Planet then
      begin
        MyTreeNode1 := Add(MyTreeNode1, Planet);
        if lastDatum <> Datum then
        begin
          AddChild(MyTreeNode1,Datum);
          if lastZeit <> Zeit then
          begin
            MyTreeNode1 := TreeView1.Items[1];
            AddChild(MyTreeNode1,Zeit);
          end;
        end
      end
      else
      begin
        if lastDatum <> Datum then
        begin
          Add(MyTreeNode1, Datum);
          AddChild(MyTreeNode1, Zeit);
        end;
        if lastDatum = Datum then
        begin
          AddChild(MyTreeNode1, Zeit);
        end;
      end;
      lastPlanet := Planet;
      lastDatum := Datum;
    end;
  end;
 end;


Ich hoffe, mir kann wer helfen, das Problem zu lösen. Ich weis einfach nit weiter, wie das gehen soll. Hab leider zu wenig Erfahrung mit der TreeView.


Moderiert von user profile iconPeter Lustig: Code- durch Delphi-Tags ersetzt.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 24.07.04 10:01 
Meine erste Frage wäre, ob du Einfluss auf das Speicherformat hast. Die benutzten Einträge in der INI-Datei scheinen mir doch recht umständlich. Wenn ich mal den Code in der Hinsicht interpretiere, dann sieht so eine Datei wohl so aus:
ausblenden Quelltext
1:
2:
3:
[Daten]
Planet=Erde
Datum=06.07.2004 19:36:13

Es wäre einfacher, wenn die Zeit ihren eigenen Eintrag hätte. Wenn diese INI-Datei in deiner Verantwortung liegt (sprich: Du kannst entscheiden, wie sie aufgebaut ist), dann solltest du das Format noch mal überdenken. Mach es so einfach wie möglich, damit du wenig Arbeit hast.

Oder (ja, einige werden jetzt aufstöhnen :mrgreen:) benutze bspw. XML, wenn du kannst/darfst/willst, etwa
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
<Planeten>
  <Planet Name="Erde" Zeit="19:36:13" Datum="06.07.2004"/>
  <Planet Name="Erde" Zeit="19:30:00" Datum="06.07.2004"/>
  <Planet Name="Erde" Zeit="19:36:13" Datum="07.07.2004"/>
  <Planet Name="Mars" Zeit="21:36:13" Datum="27.07.2004"/>
</Planeten>

oder (wenn dir das hier besser gefällt)
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
<Planeten>
  <Planet>
    <Name>Erde</Name>
    <Zeit>19:36:13</Zeit>
    <Datum>06.07.2004</Datum>
  </Planet>
  <Planet>
    <Name>Erde</Name>
    <Zeit>19:30:00</Zeit>
    <Datum>06.07.2004</Datum>
  </Planet>
  <!-- mehr Planeten //-->
</Planeten>

usw.

Letztlich ist es egal, denn die Routine zum Auslesen der Daten (ob nun aus einer INI- oder einer XML-Datei) ist relativ schnell ausgetauscht. Auf der Grundlage deiner Informationen habe ich mal einen Button-Klick zusammengeschraubt. Allerdings arbeite ich in dem Fall nicht mit einer Stringliste, sondern ich habe zum Testen vier verschiedene INIs erstellt und im Array angegeben:
ausblenden volle Höhe 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:
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:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
procedure TForm1.Button1Click(Sender: TObject);

  function GetTreeNode(const TV: TTreeView; Parent: TTreeNode;
    Caption: string): TTreeNode;
  var
    i      : integer;
  begin
    // wenn der Parent "nil" ist, dann alle "Top Level"-Knoten
    // durchsuchen
    if(Parent = nilthen
    begin
      for i := 0 to TV.Items.Count - 1 do
        if(TV.Items[i].Level = 0and
          (CompareText(TV.Items[i].Text,Caption) = 0then
        begin
          Result := TV.Items[i];
          exit;
        end;

      // Knoten existiert noch nicht, daher anlegen
      Result := TV.Items.AddFirst(nil,Caption);
    end
    // ansonsten nur die Unterknoten des Parent
    // berücksichtigen
    else begin
      for i := 0 to Parent.Count - 1 do
        if(CompareText(Parent.Item[i].Text,Caption) = 0then
        begin
          Result := Parent.Item[i];
          exit;
        end;

      // Knoten existiert noch nicht, anlegen
      Result := TV.Items.AddChild(Parent,Caption);
    end;
  end;


const
  // meine Dateinamen; du hast stattdessen deine Stringliste,
  // also beachte bitte die for-Schleife
  FileNames : array[1..4]of string =
    ('erde.ini','mars.ini','erde2.ini','erde3.ini');
var
  i         : integer;
  ini       : TIniFile;
  s1,
  s2        : string;
  Datum,
  Zeit      : string;
  tn,
  sub       : TTreeNode;
begin
  TreeView1.Items.Clear;
  TreeView1.Items.BeginUpdate;

  for i := low(FileNames) to high(FileNames) do
  begin
    s1   := '';
    s2   := '';
    ini  := TIniFile.Create(ExtractFilePath(paramstr(0)) + FileNames[i]);
    try
      s1 := ini.ReadString('Daten','Planet','Planet');
      s2 := ini.ReadString('Daten','Datum','Datum');
    finally

// Du hast vergessen, das TIniFile-Objekt wieder freizugeben.
// Wenn du sehr viele Dateien hast, dann wird bei jedem
// Schleifendurchlauf ein neues Objekt angelegt, und dein
// Speicher (RAM) füllt sich langsam aber sicher.
// Darum, nach getaner Arbeit:

      FreeAndNil(ini);

// Das try/finally ist notwendig, weil du davon ausgehen
// musst/solltest, dass beim Lesen (oder Schreiben) von Werten
// mal etwas schief gehen kann. Mit try/finally kannst du
// auf Exceptions reagieren; hier in dem Fall wird dann zumindest
// noch versucht, dass Objekt freizugeben, wenn innerhalb von
// try/finally was nicht klappt und Fehler verursacht.

    end;

    if(s1 <> ''and (s1 <> 'Planet'and
      (s2 <> ''and (s2 <> 'Datum'then
    begin

// Wenn die Zeit einen eigenen Eintrag in der INI-Datei hätte,
// dann könntest du dir das "Rumgemache" mit dem String hier
// sparen und stattdessen gleich die beiden Variablen oben beim
// Auslesen benutzen

      Datum := Trim(copy(s2,0,pos(' ',s2)));
      Zeit  := Trim(copy(s2,pos(' ',s2) + 1,length(s2)));

// Streng genommen müsste man eigentlich noch prüfen ob die
// beiden Variablen Inhalt haben (also <> '' sind), denn wer
// garantiert, dass der Eintrag in der INI nicht (un)absichtlich
// verändert wurde?


      // Mit der Funktion "GetTreeNode" wird nun überprüft, ob
      // es den Knoten "s1" (= Planetenname) schon gibt. Da als
      // Parent NIL benutzt wird, durchsucht die Funktion nur die
      // Root-Knoten.
      // Existiert der Knoten noch nicht, wird er automatisch
      // angelegt
      tn    := GetTreeNode(TreeView1,nil,s1);
      // Rückgabewert ist der angelegte Knoten, damit du jetzt
      // einen Anhaltspunkt für die Unterknoten hast

      if(tn <> nilthen
      begin

      // Das Prinzip ist das gleiche: Du prüfst, ob es den
      // Knoten für das Datum schon gibt. Diesmal gibst du
      // aber den Parent "tn" an, den du gerade gefunden bzw.
      // neu angelegt hast. Dadurch landet das Datum (wenn es
      // noch nicht existiert) automatisch unter dem eben
      // erstellten/gefundenen Root-Knoten
        sub   := GetTreeNode(TreeView1,tn,Datum);

      // Und das gilt dann natürlich auch für die Zeit, wobei
      // du hier als Parent die Variable "sub" benutzt, weil
      // das ja der Datums-Knoten ist
        if(sub <> nilthen
          GetTreeNode(TreeView1,sub,Zeit);
      end;
    end;
  end;

  TreeView1.Items.EndUpdate;
end;
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Sa 24.07.04 15:35 
Danke dir. Werde mir das ganze heute Abend anschauen und was dazu sagen. Aber die ersten Zeilen sahen von dir vernünftig aus :).

/edit
Bin gleich einen trinken, aber hab eben mal über das, was du geschrieben hast, drüber geschaut. Schaut nicht schlecht aus. Und vielen Dank für die Arbeit, die du dir gemacht hast! Mit den ganzen Kommentaren usw. Einfach Weltklasse. Werde es heute Abend gleich mal testen und dann den Stand der Dinge hier schreiben :).

/edit1
axo, eine Frage hab ich noch. Ich wollte das gnaze noch mit Bildchen verschönern. Sprich Planet, Datum und Uhrzeit hat jeweils ein anderes Bild. So wie ich es gemacht hatte, dem Node nen Imageindex zuzuweisen, haben alle das gleiche Bild. Aber wie weise ich jeder Ebene nen anderes Bild zu?

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 24.07.04 17:16 
Okay, Imageliste (TImageList) auf die Form, die Bildchen rein, dann den Tree-View auswählen und die Imageliste im Objektinspektor auswählen. Angenommen, das Planeten-Bild ist das erste, dann hat es den Index 0. Soll heißen, s. Code oben
ausblenden Delphi-Quelltext
1:
2:
3:
4:
tn               := GetTreeNode(TreeView1,nil,s1);
tn.ImageIndex    := 0;
tn.SelectedIndex := 0// <-- evtl. anderer Index, wenn sich das
                       // Bild bei der Auswahl ändern kann/soll

Das gleiche machst du bei den beiden anderen Knoten, wobei du bedenken musst, dass ich bei der Zeit das Rückgabeergebnis ignoriert habe. Das darfst du nicht machen, weil du ja das Bild zuweisen musst. Sprich: aus
ausblenden Delphi-Quelltext
1:
2:
        if(sub <> nilthen
          GetTreeNode(TreeView1,sub,Zeit);

wird
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
        if(sub <> nilthen
begin
  tn := GetTreeNode(TreeView1,sub,Zeit);
  tn.ImageIndex ...

end;

Und du gibst anstelle der Null einfach den Index des gewünschten Bildes an. Aber das hängt von der Imageliste ab, die ja die Bilder enthält.
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Sa 24.07.04 17:20 
Du bist echt klasse. Also die Procedure funktioniert genau so, wie ich es brauche. Habs gerade mit den IniFiles getestet. Werde heute Abend das ganze umschreiben für die Stringlist und dann im Lifeprogramm testen. Desweiteren werde ich mir zu gemühte fürhren, wie du das eigentlich machst :)
Und schon mal danke für die Info mit den Bilder, werde das heute Abend auch mal austesten.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 24.07.04 18:35 
DeadlyAppearance hat folgendes geschrieben:
Du bist echt klasse.

Ich weiß. :mrgreen:
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: So 25.07.04 12:32 
Also irgend wie hab ich was gegen die Componente ^^.

Wollte jetzt raus bekommen, welches Node makiert ist. Hab das ganze mit selected versucht. Ich bekomme aber nur den Text zurück bei Planet und Datum, die unterste Ebene, Zeit, kommt leer hoch.
Ich brauche ne Methode, die mir nur was liefert, wenn der Anwender auf die unterste Ebene Zeit klickt. Tuht er dies, so brauch ich den String des Datums, also eine Ebene höher und dann den Planeten, wo das Datum zu gehört. Denn nur mit diesen 3 Werten kann ich anschließend die richtige IniFile Laden.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 25.07.04 18:24 
DeadlyAppearance hat folgendes geschrieben:
Wollte jetzt raus bekommen, welches Node makiert ist. Hab das ganze mit selected versucht. Ich bekomme aber nur den Text zurück bei Planet und Datum, die unterste Ebene, Zeit, kommt leer hoch.

Könntest du das genauer erläutern? Du klickst auf den Knoten mit der Zeit, erhältst als Rückgabewert aber nicht den Text des Knotens - also die Zeit? Oder wie?

Zitat:
Ich brauche ne Methode, die mir nur was liefert, wenn der Anwender auf die unterste Ebene Zeit klickt. Tuht er dies, so brauch ich den String des Datums, also eine Ebene höher und dann den Planeten, wo das Datum zu gehört. Denn nur mit diesen 3 Werten kann ich anschließend die richtige IniFile Laden.

Nennt sich "Parent". Mal ein Beispiel aus einem anderen Programm, bei dem ich etwas vergleichbares benötigt habe: Egal auf welchen Knoten der User geklickt hat, es soll grundsätzlich der Name des obersten (Root) ermittelt werden
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
  // es muss ein Knoten gewählt sein
  if(tv1.Selected = nilthen exit;

  // der wird zugewiesen, ...
  root  := tv1.Selected;
  // ... & dann wird immer der Parent
  // ermittelt, bis man ganz oben ist
  while(root.Parent <> nildo
    root := root.Parent;

  // und dann kann man damit irgendwas
  // machen
  self.CallNamespaceMerge(root.Text);

"root" ist eine TTreeNode-Variable.
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Mo 26.07.04 02:40 
Klappt alles wunderbar :)
Nur eine Sache hab ich noch und zwar sortieren. Hab in der Hilfe geschaut. Da gibts zwar Sort, aber kann es irgend wie net aufrufen. Und SortType bringt nicht den erwünschten Erfolg...
Es sollen halt alle Planeten sortiert werden, von A-Z. Dann eine Ebene weiter, das Datum, das net Weihnachten vor Ostern steht ^^. Und auf letzter Ebene die Uhrzeit.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 26.07.04 08:10 
ausblenden Delphi-Quelltext
1:
TreeView1.AlphaSort;					

ist die einfachste Variante. Ansonsten gibt es noch die Möglichkeit über eigene Suchroutinen, aber dazu müsstest du Beispiele im Forum bzw. in der Hilfe finden können.