Auf Parent der CheckBox zugreifen



  • Hallo,

    ich möchte auf das Parent(Panel) eines Objects ,hier CheckBox, zugreifen und
    dessen Caption lesen.
    Wie stell ich so was an?

    (((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Parent->? == "Reserved")

    ((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->(TPanel*)Parent->Caption == "Reserved")
    geht ebenfalls nicht.



  • Hallo

    da ist immer erstmal günstiger, Schritt für Schritt durchzugehen (soweit ich den Sinn verstanden habe).
    Und vor allem C++ Casts zu verwenden

    TCheckBox* checkbox = static_cast<TCheckBox*>(AlarmCheck->Items[Cb+(Index*5)]); // was ist AlarmCheck? Was gibt Items zurück? cast vielleicht unnötig
    TPanel* panel = static_cast<TPanel*>(checkbox->Parent);
    panel->Caption = "Reserved";
    

    Zusammensetzen kannst du es nun selber, aber ich denke das es zu unübersichtlich wird.
    Übrigens ist == kein Operator zum Lesen eines Wertes.

    bis bald
    akari



  • Hallo

    ich glaube, ich habe das ganze etwas aus dem Zusammenhang geriessen.

    Ich erzeuge mir dynamisch eine GroupBox und in der Box Panels auf denen
    immer 5 CheckBoxen instanziert werden.

    Dieses passiert in der Funktion
    DrawAlarmList(AnsiString BoxName, unsigned char Mask,const char * List)
    hier ist BoxName der Name der GroupBox.
    List beinhaltete die Captions der einzelnen Panels.
    Mask gibt an welche der 5 CheckBoxenauf dem Panel Enabled sein sollen.
    Die CheckBoxen sollen ebenfalls nicht enabled sein wenn das Caption des
    Panels auf dem sie sich befinden "Reserved" ist.Bei der Abfrage gibt es eine
    Fehler Meldung.

    if( !((1<<Cb)&Mask)
                || ( ((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->(TPanel*)Parent->Caption == "Reserved") )
                {
                    ((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Enabled          = false;
                }
    

    Das ganze sieht dann so aus.

    //------------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------------
    void __fastcall TRelayData::FormCreate(TObject *Sender)
    {
    	const char SupplyAlarmList[] =
         {
    		"AC MAINS L1 FAIL            ""\0"
    		"AC MAINS L2 FAIL            ""\0"
    		"AC MAINS L3 FAIL            ""\0"
    		"DC OVERVOLTAGE              ""\0"
    		"DC UNDERVOLTAGE             ""\0"
    		"POWER LIMIT                 ""\0"
    		"MODULE OVERTEMP             ""\0"
    		"MODUL1 FAIL                 ""\0"
    		"MODUL2 FAIL                 ""\0"
    		"MODUL3 FAIL                 ""\0"
    		"MODUL4 FAIL                 ""\0"
    		"ALARM1                      ""\0"
    		"ALARM2                      ""\0"
    		"ALARM3                      ""\0"
    		"ALARM4                      ""\0"
    		"ALARM5                      ""\0"
    		"ALARM6                      ""\0"
    		"ALARM7                      ""\0"
    		"ALARM8                      ""\0""\0"
         };
    	const char UltraCapList[] =
         {
    		"OVERTEMP	                   ""\0"
    		"SYMMETRIE ERROR             ""\0"
    		"Reserved                    ""\0""\0"
         };
    	const char InverterList[] =
         {
    		"Reserved                    ""\0"
    		"Reserved                    ""\0"
    		"Reserved                    ""\0"
    		"Reserved                    ""\0"
        		"Reserved               	    ""\0""\0"
         };
    	const char Hallo[] =
         {
    		"bbbbbbbbbb                  ""\0"
    		"aaaaaaa                     ""\0"
        		"RESERVE                	    ""\0""\0"
         };
         DrawAlarmList("Supply",0x13,SupplyAlarmList);
         DrawAlarmList("EnergieBlock",0x13,UltraCapList);
         DrawAlarmList("Reserve",0x13,InverterList);
    	((TPanel*)Alarme->Items[0])->Color = clYellow;
    }
    //------------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------------
    void TRelayData::DrawAlarmList(AnsiString BoxName, unsigned char Mask,const char * List)
    {
    	#define BOX_WIDTH 		740
         #define PANEL_TOP 		20
         #define PANEL_LEFT 		10
         #define PANEL_HEIGHT 	20
         #define PANEL_WIDTH      700
         #define CHECK_BOX_LEFT   500
         #define CHECK_BOX_STEP   30
         #define ENABLE 0x1f
    	static int LastTopPos = 21;
         static int LastIndex  = 0;
         //Bei der ersten AlarmBox "AlarmPanel sowie CheckBox" - Listen instanzieren
         if(LastIndex == 0)
         {
    		Alarme 		     = new TList;
    		AlarmCheck 		= new TList;
        		Alarme->Count 		= 500;
    	    	AlarmCheck->Count 	= 500;
    	}
    	ListLenght 		= 0;
         while(List[ListLenght*29] != 0)ListLenght++;;
         //Neu Box erzeugen
    	AlarmBox 			= new TGroupBox((TComponent*)this);
        	AlarmBox->Parent	= Gesamt;
        	AlarmBox->Caption 	= BoxName;
        	AlarmBox->Width 	= BOX_WIDTH;
         AlarmBox->Height 	= ((ListLenght+1)*PANEL_HEIGHT)+10;
         AlarmBox->Left 	= 10;
         AlarmBox->Top 		= LastTopPos;
         LastTopPos	    	+= AlarmBox->Height+1;
         AlarmBox->Visible 	= true;
         //--------------------------------------------
    	TextIndex = 0;
         for(int Index = LastIndex; Index < (ListLenght+LastIndex); Index++)
         {
         	//Panels erzeugen
         	Alarme->Items[Index] 					= new TPanel((TComponent*)this);
         	((TPanel*)Alarme->Items[Index])->Parent 	= AlarmBox;
         	((TPanel*)Alarme->Items[Index])->Alignment 	= taLeftJustify;
         	((TPanel*)Alarme->Items[Index])->Height  	= PANEL_HEIGHT;
         	((TPanel*)Alarme->Items[Index])->Width   	= PANEL_WIDTH;
         	((TPanel*)Alarme->Items[Index])->Top     	= PANEL_TOP+(TextIndex*20);
         	((TPanel*)Alarme->Items[Index])->Left	  	= PANEL_LEFT;
         	((TPanel*)Alarme->Items[Index])->Caption 	= AnsiString().sprintf(" %3d",Index)+"  "+ (List+(TextIndex*29));   //
              ((TPanel*)Alarme->Items[Index])->OnMouseMove = MouseOnPanel;
              ((TPanel*)Alarme->Items[Index])->DoubleBuffered = true;
         	((TPanel*)Alarme->Items[Index])->Visible 	= true;
              //CheckBoxen erzeugen
              for(int Cb = 0; Cb <= 4; Cb++)
              {
              	AlarmCheck->Items[Cb+(Index*5)] = new TCheckBox((TComponent*)this);
    		   	((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->OnClick 			= CheckBoxClick;
    		   	((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->OnMouseMove		  	= MouseOnPanel;
     	     	((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Parent 				= ((TPanel*)Alarme->Items[Index]);
    		 	((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Top				= 1;
                   ((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Left   				= CHECK_BOX_LEFT+(Cb*CHECK_BOX_STEP);
    			((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Width 				= 15;
    //Zeiger auf Ram Array sowie die Maske
    			((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Tag          		= (Index<<16)|1<<Cb;
    			if( !((1<<Cb)&Mask)
    			|| ( ((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->(TPanel*)Parent->Caption == "Reserved") )
    			{
    				((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Enabled      	= false;
    			}
    			((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->DoubleBuffered		= true;
    			((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Visible				= true;
              }
              TextIndex++;
    	}
    	LastIndex += ListLenght;
         AllAlerts	= LastIndex;
    }
    

    Das ganze etwas vereinfacht.

    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
    	TPanel *Panel  = new TPanel((TComponent*)this);
    	Panel->Parent  = this;
    	Panel->Caption = "Reserved";
    	TCheckBox *CheckBox = new TCheckBox((TComponent*)this);
    	CheckBox->Parent	= Panel;
         if(CheckBox->(TPanel*)Parent->Caption == "Reserved")
    	    	CheckBox->Enabled = true;
    }
    

    Hier kommt eine Fehlermeldung "Elemente Bezeichner erwartet".



  • Hallo,

    Du hast scheinbar das Prinzip des Castens noch nicht richtig verstanden.
    Mit

    (TComponent*)TestKomponente
    

    wandelst du einen den die Variable TestKomponente in eine Variable vom Typ Zeiger auf TComponent um. Das geschieht hier ohne Typprüfung (da C-Style Cast).
    1. Verwende C++-Style Casts (static_cast, dynamic_cast) statt deinen C-Style
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-39493.html
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-39463.html
    2. Caste nur wenn es nötig ist.

    TPanel *Panel  = new TPanel((TComponent*)this);
    

    Warum castest du hier this in TComponent?
    3. Wenn du die zu castende Variable mehrfach benötigst erzeuge dir eine temporäre Variable und verwende dann diese
    Bsp. statt

    ((TPanel*)Alarme->Items[Index])->Parent     = AlarmBox;
    ((TPanel*)Alarme->Items[Index])->Alignment     = taLeftJustify;
    ((TPanel*)Alarme->Items[Index])->Height      = PANEL_HEIGHT;
    ((TPanel*)Alarme->Items[Index])->Width       = PANEL_WIDTH;
    ((TPanel*)Alarme->Items[Index])->Top         = PANEL_TOP+(TextIndex*20);
    ((TPanel*)Alarme->Items[Index])->Left          = PANEL_LEFT;
    

    lieber

    TPanel* panel = dynamic_cast<TPanel*>(Alarme->Items[Index]);
    if( panel )
    {
       panel->Parent     = AlarmBox;
       panel->Alignment     = taLeftJustify;
       panel->Height      = PANEL_HEIGHT;
       panel->Width       = PANEL_WIDTH;
       panel->Top         = PANEL_TOP+(TextIndex*20);
       panel->Left          = PANEL_LEFT;
    // usw.
    

    4. Was soll das hier

    if(CheckBox->(TPanel*)Parent->Caption == "Reserved")
         CheckBox->Enabled = true;
    

    Das Cast ist hier falsch positioniert

    TPanel* panel = dynamic_cast<TPanel*>(CheckBox->Parent);
    if(panel && panel->Caption == "Reserved")
             CheckBox->Enabled = true;
    

    oder hier besser gleich

    if(Panel->Caption == "Reserved")
         CheckBox->Enabled = true;
    

    Belies dich bitt auch ein wenig bezüglich Polymorphie
    http://www.tutorialpage.de/Cpp2/index.php?ziel=http://www.tutorialpage.de/Cpp2/chap5.php
    http://www.volkard.de/vcppkold/polymorphie.html



  • Danke für die Hilfe, werde mich näher damit beschäftigen.

    Du hast scheinbar das Prinzip des Castens noch nicht richtig verstanden.

    Ich denke schon

    unsigned char Buffer[2];
    unsigned short Test = (unsigned short)((Buffer[1]<<8)&0xff00) | (unsigned short)(Buffer[0] & 0xff);

    Ich Caste hier für diese Operation Buffer auf unsigned short.

    TPanel *Panel = new TPanel((TComponent*)this);
    Warum castest du hier this in TComponent?

    Du hast recht, ich habe das ganze gerade probiert
    TPanel *Panel = new TPanel(this);
    irgendwie ist der Cast da reingewandert, weil die Fehlermeldung
    Mehrdeutigkeit zwischen ...... kam, kann das ganze aber nicht mehr nachvollziehen
    da der Fehler nun nicht mehr auftritt.
    Irgenwie habe ich bei dem Object 3 Konstruktoren zur Auswahl unter anderem
    einen mit dem Übergabeparameter TComponent *Owner, deswegen habe ich gecastet und der Fehler kam nicht mehr.

    Zum dynamic_cast, hier caste ich den Pointer Sender dynamisch ist Sender nicht
    vom Datentyp TPanel wird ein NULL Pointer zurückgegeben.

    void _fastcall TRelayData::MouseOnPanel(TObject *Sender, TShiftState Shift,
          int X, int Y)
    {
    	TPanel *Panel = dynamic_cast<TPanel*>(Sender);
         if(!Panel)
         {
             //Wenn nicht Panel dann war der Auslöser ein Object das das 
             //Panel als Parent hat. 
             Panel = dynamic_cast<TPanel*>(((TControl*)Sender)->Parent);
         }
    

    Wie gesagt, ich kann mir immer noch nicht erklären wie Oben der Fehler
    Mehrdeutigkeit zwischen ...... kam.

    Das Cast ist hier falsch positioniert

    TPanel* panel = dynamic_cast<TPanel*>(CheckBox->Parent);
    if(panel && panel->Caption == "Reserved")
             CheckBox->Enabled = true;	
    
    TPanel* panel = dynamic_cast<TPanel*>(CheckBox->Parent);
    if(panel && panel->Caption == "Reserved")
    CheckBox->Enabled = true;	
    
    TPanel* panel = dynamic_cast<TPanel*>(CheckBox->Parent);
    if(panel && panel->Caption == "Reserved")
             CheckBox->Enabled = true;	
    
    oder hier besser gleich
    
    if(Panel->Caption == "Reserved")
         CheckBox->Enabled = true;	
    
    if(Panel->Caption == "Reserved")
    CheckBox->Enabled = true;	
    
    if(Panel->Caption == "Reserved")
         CheckBox->Enabled = true;
    

    Ok sieht gut aus. Meine Idee war CheckBox->Parent, hier ist Parent ja ein Objectzeiger auf das Parent(Panel) von CheckBox, über diesen Zeiger kann ich dann
    doch gecastet auf den Datentypen TPanel* auf dessen Caption zugreifen oder.
    Ist das nicht analog zu Panel->Caption?

    3. Wenn du die zu castende Variable mehrfach benötigst erzeuge dir eine temporäre Variable und verwende dann diese
    Bsp. statt

    ((TPanel*)Alarme->Items[Index])->Parent     = AlarmBox;
    ((TPanel*)Alarme->Items[Index])->Alignment     = taLeftJustify;
    ((TPanel*)Alarme->Items[Index])->Height      = PANEL_HEIGHT;
    ((TPanel*)Alarme->Items[Index])->Width       = PANEL_WIDTH;
    ((TPanel*)Alarme->Items[Index])->Top         = PANEL_TOP+(TextIndex*20);
    ((TPanel*)Alarme->Items[Index])->Left          = PANEL_LEFT; 	
    
    lieber
    
    	TPanel* panel = dynamic_cast<TPanel*>(Alarme->Items[Index]);
    if( panel )
    {
       panel->Parent     = AlarmBox;
       panel->Alignment     = taLeftJustify;
       panel->Height      = PANEL_HEIGHT;
       panel->Width       = PANEL_WIDTH;
       panel->Top         = PANEL_TOP+(TextIndex*20);
       panel->Left          = PANEL_LEFT;
    // usw.
    

    Finde ich auch besser so und vor allem sicherer durch den dynamic_cast, obwohl
    sich in der Liste ausschließlich Pointer vom Datentyp TPanel* befinden.

    Belies dich bitt auch ein wenig bezüglich Polymorphie

    Oh je das Wort hört sich schon kompliziert an, werde mal sehen.

    Ach das ist die Sache mit der virtuellen Funktion, diese Funktion kann
    in einer von der BasisKlasse abgeleiteten Klasse überschrieben werden.
    Passiert dies nicht wird die Funktion der BasisKlasse ausgeführt.

    Was hat das mit den Sachen weiter Oben zu tun?

    An die C++ Style Casts muss ich mich gewönnen, da ich sehr viel C
    Programmiere ist man schnell dabei diese C Style Casts auch unter C++
    zu verwenden. Werde mich diesbezüglich etwas am "Riemen reissen" und
    C++ style Casts verwenden.

    Danke für die Lehreiche Hilfe.



  • Wenn du dir sicher bist, dass du den Typ des Objektes in Sender genau kennst, kannst du auch statt dynamic_cast einen static_cast verwenden und die Prüfung auf 0 weglassen. Falls es aber nicht stimmt, bekommst du interessante Fehlermeldungen. 🙂



  • Braunstein schrieb:

    Wenn du dir sicher bist, dass du den Typ des Objektes in Sender genau kennst, kannst du auch statt dynamic_cast einen static_cast verwenden und die Prüfung auf 0 weglassen. Falls es aber nicht stimmt, bekommst du interessante Fehlermeldungen. 🙂

    Ich denke mal es kommt im schlimmsten Fall eine Speicherzugriffsverletzung.

    Ich würde das ganze etwas anders Formulieren, in deinem Kommentar sieht es so aus
    als ob bei beiden Cast Arten im Fehler Fall ein NULL Pointer zurückgegeben
    wird "kannst du auch statt dynamic_cast einen static_cast verwenden und die Prüfung auf 0 weglassen."
    Natürlich kommt im beim static_cast im Fehlerfall kein NULL Pointer zurück.

    . Wenn du die zu castende Variable mehrfach benötigst erzeuge dir eine temporäre Variable und verwende dann diese
    Bsp. statt

    ((TPanel*)Alarme->Items[Index])->Parent     = AlarmBox;
    ((TPanel*)Alarme->Items[Index])->Alignment     = taLeftJustify;
    ((TPanel*)Alarme->Items[Index])->Height      = PANEL_HEIGHT;
    ((TPanel*)Alarme->Items[Index])->Width       = PANEL_WIDTH;
    ((TPanel*)Alarme->Items[Index])->Top         = PANEL_TOP+(TextIndex*20);
    ((TPanel*)Alarme->Items[Index])->Left          = PANEL_LEFT;    
    
    lieber
    
        TPanel* panel = dynamic_cast<TPanel*>(Alarme->Items[Index]);
    if( panel )
    {
       panel->Parent     = AlarmBox;
       panel->Alignment     = taLeftJustify;
       panel->Height      = PANEL_HEIGHT;
       panel->Width       = PANEL_WIDTH;
       panel->Top         = PANEL_TOP+(TextIndex*20);
       panel->Left          = PANEL_LEFT;
    // usw.
    

    Warum denn.

    Alarme->Items[Index] 					= new TPanel(this);
    	    	((TPanel*)Alarme->Items[Index])->Parent 	= AlarmBox;
         	((TPanel*)Alarme->Items[Index])->Alignment 	= taLeftJustify;
         	((TPanel*)Alarme->Items[Index])->Height  	= PANEL_HEIGHT;
         	((TPanel*)Alarme->Items[Index])->Width   	= PANEL_WIDTH;
         	((TPanel*)Alarme->Items[Index])->Top     	= PANEL_TOP+(TextIndex*PANEL_HEIGHT);
         	((TPanel*)Alarme->Items[Index])->Left	  	= PANEL_LEFT;
         	((TPanel*)Alarme->Items[Index])->Caption 	= AnsiString().sprintf(" %3d",Index)+"  "+ (List+(TextIndex*29));   //
              ((TPanel*)Alarme->Items[Index])->OnMouseMove = MouseOnPanel;
              ((TPanel*)Alarme->Items[Index])->DoubleBuffered = true;
         	((TPanel*)Alarme->Items[Index])->Visible 	= true;
    

    Hier Instanziere ich mir ein Panel Object und schreibe es gleich in das
    List Object, nun greife ich mit einem C Style Cast auf den in der Liste
    instanzierten Pointer des Panels zu. Ist doch OK so.

    ((TPanel*)Alarme->Items[Index])->Parent     = AlarmBox;
    

    Warum sollte ich hier nicht einen C Style Cast nehmen, ist doch kein Unterschied
    zum static_cast in beiden Fällen wird der Pointer Typ nicht überprüft.

    Zu meinem anfänglichem Problem, das habe ich nun so gelöst.

    if( NULL != (TmpPanel = dynamic_cast<TPanel*>(((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Parent)) )
                   	PanelCaption = TmpPanel->Caption.SubString(7,8);
    			if( !((1<<Cb)&Mask) || (PanelCaption == "Reserved") )
    			{
    				((TCheckBox*)AlarmCheck->Items[Cb+(Index*5)])->Enabled      	= false;
    			}
    

Anmelden zum Antworten