CTreeCtrl - Unterknoten hinzufügen
-
plizer schrieb:
Sollte doch eigentlich das ergeben:
Root
|
+--Child1
| |
| +--ChildChild
|
+--Child2Nein aber das hier.
+--Root | +--Child1 | | | +--ChildChild | +--Child2
plizer schrieb:
Ok, ich nehm alles zurück und behaupte das Gegenteil
Funktioniert. Wusste nur nicht, dass Standardmäßig keine Icons dabei sind.
Meinst du Icons für jewilgen Knoten oder die Plus-/Minuszeichen? Die müssen natrülich per Flag gesetzt werden.
-
Ich hatte einfach nicht gemerkt, dass ein Baum aufgebaut wurde. Als nächsten muss ich jetzt mal schauen, wie das mit den Bildern geht. Danke für Deine Hilfe!
-
plizer schrieb:
Ich hatte einfach nicht gemerkt, dass ein Baum aufgebaut wurde. Als nächsten muss ich jetzt mal schauen, wie das mit den Bildern geht. Danke für Deine Hilfe!
Das ist auch kein Problem. Du weist dem TreeView eine ImageList mit SetImageList zu. Füllst diese mit Bildern.
Beim hinzufügen von TreeView Items muss du dann das Flag TVIF_IMAGE in der Itemstruktur setzen (mask Member) und weist dem iImage Member den Index des Bildes in der ImageList zu.
-
Gibt es eine Möglichkeit zu erfragen, ob ein string schon als Unterknoten verhanden ist? Ich muss nämlich aus einer liste von strings einen Baum erstellen.
Aus:A12 A15 A16 A21 A23 A30 B12 B13 B23 C34
soll werden:
A +-- 1 +-- 2 +-- 5 +-- 6 +-- 2 +-- 1 +-- 3 +-- 3 +-- 0 B +-- 1 +-- 2 +-- 3 +-- 2 +-- 3 C +-- 3 +-- 4
Dazu muss ich nun wissen, ob ein Unterknoten ein string enthält, nur weiss ich nicht wie ich an die strings kommen soll in den nodes!
Kannst Du mir da nen Tipp geben?
-
plizer schrieb:
Kannst Du mir da nen Tipp geben?
Eine Methode in CTreeCtrl dafür gibt es nicht. Du müsstest beim hinzufügen von Knoten vorher die vorhanden durchlaufen und prüfen ob "der Neue" schon existiert. Falls nicht fügst du ihn hinzu.
-
HaJo. schrieb:
plizer schrieb:
Kannst Du mir da nen Tipp geben?
Eine Methode in CTreeCtrl dafür gibt es nicht. Du müsstest beim hinzufügen von Knoten vorher die vorhanden durchlaufen und prüfen ob "der Neue" schon existiert. Falls nicht fügst du ihn hinzu.
Genau so wollte ich das machen! Allerdings weiss ich nicht, wie ich an den string eines vorhandenen Knoten kommen kann! Ich bekomme ja immer nur an HTREEITEM dran.
-
plizer schrieb:
Genau so wollte ich das machen! Allerdings weiss ich nicht, wie ich an den string eines vorhandenen Knoten kommen kann! Ich bekomme ja immer nur an HTREEITEM dran.
Mit GetNextSiblingItem / GetPrevSiblingItem kannst du die Items durchwandern. und mit GetItemText erhälst du einen CString mit dem zugehörigen Text welchen du mit Compare vergleichen könntest.
-
HaJo. schrieb:
plizer schrieb:
Genau so wollte ich das machen! Allerdings weiss ich nicht, wie ich an den string eines vorhandenen Knoten kommen kann! Ich bekomme ja immer nur an HTREEITEM dran.
Mit GetNextSiblingItem / GetPrevSiblingItem kannst du die Items durchwandern. und mit GetItemText erhälst du einen CString mit dem zugehörigen Text welchen du mit Compare vergleichen könntest.
Danke für Deine Unterstützung!
Mit den Daten sollte ich es dann hinbekommen!
-
Ich kanns nicht glauben, dass ich nach mindestens 2 Manntage es immer noch nicht hinbekommen habe, in einem CTreeCtrl zu schauen, ob ein Unterknoten mit einem bestimmten string vorhanden ist und falls nicht, diesen einzufügen.
Ich habe mir alle interessanten MSDN Beispiele zum CTreeCtrl angeschaut und alles versucht. Aber die Beispiele entbehren sich für mich jeder Logik, so dass ich da einfach nichts hinbekomme.
Beispiel:HTREEITEM hmyItem; if (pmyTreeCtrl->ItemHasChildren(hmyItem)) { ...
hmyItem ist doch undefiniert. Wie kann ich dann anschließend einer Methode ein undefiniertes Objekt (bzw. eine Kopie) in der Parameterliste übergeben? Oder wird hmyItem ein neuer Wert zugeordnet? (Weil anschließend damit weitergearbeitet wird) Wenn das so ist, werde ich das wohl nie wirklich verinnerlichen, weil ich das für mich sehr unlogisch ist.
-
plizer schrieb:
hmyItem ist doch undefiniert. Wie kann ich dann anschließend einer Methode ein undefiniertes Objekt (bzw. eine Kopie) in der Parameterliste übergeben? Oder wird hmyItem ein neuer Wert zugeordnet? (Weil anschließend damit weitergearbeitet wird) Wenn das so ist, werde ich das wohl nie wirklich verinnerlichen, weil ich das für mich sehr unlogisch ist.:(
Der Parameter hItem müsste ein Handle auf das TreeView Item sein, bei dem du die Kinderprüfung durchführen möchtest.
-
HaJo. schrieb:
plizer schrieb:
hmyItem ist doch undefiniert. Wie kann ich dann anschließend einer Methode ein undefiniertes Objekt (bzw. eine Kopie) in der Parameterliste übergeben? Oder wird hmyItem ein neuer Wert zugeordnet? (Weil anschließend damit weitergearbeitet wird) Wenn das so ist, werde ich das wohl nie wirklich verinnerlichen, weil ich das für mich sehr unlogisch ist.:(
Der Parameter hItem müsste ein Handle auf das TreeView Item sein, bei dem du die Kinderprüfung durchführen möchtest.
Danke! Hast Du dazu vielleicht einen Link wo ich Infos dazu bekomme? Ich habe zwar schon einige gute C++ Bücher hier, aber zu handles steht da nirgend etwas.
PS: Sieben Bücher und insgesamt über 5000 Seiten und keinmal das Wort handle. Wieder einmal etwas, was ich nicht verstehe.
-
plizer schrieb:
Danke! Hast Du dazu vielleicht einen Link wo ich Infos dazu bekomme? Ich habe zwar schon einige gute C++ Bücher hier, aber zu handles steht da nirgend etwas.
Zu Handles oder wie du weiter vorgehen müsstest?
PS: Sieben Bücher und insgesamt über 5000 Seiten und keinmal das Wort handle. Wieder einmal etwas, was ich nicht verstehe.[/quote]
http://de.wikipedia.org/wiki/Handle
-
Am besten natürlich wie ich auch weiterkomme. Aber ich mags ja selbst nicht, wenn sich Leute was verkauen lassen. Also bin ich auch nicht böse wenn mir keiner hilft ;). Obwohl, lange genug sitz ich ja schon dran.
Aber was meinst Du genau mit:
Der Parameter hItem müsste ein Handle auf das TreeView Item sein, bei dem du die Kinderprüfung durchführen möchtest.
Ich will also schauen, ob im CTreeCtrl ein Eintrag vorhanden ist.
Ich lege die Items folgendermaßen an:
HTREEITEM hRoot = m_ctlTreeCtrl.InsertItem("Wurzel", TVI_ROOT); HTREEITEM h1 = m_ctlTreeCtrl.InsertItem("Unterknoten", hRoot); HTREEITEM h2 = m_ctlTreeCtrl.InsertItem("UUnterknoten".c_str(), h1); HTREEITEM h3 = m_ctlTreeCtrl.InsertItem("UUUnterknoten".c_str(), h2); HTREEITEM h4 = m_ctlTreeCtrl.InsertItem("UUUUnterknoten".c_str(), h3);
Wie kann ich nun z.B. rausfinden ob unter der "Wurzel" der Eintrag "Unterknoten" verhanden ist. Oder halt ob bei "UUUnterknoten" "UUUUnterknoten" enthalten ist.
Da ich erst später nachfrage, kenne ich in dem Moment nicht hRoot oder h1 usw., sondern muss die Information aus dem CTreeCtrl bekommen, nur wie?
-
plizer schrieb:
Da ich erst später nachfrage, kenne ich in dem Moment nicht hRoot oder h1 usw., sondern muss die Information aus dem CTreeCtrl bekommen, nur wie?
Kurze Verständnisfrage. Legst du alle Elemente erst an - auch doppelte - und prüfst "irgendwann" später oder möchtest du beim Anlegen immer gleich prüfen ob ein Knoten mit dem String X schon existiert?
-
Ich bekomme die einzelnen Strings aus einer Datenbank, die vereinfacht so aussehen:
A12 A15 A16 A21 A23 A30 B12 B13 B23 C34
Daraus soll dann der unten dargestellte Baum werden. Ich habe den String schon aufgeteilt, so dass ich 5 Variablen habe, die bis zu 5 Ebenen tief gehen. Natürlich soll er das A am Anfang z.B. nur einmal anlegen, wenn es da ist, kann er direkt den Unterpunkt einfügen, aber natürlich nur falls dieser auch noch nicht da ist usw.
Algorithmisch gesehen macht mir das keine Probleme, aber ich kann mit dem CTreeCtrl überhaupt nicht umgehen!A +-- 1 +-- 2 +-- 5 +-- 6 +-- 2 +-- 1 +-- 3 +-- 3 +-- 0 B +-- 1 +-- 2 +-- 3 +-- 2 +-- 3 C +-- 3 +-- 4
-
Hmm nun gut. Deine Datenbank scheint sortiert zu sein. Erst alle Werte mit A dann B ...
// hParentItem gibt das Elternelement an mit desses Kindelementen der Stringvergleich duchgeführt werden soll bool CMyDialog::NodeExists(const HTREEITEM &hParentItem, const CString &NodeValue) { if (this->m_TreeView.ItemHasChildren(hParentItem)) { // Erstes Kindelement HTREEITEM hItem = this->m_TreeView.GetNextItem(hParentItem, TVGN_CHILD); while(hItem != NULL) { // Text des Knotens holen CString Text = this->m_TreeView.GetItemText(hItem); // Strings vergleichen if (NodeValue.Compare(Text) == 0) return true; // Nächsten Knoten holen this->m_TreeView.GetNextItem(hItem, TVGN_NEXT); } } return false; // Keine Kinder } void CMyDialog::OnBnClickedButton1() { TVINSERTSTRUCT TvStruct; TVITEMEX &TvItemEx = TvStruct.itemex; HTREEITEM hRootItem = 0; // Wurzel Knoten Ebene 0 HTREEITEM hCharacterItem = 0; // Buchstaben Knoten (A, B, ...) Ebene 1 CString CharNode, NumNode; TvStruct.hParent = NULL; TvStruct.hInsertAfter = TVI_ROOT; TvItemEx.mask = TVIF_TEXT; TvItemEx.pszText = "Ich bin die Wurzel"; // (1) Als erstes den Wurzelknoten if ((hRootItem = this->m_TreeView.InsertItem(&TvStruct)) == NULL) { // Fehler } TvStruct.hParent = hRootItem; TvStruct.hInsertAfter = TVI_LAST; // (2) Die Buchstabenknoten hinzufügen vorher prüfen ob Knoten schon existiert if (!NodeExists(hRootItem, CharNode)) { TvItemEx.pszText = CharNode.GetBuffer(); // Hier die Buchstaben angeben if ((hCharacterItem = this->m_TreeView.InsertItem(&TvStruct)) == NULL) { // Fehler } // (3) Hier di Zahlenknoten hinzufügen und auch vorher prüfen if (!NodeExists(hCharacterItem, NumNode)) { TvStruct.hParent = hCharacterItem; TvItemEx.pszText = NumNode.GetBuffer(); // Hier die Zahlen angeben if (this->m_TreeView.InsertItem(&TvStruct) == NULL) { // Fehler } } } }
So in etwa sollte es gehen. Die Schritte 2/3 sollten natürlich in eine Schleife. Der Code ist ohne Gewähr und ich habe ihn nicht getestet.
-
@HaJo.: Vielen, vielen Dank!
Da hab ich ja schon ein schlechtes Gewissen, dass Du das so mal eben für mich gemacht hast!
Ich werde versuchen es sofort zu implementieren.
Nochmals vielen Dank!
Schöne Grüße,
plizer
-
HaJo. schrieb:
plizer schrieb:
Ich hatte einfach nicht gemerkt, dass ein Baum aufgebaut wurde. Als nächsten muss ich jetzt mal schauen, wie das mit den Bildern geht. Danke für Deine Hilfe!
Das ist auch kein Problem. Du weist dem TreeView eine ImageList mit SetImageList zu. Füllst diese mit Bildern.
Beim hinzufügen von TreeView Items muss du dann das Flag TVIF_IMAGE in der Itemstruktur setzen (mask Member) und weist dem iImage Member den Index des Bildes in der ImageList zu.
Ich bin nun dabei die Plus- und Minuszeichen in dem Baum darzustellen. Wie wird dies in MFC gemacht mit dem Flag?
Was ich auch noch nicht verstehe, weil ich wohl immer noch nur in Objekten denke (HTREEITEM ist ja kein Objekt und kann es einfach nicht bei mir im Hirn zuordnen):
Wie komme ich denn an das erste Element im Baum? Ich hab die MSDN für CTreeCtrl vorliegen und finde Methoden wie SelectItem(), GetParentItem(), aber diese brauchen ja alle schon HTREEITEM, aber da will ich ja drankommen! Also wo ist mein Denkfehler?
Warum wird es denn nicht z.B. so gelöst, wenn ich den Text des ersten Unterknoten des ersten Element haben will (Methoden erfunden)?
String text = tree.getItem(0).getItem(0).getText();
Das wäre doch soviel einfacher, oder denk ich das nur?
Ich brauch bei Java praktisch keine Hilfe mehr, weil die Klassen- und Methodennamen und der immer gleiche Aufbau alles an Informationen geben, was ich brauche. Aber wahrscheinlich gehts euch C++-lern genauso...
-
War vielleicht jetzt ein blödes Beispiel, weils so in Java auch nicht aussehen würde, aber vielleicht weiss jemand, wie ich das meine!
-
plizer schrieb:
Ich bin nun dabei die Plus- und Minuszeichen in dem Baum darzustellen. Wie wird dies in MFC gemacht mit dem Flag?
Der Schalter heißt TVS_HASLINES. Falls du das Steuerelement im Resource Editor hinzufügst, kannst du es auch manuelle über die Eigenschaften setzen.
plizer schrieb:
Was ich auch noch nicht verstehe, weil ich wohl immer noch nur in Objekten denke (HTREEITEM ist ja kein Objekt und kann es einfach nicht bei mir im Hirn zuordnen):
Ein HTREEITEM ist ein Handle - also so etwas wie ein eindeutiger Indetifizierer - für ein Objekt. Mit Objekt ist unter Windows nicht immer ein Objekt wie eine Klasse gemeint. Ein HWND ist auch ein Handle für ein bst. Fenster.
plizer schrieb:
Wie komme ich denn an das erste Element im Baum? Ich hab die MSDN für CTreeCtrl vorliegen und finde Methoden wie SelectItem(), GetParentItem(), aber diese brauchen ja alle schon HTREEITEM, aber da will ich ja drankommen! Also wo ist mein Denkfehler?
Das erste Element ist *immer* das Wurzelelement. Wie bei einem Baum in der "echten" Welt auch. Also holst du dir erst einmal das Handle dafür mit GetRootItem. Ab hier müsstest du durch deinen Baum navigieren.
plizer schrieb:
Warum wird es denn nicht z.B. so gelöst, wenn ich den Text des ersten Unterknoten des ersten Element haben will (Methoden erfunden)?
String text = tree.getItem(0).getItem(0).getText();
Das wäre doch soviel einfacher, oder denk ich das nur?Das hat windowsevolutionsspezifische Gründe und eben dann auch MFC Entiwicklungsgründe. Die MFC sind bei weitem nicht perfekt erleichtern dem Entwickler aber ungemein die Arbeit unter Windows. Sicherlich hätte man vieles einfacher/besser machen können. Aber die Entwickler werden sich schon etwas dabei gedacht haben. Genaueres kann ich dir dazu leider nicht sagen.
plizer schrieb:
Aber wahrscheinlich gehts euch C++-lern genauso...
Ja. Die MFC sind ein guter Weg das Windows API in Objekten/Klassen zu kapseln. Dieser Weg hätte von mir aus aber auch konsequenter und an einigen Stellen etwas einfacher für den Endentwickler desinged werden können. Aber wie gesagt, die MFC Schöpfer werden sich bestimmt jede Menge Gedanken gemacht haben.