TTreeView: Aufbau bei Start des Programms (Eigene Datenstruktur für Knoten)



  • Hallo,

    ich habe folgendes Problem. Beim Starten des Programms soll eine TTreeView-Objekt gefüllt werden. Der Inhalt aus und die Texte zu den einzelnen Knoten sind in einer Datenstruktur hinterlegt. Sie sollten der Eigenschaft "Data (void*)" zugeordente werden.
    Durch eine rekursive Funktion werden die Knoten in die Baumstruktur eingeordnet.
    Ich nutze CodeGear RAD Studio C++ Builder 2007 Pro.

    Hier erstmal der Quelltext:

    // Methode dient zur Befüllung der Baumstruktur
    // Die Methode fügt den ersten Eintrag ein und ruft eine weitere Funktion
    // zum eintragen weiterer Unterknoten ein.
    void __fastcall TForm_Main::FillTopicTree(TTreeView* pTreeView)
    {
    /*
    Übergabewerte:
    --------------
    TTreeView *pTreeView			    -	Zeiger auf das TTreeView-Objekt, dass befüllt
    										werden soll
    
    Funktionsvariablen:
    --------------------
    const PARAMETER_TREE *pMenu			-	Zeiger auf Datenstruktur
    TTreeNode 			 *pChildNode	-  	Zeiger auf Knoteneintrag
    
    Rückgabe:
    ---------
    void
    */
    
    	// Funktionvariablen / Objekte
    	const PARAMETER_TREE 	*pMenu;
    	TTreeNode 				*pChildNode;
    
    	// Zeiger auf den Parameterbaum erzeugen
    	pMenu = TopicTree0;
    
    	// Alle Elemente des TreeView-Objekts löschen
    	pTreeView->Items->Clear();
    	// Erster Eintrag in Baumstruktur wird angelegt.
    	pTreeView->Items->Add(NULL, pMenu->ccNodeText);
    	pTreeView->Items->Item[pTreeView->Items->Count - 1]->Data  = (void*)pMenu;
    
    	// Alle Unterknoten werden rekursiv in die Baumstruktur eingetragen.
    	pChildNode = pTreeView->Items->Item[pTreeView->Items->Count -1];
    
    	AnsiString temp = pTreeView->Items->Item[pTreeView->Items->Count -1]->Text;
    	AddChildNode(pTreeView, pMenu, pChildNode);
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm_Main::AddChildNode(TTreeView*  pTreeView,
    	const PARAMETER_TREE* pMenu, TTreeNode* pChildNode)
    {
    	// Nächster Eintrag
    	pMenu++;
    
    	// Einfügen des Knotens bis in der Datenstruktur der Text == \0
    	while((AnsiString)pMenu->ccNodeText != "\0")
    	{
    		// Name des Unterknotens eintragen (Nächster Knoten)
    		pTreeView->Items->AddChild(pChildNode, pMenu->ccNodeText);
    		// Zeiger auf Datenstruktur
    		pChildNode->Item[pChildNode->Count -1]->Data = (void*)pMenu;
    
    		// Sollte der Knoten einen Unterknoten enthalten wird dieser durch den
    		// rekursiven Aufruf der Methode eingefügt
    		if (pMenu->iMenuId == NODE_MENU)
    		{
    			// Aufruf der Methode zum Einfügen des Knotens
    			AddChildNode(pTreeView, (PARAMETER_TREE*)pMenu->Data,
    				pChildNode->Item[pChildNode->Count -1]);
    		}
    		pMenu++;
    	} 
    }
    //---------------------------------------------------------------------------
    

    Wie zu erkennen ist, beinhaltet pMenu die folgenden Datenstrukturen:

    //---------------------------------------------------------------------------
    
    // Strucktur für einen Menueintrag im TTreeView-Objekt
    typedef struct
    {
    	const char 		*ccNodeText;  	// AnsiString Knotentext (Menütext)
    	int			 	iMenuId;	  	// Integervariable für die Identifizierung
    									// des Menüfesnters.
    	int 			iParameters[];	// Parameternummer, die mit dem Eintrag
    									// abgedeckt werden.
    	int 			iHelpIndex;		// Variable zur Identifizierng des
    									// Hilfeeintrags in der Hilfedatei.
    	int 			iIconIndex;		// Integervariable zur identifizierung
    									// des Icons an der Stelle
    	float			fMin;  			// Minimalwert
    	float			fMax;			// Maximalwert
    	//int				iNodeIndex;		// Variable ist Identifizierend für den
    									// Knoten.
    									// iNodeIndex = 0 wird nicht berücksichtigt
    									// iNodeIndex > 0 Eintrag im mit Parameter
    	void			*Data;			// void-Zeiger auf Datenstruktur
    } PARAMETER_TREE;
    //---------------------------------------------------------------------------
    
    // Eintiegsknoten wir für andere Module bereitgestellt
    extern const PARAMETER_TREE TopicTree0[];
    //---------------------------------------------------------------------------
    

    Headerdatei

    //---------------------------------------------------------------------------
    // Einstiegsknoten des TreeView-Objekts
    const PARAMETER_TREE TopicTree1[] =
    {
    
    	{"Datensatz",NODE_NOTAVAIL},
    	{"Dataset_Information", NODE_NOTAVAIL, {0}, 0, 0, 0, 0, 0},
    	{"\0", NODE_NOTAVAIL}
    };
    
    //---------------------------------------------------------------------------
    // Einstiegsknoten des TreeView-Objekts
    const PARAMETER_TREE TopicTree0[] =
    {
    	{"Dataset", NODE_NOTAVAIL},
    	{"Basic_Configuration" , NODE_MENU, {0}, 0, 0, 0, 0, (void*)TopicTree1},
    	{"\0", NODE_NOTAVAIL}
    };
    

    cpp-Datei

    Mein Problem ist nun Folgendes.
    Bei dem ersten rekursiven aufruf der Methode "AddChildNode" sollte die Datenstruktur "TopicTree1" zur Verfügung stehen. Allerdings ist mir aufgefallen, dass stattdessen nur NULL für die Datenstruktur zur verfügung steht (Alle Elemente der Datenstruktur sind leer bzw. NULL).
    Ich benötige aber den Eintrag um einen Unterknoten anzulegen.
    Ich bitte um Hilfe. Bitte erklärt mir meinen Fehler. Wie kann ich dieses Problem umgehen? Die Methode mit der Datenstruktur muss bleiben, da jeder Knoten eigene Eigenschaften für einen Wertebereich besitzt.

    Bin für jede hilfe dankbar.

    (Bitte keine Antworten mit nur zwei Wörtern hinterlassen) 😉



  • Gibt es einen Grund, nicht TTreeNode::Data zu verwenden, um die Daten an den Knoten zu hängen?

    Außerdem gibt Dir TTreeNodes::Add() den Zeiger auf den erzeugten TTreeNode zurück. Ein Suchen über den ItemIndex ist nicht notwendig.



  • Hallo

    Warum hast du hier einen zweiten Thread zum selben Thema aufgemacht? Wenn du diese Frage hier präzisieren wolltest dann hättest du das doch auch hier machen können.

    Zum Thema : Ich vermute mal das du einfach einen Grund gefunden hast keine globalen Variablen zu verwenden. Denn niemand garantiert dir die Reihenfolge der Initialisierung der globalen Variablen. Globale Variablen die aufeinander aufbauen sind also potentiel undefiniert.

    bis bald
    akari



  • Ich danke euch Beiden.
    Ich habe das Problem gefunden.
    1. Die Initialisierung der globalen Variablen ergibt sich in meinem Programm zumindest teilweise.
    2. Das Problem lag in der Initialisierung des Arrays.
    3. Der zweite Thread tut mir leid. Mache es nächstes Mal nicht wieder.
    4. Danke für die Antworten.



  • ´ne Beschreibung der Lösung wäre nicht schlecht, damit die Nachwelt weiss, wie man´s macht.

    Gruss,
    Doc



  • PS:

    Globale Variablen sind böse. Oft können globale Variablen irgendwie zu einer Klasse zusammengefasst werden. Wenn diese Klasse dann als Singleton implementiert wird hast du 1) keine globalen Variablen mehr und 2) immer einen initialisierten Ausgangszustand. Bisher habe ich nichts programmiert, das man mit diesem Ansatz nicht abdecken konnte.

    Gruss,
    Doc


Anmelden zum Antworten