Komponentenmanipulation über Index



  • Hallo

    Versteht mich bitte nicht falsch in meiner Unwissenheit - also: Wenn ComponentIndex nicht manipuliert werden darf, wäre er doch für uns Nutzer nicht manipulierbar (read only)!? Bei anderen Eigenschaften ist es doch auch so... Im Zitat aus der Hilfe steht nicht, dass ComponentIndex nicht manipuliert werden sollte.

    Das stimmt grundsätzlich.

    Wenn ich selbst Indizes zuweise, was soll passieren, außer dass ich sie kenne? Ich stelle mir das so vor: BCB schaut nach den Komponenten und bereits vergebenen Indizies (ich habe sie gleich im Aufruf der Main-Form manipuliert) und vergibt dann an die verbleibenden Komponenten ohne Index freie Indizes. Was soll da schief gehen?

    Leider ist nicht klar ob es wirklich so ist. Es könnte genauso gut sein das du durch das Setzen des ComponentIndex intern die Verwaltungsstruktur durcheinander bringst, mit Auswirkungen die vielleicht erst unter gewissen Umständen sich bemerkbar machen.
    /Edit : Und natürlich Braunsteins Einwand : Mit dem setzen von ComponentIndex kannst du maximal eine Reihe festmachen. Wenn du aber zwei oder mehr verschiedene Sammlungen von Arrays willst, wirst du dir dann selber die Indexe verschieben.

    Tja, und was "iterative Zuweisungsprozeduren" sind, müsste ich mich erstmal schlau machen...

    Ein Schleife die für alle Komponenten eine bestimmte Methode aufruft.

    bis bald
    akari



  • So, das Zuweisen von Indizes habe ich jetzt rausgenommen - ihr habt mich überzeugt, dass die Folgen in ihrer Gesamtheit schlecht überschaubar sind (erst recht für mich als Anfänger).

    ich schrieb:

    Tja, und was "iterative Zuweisungsprozeduren" sind, müsste ich mich erstmal schlau machen...

    akari schrieb:

    Eine Schleife die für alle Komponenten eine bestimmte Methode aufruft.

    Danke. Super, sowas mache ich ja schon... Ich habe mir somit die Hände gewaschen und hinterher gelernt, dass es "Hygene" heißt 🙂

    Hier jetzt mal meine, inzwischen fertiggestellte, Ereignisbehandlungsmethode /~routine:

    void __fastcall TForm4::CheckBoxClick(TObject *Sender)
    {
    	unsigned short j= dynamic_cast<TCheckBox*>(Sender)->Tag;
    	unsigned short k;
    
    	for(k=0; k < (Form4->ComponentCount-1); )
    	{
    		if((this->Components[k]->ClassNameIs("TEdit")) && (dynamic_cast<TEdit*>(this->Components[k])->Tag==j))
    		{
    			TEdit *VirtualEdit= dynamic_cast<TEdit*>(this->Components[k]);
    
    			if(!VirtualEdit->Enabled)
    				VirtualEdit->Enabled= true;
    			else
    			{
    				VirtualEdit->Enabled= false;
    				VirtualEdit->Text= "0";
    			}
    			k= Form4->ComponentCount - 1;	// Schleifenabbruch herbeiführen
    		}
            else	k++;
    	}
    }
    

    Ist doch im Prinzip auch eine iterative Zuweisungsoperation?

    Dazu noch eine Frage: Ist diese Version besser oder schlechter als die Obige?:

    void __fastcall TForm4::CheckBoxClick(TObject *Sender)
    {
    	unsigned short j= dynamic_cast<TCheckBox*>(Sender)->Tag;
    	unsigned short k;
    
    	for(k=0; k < (Form4->ComponentCount-1); )
    	{
    		if((this->Components[k]->ClassNameIs("TEdit")) && (dynamic_cast<TEdit*>(this->Components[k])->Tag==j))
    		{
    			if(!dynamic_cast<TEdit*>(this->Components[k])->Enabled)
    				dynamic_cast<TEdit*>(this->Components[k])->Enabled= true;
    			else
    			{
    				dynamic_cast<TEdit*>(this->Components[k])->Enabled= false;
    				dynamic_cast<TEdit*>(this->Components[k])->Text= "0";
    			}
    			k= Form4->ComponentCount - 1;	// Schleifenabbruch herbeiführen
    		}
            else	k++;
    	}
    }
    

    Und wenn, warum ist die Eine besser als die Andere?



  • Hallo

    dynamic_cast ist immer eine Laufzeit-Überprüfung. Damit sollte man es so wenig wie möglich aufrufen. Und wenn du dynamic_cast einsetzt, brauchst du auch kein ClassName mehr Also ungefähr so

    void __fastcall TForm4::CheckBoxClick(TObject *Sender)
    {
        unsigned short j= dynamic_cast<TCheckBox*>(Sender)->Tag;
        unsigned short k;
    
        for(k=0; k < (Form4->ComponentCount-1); k++)
        {
            TEdit *VirtualEdit= dynamic_cast<TEdit*>(this->Components[k]);
            if (VirtualEdit)
            {
    
                if(!VirtualEdit->Enabled)
                    VirtualEdit->Enabled= true;
                else
                {
                    VirtualEdit->Enabled= false;
                    VirtualEdit->Text= "0";
                }
                break;    // Schleifenabbruch herbeiführen
            }
        }
    }
    

    Allerdings wäre es noch besser wenn du die Variante aus der FAQ nimmst die mit einem eigenen DynamicArray arbeitet.

    bis bald
    akari



  • akari schrieb:

    ...wenn du dynamic_cast einsetzt, brauchst du auch kein ClassName mehr...

    Ahh, verstehe... Und zwar wegen:

    BCB-Hilfe schrieb:

    ... Wenn die Umwandlung durchgeführt werden kann, so wandelt der Ausdruck dynamic_cast< T > (ptr) den Zeiger ptr in den gewünschten Typ um. Falls die Umwandlung eines Zeigertyps nicht möglich ist, hat der zurückgegebene Zeiger den Wert NULL. ...

    stimmts?

    Und die Sache mit dem Schleifenabbruch ist mir ja peinlich... War schon wieder zu einfach für mich! 🙄

    Zur FAQ-Variante: wenn sich herausstellt dass ich noch Zeit habe, werde ich das machen!

    Wikipedia schrieb:

    ... Ein wichtiger Faktor bei der Entwicklung eines Systems ist aus Wettbewerbsgründen die Zeit. So muss sich der Ingenieur in der Praxis häufig mit einer nichtidealen Lösung zufrieden geben, die aber dennoch als gut einstufbar ist. ...

    😉



  • Mir ist da gerade noch etwas aufgefallen: Ist meine Lösung in diesem Fall nicht besser, weil dynamic_cast nur ausgeführt wird, wenn die Komponente ein TEdit ist? Mit der Lösung die akari angeboten hat, wird doch bei jeder Komponente ein dynamic_cast versucht... macht in meinem speziellen Fall einen maximalen Unterschied von 31 dynamic_casts (derzeit 48 Komponenten auf dem Formular, 17 davon TEdit). Hab ich was übersehen? 😕



  • Hallo

    Ahh, verstehe... Und zwar wegen:
    stimmts?

    Korrekt.

    Mir ist da gerade noch etwas aufgefallen: Ist meine Lösung in diesem Fall nicht besser, weil dynamic_cast nur ausgeführt wird, wenn die Komponente ein TEdit ist? Mit der Lösung die akari angeboten hat, wird doch bei jeder Komponente ein dynamic_cast versucht... macht in meinem speziellen Fall einen maximalen Unterschied von 31 dynamic_casts (derzeit 48 Komponenten auf dem Formular, 17 davon TEdit). Hab ich was übersehen?

    Du übersiehst zwei Sachen :
    - Auch die Ermittlung des ClassName sowie der AnsiString-Vergleich mit "TEdit" braucht seine Verarbeitung.
    - Wenn du schon auf ClassName vergleichst, brauchst du auch kein dynamic_cast sondern dann reicht ein static_cast ohne Überprüfung.

    bis bald
    akari



  • Wenn mans genau nimmt sollte auch bei der CheckBox-Umwandlung ein Test rein.
    Also

    TCheckBox* check(dynamic_cast<TCheckBox*>(Sender));
    if( !check) return;
    unsigned short j= check->Tag;
    


  • akari schrieb:

    Du übersiehst zwei Sachen :
    - Auch die Ermittlung des ClassName sowie der AnsiString-Vergleich mit "TEdit" braucht seine Verarbeitung.

    Ok, und was ist aufwendiger? Das oder dynamic_cast?

    akari schrieb:

    - Wenn du schon auf ClassName vergleichst, brauchst du auch kein dynamic_cast sondern dann reicht ein static_cast ohne Überprüfung.

    Kannst du das bitte nochmal anders (und evtl ausführlicher) formulieren? Ich steh' schon wieder auf der Leitung! 😞

    Braunstein schrieb:

    Wenn mans genau nimmt sollte auch bei der CheckBox-Umwandlung ein Test rein.

    Aber die Ereignisbehandlung ist doch für CheckBoxClick; Sender ist doch immer ein TCheckBox-Element 😕 Wozu der Test 😕



  • Hallo

    Ok, und was ist aufwendiger? Das oder dynamic_cast?

    Gute Frage. Schwer zu sagen. Ich vermute die ClassName-Variante.

    Kannst du das bitte nochmal anders (und evtl ausführlicher) formulieren? Ich steh' schon wieder auf der Leitung!

    Du machst momentan erst die ClassName-Überprüfung und dann die dynamic_cast-Umwandlung mitsamt Überprüfung. Damit ist eine Überprüfung doppelt. Und darum reicht eigentlich ein dynamic_cast aus.
    Du kannst natürlich auch die ClassName-Überprüfung machen und statt dem dynamic_cast einfach static_cast verwenden. Denn static_cast ist nur eine Umwandlung ohne Überprüfung, die man nehmen darf wenn man sich wirklich sicher ist. Dafür ist static_cast zur Laufzeit kostenlos.

    Aber die Ereignisbehandlung ist doch für CheckBoxClick; Sender ist doch immer ein TCheckBox-Element

    Braunstein meint genau das was ich oben gesagt habe : dynamic_cast brauchst du nur wenn du dir nicht sicher bist und ein Überprüfung braucht, ob die Umwandlung wirklich machbar ist. Das bedeutet aber auch das nach jedem sinnvollen dynamic_cast auch das Ergebnis von dynamic_cast überprüft werden sollte.

    Wenn du dir zur Entwurfszeit sicher bist das es funktioniert dann reicht ein static_cast.

    bis bald
    akari



  • Kolumbus schrieb:

    [Aber die Ereignisbehandlung ist doch für CheckBoxClick;

    Die ist nur dafür gedacht. Ja. Wenn du sie aber mal versehentlich einem TEditClick zuweist knallt es. Dazu brauchst du nur mal im Objektinspektor falsch auswählen.



  • Hallo

    Braunstein schrieb:

    Kolumbus schrieb:

    [Aber die Ereignisbehandlung ist doch für CheckBoxClick;

    Die ist nur dafür gedacht. Ja. Wenn du sie aber mal versehentlich einem TEditClick zuweist knallt es. Dazu brauchst du nur mal im Objektinspektor falsch auswählen.

    Also nur wegen dieser Befürchtung würde ich kein dynamic_cast verwenden. Soviel Kontrolle hab ich schon über mein Projekt 😉

    bis bald
    akari



  • Mag sein. Ich finde es nur eine nützliche Angewohnheit, bei dynamic_cast grundsätzlich zu prüfen. Kann sein das das manchmal unnötig ist, aber auf keinen Fall fehlerhaft. 🙂
    Wie du ja schon gesagt hast kann man ja sonst gleich static_cast nehmen.



  • Hallo

    Braunstein schrieb:

    Mag sein. Ich finde es nur eine nützliche Angewohnheit, bei dynamic_cast grundsätzlich zu prüfen. Kann sein das das manchmal unnötig ist, aber auf keinen Fall fehlerhaft. 🙂

    Genau 👍

    Wie du ja schon gesagt hast kann man ja sonst gleich static_cast nehmen.

    Und genau das würde ich in diesem Fall auch machen.

    bis bald
    akari



  • So, jetzt würde ich gern einen ausgeben; Ihr seid spitze - ich glaub' ich hab's gerafft! 👍
    Nach Abwägung eurer Argumente sieht das (vorläufige) Ergebnis nun so aus:

    void __fastcall TForm4::CheckBoxClick(TObject *Sender)
    {
    	unsigned short j= static_cast<TCheckBox*>(Sender)->Tag;
    
    	for(unsigned short k= 0; k < (this->ComponentCount-1); k++)
    	{
    		if((this->Components[k]->ClassNameIs("TEdit")) && (static_cast<TEdit*>(this->Components[k])->Tag==j))
    		{
    			TEdit *VirtualEdit= static_cast<TEdit*>(this->Components[k]);
    
    			if(!VirtualEdit->Enabled)
    				VirtualEdit->Enabled= true;
    			else
    			{
    				VirtualEdit->Enabled= false;
    				VirtualEdit->Text= "0";
    			}
    			break;
    		}
    	}
    }
    //---------------------------------------------------------------------------
    


  • Eine kleine Änderung

    for(unsigned short k= 0; k < (ComponentCount-1); k++)
        {
            TEdit* VirtualEdit = dynamic_cast<TEdit*>(Components[k]);
            if(VirtualEdit && VirtualEdit->Tag==j)
            {
    
                if(!VirtualEdit->Enabled)
                    VirtualEdit->Enabled= true;
                else
                {
                    VirtualEdit->Enabled= false;
                    VirtualEdit->Text= "0";
                }
                break;
            }
        }
    


  • Ok, das this spare ich mir gerne. Ich weiß ja zur Entwicklungszeit wo ich mich bewege. 👍
    Das deine Version übersichtlicher ist gebe ich zu und sie entspricht ja auch deinen dargelegten Prinzipien, aber ist sie zur Laufzeit ressourcensparender? Du castest jede Komponente, ich überprüfe bei jeder den Namen... wie bekommen wir raus, was günstiger ist? Gibts da eine Möglichkeit?



  • dynamic_cast wie auch ClassNameIs sollten ähnliche Laufzeiten haben, so dass sich beide Versionen nicht viel nehmen. Sie müssen ja beide intern überprüfen welche Klasse wirklich hinter dem Object-Zeiger steckt. Wenn du es genau wissen willst mußt du es halt mal überprüfen.



  • Jetzt habe ich das mal getestet.
    Die dynamic_cast Variante ist deutlich schneller als ClassNameIs (mehr als Faktor 20).



  • Interessant. Ich werd das morgen auch mal prüfen. Ich stell' mir vor, einfach nen Timer vorher zu starten und hinterher abzulesen. Passt das? Oder geht das so nicht?

    Edit: immer diese Schreibfehler 🙄

    Edit2: Schneller ist aber nicht unbedingt ressourcensparender (- CPU-Belastung, Arbeitsspeicher)? 😕



  • Ich habe den Thread nur überflogen, daher ganz bescheiden die Frage: ist es möglich, daß eine TCheckListBox deine Bedürftnisse besser erfüllt?


Anmelden zum Antworten