| Autor |
Beitrag |
cyberax
      
Beiträge: 247
Win XP Pro
Delphi 5 Enterprise
|
Verfasst: Sa 10.02.07 19:31
Hallo, benutze mysql und Zeos Komponenten. ich habe eine Artikel tabelle. Nun sollen die Artikel verschiedenen Kategorien zugeordnet werden. Dafür ist sicher ein Treeview passend. Die Artikel sollen dann so dargestellt werden. +Hauptgruppe 1 -Hauptgruppe 2 +Untergruppe 1 +Untergruppe 2 -Untergruppe 3 - Artikel 1 - Artikel X .... Es sollen beliebig viele Gruppen und Untergruppen bzw. Einträge definiert werden können. Ich dachte mir das so, wie es in vielen Online - Shops der Fall ist. Wie kann ich nun am besten hinterlegen/speichern wo welcher Artikel liegt, bzw. wie der Baum aussieht? Bei dem Treeview kann man ja einfach den Inhalt speichern, aber ich möchte nicht den dargestellten Text speichern, sondern etwas eindeutiges - wie die ID des Artikels. Gibt es für so etwas eine Komponente? Oder wie könnte ich das am einfachsten machen? Gruß cyberax Moderiert von Christian S.: Titel geändert.
|
|
stifflersmom
      
Beiträge: 194
XP /XP PRO/ SuSE div.
D1 - D7, BDS 2006
|
Verfasst: Sa 10.02.07 20:15
Ich weiß nicht ob es die beste Komponente für Dein Vorhaben ist,
aber was Bäume angeht ist wohl das VirtualTreeView von Mike Lischke
die Komponente überhaupt. Deer Umgang damit ist zwar definitiv aufwendiger
als mit einem "normalen" TreeView, dsfür hast Du allerdings dievesre Möglichkeiten
Deine Anforderungen zu befriedigen.
Beim VirtualTreeView kannst Du (ja mußt Du sogar) jedem Node einen record zuordnen
und der kann natürlich auch eine ID aus Deiner Tabelle aufnehmen.
By The way, hast Du vor, eine Verwaltung für die datenbank vom Oscommerce oder sogar
Xtcommerce zu entwickeln?
Moin
|
|
Grenzgaenger
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Sa 10.02.07 21:16
dafür baut man sich normal eine rekursive tabelle auf. dort stehen dann einfach die zuordnungen drin. wenn du möchtest, kannst ja zusätzliche informationen hinterlegen. tabellenaufbau ist so
t{@key; SubKey; ...}
die musst dann nur noch auswerten und deinen tree entsprechend aufbauen. sollte kein problem sein.
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Sa 10.02.07 21:16
man kann bei dem "normalen" TTreeView auch Daten zuordnen, jeder Knoten hat einen Data-pointer
Was Du brauchst, ist nicht das speichern eines Treeviews, sondern eine vernünftige Daten-Definition in deiner Datenbank.
zum bsp:
Table1=Hauptgruppe1
ID : integer; (unique!)
Name : String;
... (was du sonst noch brauchst)
Table2=Untergruppe
ID : Integer; (unique!)
ID_Hauptgruppe : Integer; (Verweis auf die ID der Hauptgruppe)
Name : String;
... (was du sonst noch brauchst)
Table3=Artikel
ID : Integer; (unique!)
ID_Untegruppe: Integer; (Verweis auf die ID der Untergruppe, damit hast du automatisch die Hauptgruppe dazu)
Name : String;
...
somit hast du für alle artikel den Baum.
Im programm erzeugst du für alle Hauptgruppen einen Knoten, dann Lädst du die Untergruppen und legst Kindknoten in den Hauptgruppen an für die untergruppen. Dann gehst zu deinen Artikeln und machst das gleiche dort, allerdings als kinder der untergruppen. Aus der Tabelle weisst Du ja, zu welche Untergruupe welcher Artikel gehört.
Du kannst es natürlich auch so machen, dass Du statt 2 Tabellen für Gruppen nur 1 machst, die noch ein ID feld bekommmt, wo Du auf die Hauptgruppe verweist. Ist es 0, dann ist der Gruppeneintrag eine Hauptgruppe. Ist es grösser als 0, dann eine UNtergruppe und die ID ist der verweis auf die Hauptgruppe.
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
cyberax 
      
Beiträge: 247
Win XP Pro
Delphi 5 Enterprise
|
Verfasst: Do 15.02.07 23:21
Also vielen Dank für eure Hilfe!
@stifflersmom - habe das mit der Komponente auf die "Schnelle" nicht hinbekommen. Habe nur die für Lazarus gefunden..  ..
werde es nun so machen, wie ihr es mir geraten habt. Eine tabelle
"gruppe" mit:
id
gr_id
name
In der Tabelle "artikel" gibt es eine "gr_id" wo der Verweis auf die nächste Gruppe steht. In der nächsten Gruppe steht der Verweis per "gr_id" auf die nächste und so weiter, bis die "gr_id" = 0 ist. Das wäre dann eine Hauptgruppe.
Also vielen Dank. Muss es nun nur noch umsetzen 
|
|
cyberax 
      
Beiträge: 247
Win XP Pro
Delphi 5 Enterprise
|
Verfasst: Fr 16.02.07 00:45
| Zitat: |
die musst dann nur noch auswerten und deinen tree entsprechend aufbauen. sollte kein problem sein
|
...stellt doch ein kleines Problem dar. Habe schon im Forum gesucht aber leider nix gefunden, was mit hilft. Also ich habe nun eine tablle "gruppe" wie beschrieben.
Ich hatte mir das mit dem Füllen des Trees so gedacht, dass ich aus der tabelle erst alle Einträge abfrage, die zur Hauptgruppe gehören ("gr_id"=0) und diese in das Tree schreibe. dann wollte ich die nächsten einlesen und so weiter. Nur habe ich keine Ahnung, wie ich das am besten umsetze bzw scheint mir das recht umständlich..
@Grenzgaenger: meintest du, ich solle in die artikel tabelle ein Feld haben in dem der vollständige Pfad steht (zum Beispiel:"Hauptgruppe1/Untergruppe8/Artikelx")?
|
|
Grenzgaenger
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Fr 16.02.07 01:00
also das ist 'n rekursiver algo. musst mal bei deiner datenbank schaun, vielleicht unterstützt sie das ja per sql.  . bpw. oracle konnte zumindest in version 7 entsprechende auflösungen in sql direkt auflösen. bei mySQL kenn ich mich gar nicht aus. ansonsten musst ihn halt per software nachbilden. der ist eigentlich recht einfach, musst nur aufpassen, dass sich der algo durch sich selbst definiert. und er macht ja da auch nichts anderes wie sich den knoten herauszuhohlen, sich selbst einzuknüpfen und zu gucken ob er unterknoten hat, wenn ja, fängt das ganze wieder von vorne an... bis in die 'zig'ste ebene.. wichtig dabei ist, dass die tabellendefiniton auch rekursiv aufgebaut ist, wie in meinen ersten post aufgezeigt, sonst brichst du dir die finger bei der implemtation. wünsch dir noch viel erfolg. ich meinte, in der tabelle sollten die primärschlüssel stehen. die tabelle selbst braucht nur aus zwei feldern zu bestehen, einen schlüssel und einen schlüssel, der auf den schlüssel verweisst. bspw. t{@k;@s} Quelltext 1: 2: 3: 4: 5: 6:
| 1 3 3 4 3 5 5 6 5 7 7 9 | das würde den folgenden baum ergeben Quelltext
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 16.02.07 15:17
Ich hatte dasselbe Problem auch schon mal, allerdings mit C++ und Firebird.
In diesem Artikel steht meine damalige Lösung dazu, mit einer Stored Procedure, die die Daten entsprechend aufbereitet und einer Prozedur, die das TreeView füllt. Ich denke, es sollte nicht so schwierig sein, beides in Delphi-code zu übersetzen und noch die Verwendung der Data-Eigenschaft einzubinden.
|
|
cyberax 
      
Beiträge: 247
Win XP Pro
Delphi 5 Enterprise
|
Verfasst: Sa 17.02.07 13:34
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Sa 17.02.07 15:58
Ich glaube, rein technisch gesehen musst Du nur die Abgfrage nach ID sortieren lassen, denn kein SubNode kann eher erstellt worden sein, als deren Parent.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| tv_eg1.Items.Clear; with ZQuery_GRUPPE do begin sql.Text:='SELECT * FROM GRUPPE ORDER BY ID ascending'; open; end; While not ZQuery_GRUPPE.EoF do begin If ZQuery_GRUPPE.FieldByName('id_gr').AsInteger = 0 Then tv_eg1.Items.AddFirst( nil,ZQuery_GRUPPE.FieldByName('name').Text) Else begin MyGr_ID := ZQuery_GRUPPE.FieldByName('id_gr').AsInteger; MyName := ZQuery_GRUPPE.FieldByName('name').Text; AddSubNodeMain(MyGr_ID, MyName); end; ZQuery_GRUPPE.Next; end; |
Deine Aufgabe wird es nun sein, eine
Delphi-Quelltext 1:
| procedure AddSubNodeMain(MyGr_ID : Integer; MyName: String); |
zu schreiben, die wieder eine rekursive funktion aufruft, welche immer tiefer in deinen Baum eindringt. Du gibst also dieser funktion einen deiner rootnodes mit (die, die gr_id=0 haben), die funktion testet, ob kinder da sind, wenn ja, schnappt sie sich das erste kind, ruft sich selbst auf mit dem ChildNode, wenn nicht, testet sie auf Siblings. Und bei jedem Node, der gefunden wird, wird geprüft, ob die Gr_ID des nodes die ist, die du suchst. Hast Du den node gefunden, gibst du ihn zurück als funktionsresult. Und wenn du in der funktion siehst, dass da ein Result ist (Result <> nil), dann immer schön die Suche abbrechen, dann kommst du aus der Rekursion raus.
Bist du nach dem ersten Durchlauf noch ohne Ergebnis, nimmst du ihn der procedure "AddSubNodeMain" den nächsten Sibling und schickst ihn wieder an die rekursive funktion.
Oh, und btw... wie du im Code ganz oben gesheen hast habe ich deine "Repeat..Until" gegen eine "While not EoF do.." getauscht. Das liegt daran, dass Repeat-Until fusslastige schleifen sind, While-Do sind aber kopflastige.
Eine Fusslastige schleife wird mind. 1x durchlaufen und wenn du aus irgendeinem Grund keine Daten drin hast, gibt es einen crash.
Bei einer kopflastigen Schleife kann das nicht passieren, da sie nicht unbedingt durchlaufen wird, sondern erst geprüft wird, ob eine gewissen Grundvoraussetzung gegeben ist (in dem Fall, ob überhaupt Daten für die abfrage zurück kamen).
Hoffe, das half dir jetzt ein bisschen, Klarheit reinzubringen in deinen Task. den rekursiven Algo hab ich dir bewusst nicht geschrieben, Du musst das ja lernen, nicht ich
LG aus Caracas.
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
cyberax 
      
Beiträge: 247
Win XP Pro
Delphi 5 Enterprise
|
Verfasst: Sa 17.02.07 17:46
Okay vielen Dank!
Muss also selbst überlegen ...?...
Okay ist richtig. Ich werde mich mal versuchen und das Resultat (auch wenn es unter Umständen zur allg. Belustigung beiträgt)  später schreiben.
Grüße zurück aus Deutschland
|
|
cyberax 
      
Beiträge: 247
Win XP Pro
Delphi 5 Enterprise
|
Verfasst: So 18.02.07 23:35
Bin mit dieser Sache "leicht" überfordert...
Habe nun versucht das ganze mal zu ordnen und denke das die procedure AddSubNodeMain(MyGr_ID : Integer; MyName: String); wie folgt aufgebaut sein muss:
Quelltext 1: 2: 3:
| Node anlegen Kindertest durchfü0hren (where gr_id = id des akt. Nodes) bei Kindertest = JA ruft sich die Funktion selbst wieder auf, bei Kindertest = NEIN -> RAUS |
Sie Sieht so bei mit aus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure AddSubNodeMain(MyGr_ID : Integer; MyName: String); var MyTreeNode: TTreeNode; begin MyTreeNode := artikel_baum.tv_eg1.Items[mygr_id]; artikel_baum.tv_eg1.Items.AddChild(MyTreeNode,myname); if kindertest(artikel_baum.ZQuery_GRUPPE.FieldByName('id').AsInteger) = 1 then AddSubNodeMain(artikel_baum.zquery_search.FieldByName('gr_id').asinteger,artikel_baum.zquery_search.FieldByName('name').text); end; |
die Funktion "Kindertest" so: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function kindertest(id:integer):real; var MyTreeNode: TTreeNode; begin with artikel_baum.zquery_search do begin sql.Text:='SELECT * FROM GRUPPE WHERE ID = :searchid'; With Params.ParamByName('searchid') do begin DataType := ftinteger; Value := id; End; open; end; if artikel_baum.zquery_search.RecordCount>0 then result:=1 else result:=0; end; |
Funktioniert nicht. (Hätte mich auch gewundert.  )
Stimmt denn mein Denkansatz wie oben beschrieben mit deinem überein bzw. könnte er so funktionieren ?
Benutze ja in der Kindersuch- Funktion auch ein zweites Query. Ist das nötig?
| Zitat: | | Und bei jedem Node, der gefunden wird, wird geprüft, ob die Gr_ID des nodes die ist, die du suchst |
Ich habe keine Ahnung, wie ich das machen soll??!!!??
Habe mir echt den Kopf zerbrochen und alles auch mehrmals aufgemalt, aber komm hier nicht weiter 
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Mo 19.02.07 01:01
Naja, du hattest nicht ganz richtig gelesen
In der AddSubNodeMain gehst du "nur" zum root-knoten, der schnappt sich das erste child un dsendet es an eine ANDERE funktion, die rekursiv ist und sich selbst aufruft, je tiefer sie eindringt in den Baum.
AddSubNodeMain geht nur durch die Siblings (Geschwister) in der ersten ebene, die als Parent den Rootnode haben, ungefähr so :
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:
| unit uTreeView_Helper;
interface
uses Windows, DB, ComCtrls, Classes, SysUtils, Controls, GlobalVars, ResClient;
Type RNodeData = packed record StringID : Integer; HookNr : Integer; end; PNodeDate = ^RNodeData;
function TreeAddItem(Sender: TTreeView; IL: TImageList; pData : PConfigHookData; RC: TResClient; Resort: Boolean): TTreeNode; function TreeFindItem(Sender: TTreeView; NodeItem: TTreeNode; Name: String): TTreeNode;
implementation
function TreeAddItem(Sender: TTreeView; IL: TImageList; pData: PConfigHookData; RC: TResClient; Resort: Boolean): TTreeNode; var ThisNode, Node : TTreeNode; S : String; pND : PNodeDate; begin Node := nil; S := RC.GetString(pData^.ParentName); ThisNode := TreeFindItem(Sender, Node, S); If ThisNode <> nil Then Node := ThisNode Else begin New(pND); pND^.StringID := pData^.ParentName; pND^.HookNr := 0; Node := Sender.Items.AddChildObject(nil, S, pND); Node.ImageIndex := pData^.ParentImage; Node.SelectedIndex := pData^.ParentImage; end; New(pND); pND^.StringID := pData^.Name; pND^.HookNr := pData^.HookNr; S := RC.GetString(pData^.Name); ThisNode := Sender.Items.AddChildObject(Node, S, pND); ThisNode.ImageIndex := pData^.Image; ThisNode.SelectedIndex := pData^.Image; ThisNode.StateIndex := ThisNode.Level + 1; If Resort and (Node.Parent <> nil) Then Node.Parent.AlphaSort; Result := ThisNode; end; function TreeFindItem(Sender: TTreeView; NodeItem: TTreeNode; Name: String): TTreeNode; begin if NodeItem = nil Then NodeItem := Sender.Items.GetFirstNode Else NodeItem := NodeItem.GetFirstChild; if (NodeItem <> nil) and (NodeItem.Text <> Name) then repeat NodeItem := NodeItem.GetNextSibling; until (NodeItem = nil) or (NodeItem.Text = Name); Result := NodeItem; end; end. |
Ist ne Unit, die ich mal vor jahren geschrieben habe. In dem Fall ging ich davon aus, dass es immer nur 2 Lebel gibt in dieser Anwendung. Aber es sollte für dich ja kein Problem sein, es dementsprechend zu erweiterm. dass TreeFindItem bei Unterknoten sich entsprechend selbst wieder aufruft. Ist natürlich mehr Code, als Du brauchst, da es ich es für mich für eine ganz spezielle Situation geschrieben habe... Aber es sollte etwas helfen 
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
Grenzgaenger
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 19.02.07 02:36
hallo cyberax, wenn du nur das ttreeview verwendest, kannste auch den baum über den index travisieren. das geht ähnlich wie bei 'er stringlist . Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| ... t: ttreeview; i: integer; ... begin for i := 0 to t.items.count - 1 do listbox.items.add(t.Items[i].Text); end. | PS: aus der OH: "Der Zugriff auf Einträge im Baumdiagramm über den Index kann sehr zeitaufwendig sein, wenn das Diagramm viele Einträge enthält. Verwenden Sie daher aus Geschwindigkeitsgründen in Ihren Anwendungen möglichst wenige Indexzugriffe auf Elemente." von daher ist die zugriffsmethode von helge immer noch dieser vorzuziehen. daher dies nur als anregung. ausserdem solltest du beim hinzufügen die schlüsselinformation mit in die daten des nodes mit aufnehmen, dann kannst jederzeit auf deine datenbank eindeutig referenziern  . und nicht vergessen, beim löschen des nodes auch wieder die data strukturen freizugeben, sonst neigt sich dein hauptspeicher recht schnell dem ende zu ...
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Mo 19.02.07 07:09
mir ist grad 'ne Idee gekommen (die für meine Zwecke zu unpraktisch wäre/war, aber eben für Dich ganz gut). Ich habe das letzten Mal für meine Resourcen-Sachen in meinen Resourcen-Manager eingebaut.
Kurze beschreibung des Resourcen-Problems bei mir. Man kann in pro Bibliothek (also EXE oder DLL) Resourcen ID's nur bis MAX_WORD (also 0-65.535) vergeben. Nur will ich allerdings die Möglichkeit haben, alle Resourcen von n-DLL's (die Zahl weiss ich ja jetzt noch nicht und kann im laufe der Jahre anwachsen) in einem Manager zusammenfassen und dass das Modul, welches eine Resource anfordert, nicht wissen muss, woher die Resource kommt. Bei einer Beschränkung von 65k "kann" es mal voll werden. Als Lösung habe ich mir den Basis-Multiplikator ausgedacht. Das funktioniert wie ein Überlauf-Register. Sagen wir, die Haupt-Resourcen-DLL hat die Basis 0, also alle angeforderten Resourcen mit einer ID zw. 0 und 65.535 kommen aus dieser DLL. Ist die Nummer grösser als 65.535, wird eine Modulo-Operation angewandt, wie oft passt eine 65.535 in die ID, bevor das Endergebnis kleiner ist. Damit habe ich dann a) die wirkliche ID der Resource und b) die Basis, wonach ich die entsprechende Resourcen-Bibliothek anwählen kann, um dann die Resource zu holen.
Ok, jetzt wirst du dich fragen, was das ganze mit dir zu tun hat. Sehr viel
Ich finde Deine Idee nicht gut (und widerspricht auch allen gängigen designs, die ich kenne), die Artikel mit den Gruppen zusammen in einem Treeview unterzubringen (abhängig natürlich von der Anzahl der Artikel). Ich würde ab mind. 50 Artikel das Ganze eher 3-gegliedert aufbauen : TreeView, ListView, Detail-Ansicht (wahrscheinlich ein Panel mit aufgelegten Formular oder Controls). Aber das ist im Endeffekt Deine Sache
Was Du machen kannst, um schnell den richtigen Baum zu finden, ist ungefähr das Gleiche, was ich mit meinem Resourcen mache. Ich habe das Beispiel mit meinen Resourcen deswegen gewählt, weil es verständlicher im Grundprinzip ist. Und mit dem Grundprinzip kannst Du auch Dein Problem einfacher lösen.
Für jede Hauptgruppe vergibst Du einen Basis-Multiplaikator. Sagen wir 1.000.000. Ist eine beliebige gesuchte ID grösser als 1 mio, brauchst Du in das erste Element garnicht reinzuschauen, da es unter 1 mio ist. Damit scheidet ein ganzer Tree beim durchsuchen aus. In der Untergruppe wählst Du dir einen anderen Multiplikator aus, sagen wir 10.000. Also hast Du platz für 100 Untergruppen (sollten eh nicht soviele werden, oder es wird zu unübersichtlich und Du solltest generell mal über das problem der datendarstellung nachdenken). Alle Unter-Untergruppen (also Kinder der kinds-gruppen der Hauptgruppen) kriegen auch einen Basis-Multiplikator, sagen wir 100, das gibt dir 100 IDs Platz für diese Untergruppen und 100 Platz für Artikel (die eh nur bis 50 gehen oder eben getrennt angezeigt werden sollten).
Wie findest Du da nun schnell den passenden Knoten ? Ganz einfach.
Nehmen wir an, die gelesene ID ist 1.059.756
Im Rootknoten findest Du 5 Kinder, deine Hauptgruppen. Sie haben die IDs 1, 2, 3, 4 und 5.
Deine Formel ist (ID - 1) * BasisMultiplikator für die StartID, EndID ist StartID + BasisMultiplikator - 1
Das Erste brauchst Du nicht zu durchsuchen, die ID ist 1, also StartID ist 0, EndID ist 999.999. Und anstelle da jetzt reinzugehen und alle Kinderknoten zu durchsuchen, beschränken wir uns auf den Test, ob die von uns gesuchte ID in diesem Bereich liegt, das ist eh allemal schneller
Im 2. Item ist die ID 2, also hast du den Bereich von 1.000.000-1.999.999. Nun liegt Deine ID in dem Bereich, also gehst Du rein und ziehst von der gesuchten ID den Basis-Multiplikator für Hauptgruppen ab. Übriug bleibt die ID 59.756 und Dein neuer Basis-Multiplikator ist 10.000. Also los un den Knoten suchen, der als basis die 6 hat ((ID - 1) * BasisMultiplikator), also zw. 50.000 und 60.000... dann wieder in die nächste Kinds-Ebene...
Das ist natürlich nur die Idee, und ist auch etwas abgefahrener als meine Idee für meine Resourcen, aber hey, smot kannst Du echt schnell Dein Zeug finden, selbst wenn du tausende Knoten hast (ok, nur, wenn sie nicht alle auf einer Ebene liegen, sondern dem von dir geschildertem Auftreten folgen.. aber es ist ja eine Lösung für dich  )
Wenn Du das gern umsetzen willst, dann können wir gemeinsam drüber nachdenken, falls Du problem hast... Oder vllt hat jemand eine solche Lösung parat (bin ja nicht der Einzigste, der abgefahrene Ideen hat !)
So, ich geh jetzt ins Bett, ist spät...
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
cyberax 
      
Beiträge: 247
Win XP Pro
Delphi 5 Enterprise
|
Verfasst: Mo 19.02.07 22:44
@Grenzgaenger:
habe deinen Vorschalg probiert, aber hat bei mir das selbe Ergebnis geliefert wie meine Funktion. Sprich die Einträge waren nicht an der richtigen Stelle. Das liegt sicher daran, dass der Index in jedem Knoten immer wieder von 0 beginnt. Daher geht meine Funktion auch so nicht auf und es kommt zu falschen Einordnungen im Tree.
@helgelange:
Also finde die Idee von dir wirklich sehr gut. Doch (wie dir schon bekannt ist  ) bin ich noch nicht ganz hinter das System gestiegen.
Also lieber erst einmal zu deinen Funktionen...
Frage(n):
Die variablen Resort und IL benötige ich ja (vorerst) nicht um das Tree zu füllen.
Quelltext 1:
| S := RC.GetString(pData^.ParentName); |
Ich müsste also an dieser Stelle mit einem zweiten Query den Rootnode suchen und den Name (???) des Nodes übergeben, auf den mittels "gr_id"(DB) von dem aktuellen Node (das erstellt werden soll) verwiesen wird ?? Ist dieser Name eindeutig??? "Autos" zum Beispiel kann doch mehrmals in dem Tree vorkommen....?!?
Oder wie erkenne ich sonst den Name des parents?
Und wofür steht das ...
Quelltext
Ich hoffe das auch ich das hier irgendwann mal verstehe und hoffe bis dahin auf eure weitere Mithilfe!
Danke schonmal für eure Mühen!!
Und gute Nacht...
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Mo 19.02.07 23:51
nah, RC.GetString ist für meinen Resourcen-manager, einfach raus
er liefert den Namen für den Knoten wieder (ist wichtig für Mehrsprachigkeit etc. bei mir).
pND^ zeigt auf meine pNodedata-struktur und HookNr ist eine Variable in der Strucktur, die ich an jedem node brauche. Kann für Dich auch raus.
IL ist die ImageList, brauch ich scheinbar nicht mehr in der Routine, weiss auch nicht, warum es noch da ist
In "TreeFindItem" musst du vom Prinzip nur noch entscheiden, ob ein Eintrag noch weitere Untereinträge hat, oder ob du zum NextSibling gehst.
In TreeAddItem kannst Du alles rauswerfen, was mit Images zu tun hat oder HookNr. Du musst Dir eine Struktur für Deine Nodedata basteln (wenn Dir die ID nicht reichen sollte), ansonsten gibst Du an die Routine eben nur auch Deine Gr_ID mit und vergleichst sie jeweils mit der ID des augenblicklichen Nodes.
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
Grenzgaenger
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 21.02.07 01:39
hier mal 'n kleines beispiel, schnell runtergeschrieben aber es sollte in etwa zeigen, wie das funktioniert... 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:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, contnrs;
type TForm1 = class(TForm) b: TButton; lb: TListBox; tv: TTreeView; od: TOpenDialog; procedure bClick(Sender: TObject); procedure tvDeletion(Sender: TObject; Node: TTreeNode); private public end;
var Form1: TForm1;
implementation
{$R *.dfm}
type tft= class (tobject) grp, nd: integer; bez: string; end;
procedure TForm1.bClick(Sender: TObject); procedure LoadAndSplit(const sl: tstringlist; const ol: tobjectList); var i: integer; ft: tft; s : string; begin for i := 0 to sl.Count - 1 do begin ft:= tft.create; s := sl.Strings[i]; if s <> '' then begin ft.grp:= strtoint(copy(s,1,pos(',',s)-1)); delete(s,1,pos(',',s)); ft.nd:=strtoint(copy(s,1,pos(',',s)-1)); delete(s,1,pos(',',s)); ft.bez := s; ol.add(ft); end; end; end; procedure AddTV(const ol: tObjectList; nd: ttreenode); function AddNode(const ol: tObjectList;nd: tTreeNode): ttreenode; var dta: tft; begin dta := tft.Create; dta.grp := tft(ol.Items[0]).grp; dta.nd := tft(ol.items[0]).nd; dta.bez := tft(ol.items[0]).bez; result := tv.Items.AddChildObject(nd, tft(ol.Items[0]).bez, dta) end; begin if ol.Count > 0 then begin if tft(ol.Items[0]).grp = 0 then nd := NIL; if nd = NIL then nd:=addnode(ol, nd) else if tft(nd.Data).nd = tft(ol.Items[0]).grp then nd := addnode(ol, nd) else nd := addnode(ol, nd.GetNext); ol.Delete(0); AddTV(ol,nd); end; end; var sl: tstringlist; ol: tobjectlist; i : integer; begin od.Filter := 'textdatei | *.txt'; if od.execute and fileexists(od.FileName) then begin sl := tstringlist.Create; try sl.loadfromfile(od.FileName); ol := tobjectlist.Create; try LoadAndSplit(sl, ol); for i := 0 to ol.Count - 1 do lb.Items.Add(inttostr(tft(ol.Items[i]).grp)+', '+inttostr(tft(ol.items[i]).nd)+', '+tft(ol.items[i]).bez); AddTV(ol, NIL); finally ol.Free; end; finally sl.free; end; end; end;
procedure TForm1.tvDeletion(Sender: TObject; Node: TTreeNode); begin if (node <> NIL) and (node.data <> NIL) then begin tobject(node.data).free; node.Data := NIL; end; end;
end. | es wird vorausgesetzt, dass die eingabedatei sortiert ist. alles andere sollte bereits im thread erwähnt sein. wenn du grossere sprünge hast, musst evtl. bei der IF anweisung in der form AddTV anpassungen vornehmen. <HTH>
Einloggen, um Attachments anzusehen!
|
|
uwewo
      
Beiträge: 154
|
Verfasst: Mi 21.02.07 08:58
Hallo,
warum musst Du denn überhaupt alle Daten sofort in das TreeView schreiben?
Ich hatte das mal wie folgt gelöst:
Erstelle zuerst die Haupgruppen mit einem Dummy Eintrag damit das + vor den Hauptgruppen erscheint, jetzt reagierst Du erst beim öffnen einer Hauptgruppe
Delphi-Quelltext 1: 2:
| procedure TForm.TreeListExpanding(Sender: TObject; Node: TTreeNode; var AllowExpansion: Boolean); |
und führst hier die neue SQL Anweisung aus, um die Hauptgruppe mit Untergruppen zu füllen usw. Das spart Zeit und Speicher beim öffnen des Formulars, ausserdem ist es auch übersichtlicher zu programmieren.
Nur eine Idee
|
|
cyberax 
      
Beiträge: 247
Win XP Pro
Delphi 5 Enterprise
|
Verfasst: Mi 21.02.07 19:45
Kurze Zwischenfrage: wie kann ich denn meine Integer Variable (gr_id) einem Treenode zuweisen?
Quelltext 1:
| MyTreeNode := artikel_baum.tv_eg1.Items[mygr_id]; |
So funktioniert es jedenfalls nicht, da so das treenode immer nil bzw. "()"...?!? was bewirkt, dass immer nur ROOT Einträge erstellt werden
|
|
|