Abfragen auf welche Komponente geklickt wurde?
-
Hallo Zusammen,
ich erstelle während der Laufzeit mehrere CheckBoxen denen ich ein OnClick Event zuweise. Das funktioniert soweit auch. Ich möchte dieses OnClick Event jetzt aber so variabel wie möglich gestalten.Ich habe momentan 15 CheckBoxen. Es werden aber von Zeit zu Zeit mehr. Ich könnte jetzt natürlich jeder CheckBox ein eigenes OnClick Event zuweisen. Dann hätte ich momenten 15 Events. Jetzt habe ich mir gedacht, dass das doch bestimmt einfacher geht.
Jetzt ist meine Frage, ob ich herausfinden kann welche CheckBox geklickt wurden ist? Ich habe mal in der FAQ geschaut. Da habe ich folgendes gefunden:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-39210.htmlIch denke mal, dass ist das was ich brauche. Aber wie kann ich das jetzt einzetzen? Momentan sieht meine Funktion so aus:
void __fastcall Tneue_bestellung::ArtikelClick(TObject *Sender) { if(CBhs005->Checked == true) { Ehs005_menge->Visible = true; preisberechnung(); } else { Ehs005_menge->Visible = false; preisberechnung(); } tab_control(); adress_kontrolle(); }
Wie kann ich das jetzt so umbauen, dass die Funktion nicht nur für CBhs005 gilt? Liege ich da mit Sender richtig? Könnte ich da vielleicht sowas wie
if(Sender->Checked == true) {
machen?
-
Hallo,
du kannst den Sender casten
if (dynamic_cast<TCheckBox*>(Sender)->Checked)) //...
vorher vllt noch mittels IsClassName prüfen ob es sich wirklich um eine Checkbox handelt. Ist ja auch möglich dass der Event durch ein anderes Objekt ausgelöst wird (warum auch immer).
Edit: öhm und mittels "->Name" kannst du prüfen welche Checkbox gewählt wurde ^^
LG, Micha
-
Hallo
Das einfachste ist die Umwandlung des Senders in die CheckBox. Denn in Sender ist laut VCL-Richtlinie immer die auslösende Komponente überliefert.
void __fastcall Tneue_bestellung::ArtikelClick(TObject *Sender) { TCheckBox* Akt = static_cast<TCheckBox*>(Sender); if (Akt->Checked) { //... } else { //... } }
Damit das nun auch wirklich generisch funktioniert, muß nun aus dem allgemeinen Zeiger auf die genaue Funktion der Komponente geschlossen werden. Um nun den Event nicht wieder durch unelegante Vergleiche mit den festen OI-Namen zu unflexibel zu machen, kannst du in jede der relevanten CheckBoxen in deren Tag-Eigenschaft einen Wert eintragen um diese durchzunummerieren. Z.B. bei der CheckBox mit dem Namen "CBhs005" trägst du die 5 als Tag ein (Wenn deine Zählung bei den Namen nicht mit "000" anfängt, dann bitte jeweils eins abziehen).
Nun kannst du auch im Event diesen Tag auslesen :... int Nummer = Akt->Tag; ...
Damit du diese Nummer nun auch elegant für die Bestimmung der dazugehöhrigen EHS-Komponente benutzen kannst, solltest du vorher einmalig die Komponenten in ein statisches Member-Array eintragen. Weiteres dazu findest du in der FAQ hier im Builder-Forum, Abschnitt Komponenten benutzen, Thread "Dynamische Arrays von Komponenten".
Damit sähe dann dein Event so aus :void __fastcall Tneue_bestellung::ArtikelClick(TObject *Sender) { TCheckBox* Akt = static_cast<TCheckBox*>(Sender); if(Akt->Checked == true) { Ehs[Akt->Tag]->Visible = true; preisberechnung(); } else { Ehs[Akt->Tag]->Visible = false; preisberechnung(); } tab_control(); adress_kontrolle(); }
bis bald
akari
-
Hallo,
danke für eure Tipps. Inzwischen habe ich es auch hinbekommen. Ich habe es allerdings so gelöst:void __fastcall Tneue_bestellung::ArtikelClick(TObject *Sender) { if(dynamic_cast<TCheckBox*>(Sender)->Checked == true) { preisberechnung(); } else { preisberechnung(); } tab_control(); adress_kontrolle(); }
Kann ich das so lassen oder wäre das nicht so gut?
-
Wenn ich mal kurz nachfragen darf... Pseudocode:
if(true){ MacheA(); } else [ MacheA(); }
Wozu brauchst du da eine Verzweigung?
MfG
-
RandomAccess85 schrieb:
vorher vllt noch mittels IsClassName prüfen ob es sich wirklich um eine Checkbox handelt.
[...]
Edit: öhm und mittels "->Name" kannst du prüfen welche Checkbox gewählt wurde ^^Uah.
Was spricht dagegen, das Ergebnis von dynamic_cast<> auf 0 und das übergebene Objekt auf Gleichheit mit der erwarteten Komponente zu prüfen?
Gewöhnlich ist in diesen Fällen aber ein Referenz-Cast besser geeignet als die manuelle Überprüfung:
http://www.c-plusplus.net/forum/viewtopic-var-p-is-1598086.html#1598086
-
audacia schrieb:
RandomAccess85 schrieb:
vorher vllt noch mittels IsClassName prüfen ob es sich wirklich um eine Checkbox handelt.
[...]
Edit: öhm und mittels "->Name" kannst du prüfen welche Checkbox gewählt wurde ^^Uah.
Was spricht dagegen, das Ergebnis von dynamic_cast<> auf 0 und das übergebene Objekt auf Gleichheit mit der erwarteten Komponente zu prüfen?
Was spricht dagegen, das Ergebnis von dynamic_cast<>()->Name zu prüfen, wenn vom Namen abhängig gemacht wird, was die Folgeschritte sind?
Und was spricht dagegen mittel ClassNameIs zu prüfen ob es sich tatsächlich um TCheckBox handelt
LG, Micha
-
Dagegen spricht folgendes.
Wenn du sowieso einen dynamic_cast machen willst, der einen gültigen Pointer liefert wenn die Klasse stimmt, wieso sollte man noch mit ClassNameIs prüfen.
ClassnameIs ist um einiges langsamer als dynamic_cast. Das spielt zwar hier keine Rolle aber vielleicht später mal.
Ein Ausdruck wie dieserdynamic_cast<>()->Name
kann zu den schönsten AccessViolations führen wenn der Typ nicht stimmt.
Reicht das jetzt?
-
Hallo,
wenn ich den OnClick-Event für verschiedene Zwecke verwende -> einmal für Button / einmal für CheckBox, halte ich es für sehr hilfreich abzufragen welche Klasse ich überhaupt ansprechen will.
if (Sender->ClassNameIs(TButton)) // nach TButton casten else if (Sender->ClassNameIs(TCheckBox)) // nach TCheckBox casten
Project Project1.exe raised exception class EAccessViolation with message 'Access violation at address 004637A2 in module 'Project1.exe'. Read of address 00000008'. Process stopped. Use Step or Run to continue.
... erhalte ich wenn ich nach TCheckBox caste, aber der Event durch einen Button ausgelöst wurde!
Wenn ich vorher aber Frage ob es sich überhaupt um einen Button handelt, umgehe ich diesen Fehler.
LG, Micha
-
Wenn du das Ergebnis von dynamic_cast testest hast du das Problem auch nicht. Wenn der cast klappt kannst du auch gleich mit der variable weiterarbeiten und brauchst keinen weiteren cast.
TButton* button = dynamic_cast<TButton*>(Sender); if (button) // nach TButton casten else { TCheckBox* chbox= dynamic_cast<TCheckBox*>(Sender); if (chbox) // nach TCheckBox casten }
Performanter als deine Lösung ist das auch.
-
Hallo,
ok einverstanden
! Gleiches Ziel, unterschiedliche Lösungswege...
LG, Micha
-
IMHO ist euer "kleiner Glaubenskrieg" dem Threadsteller nicht unbedingt hilfreich...
Beide Methoden funktionieren, die Eine angeblich (hier "angeblich", weil ich es selbst nicht getestet habe) etwas langsamer als die Andere... aber das wars ja dann wohl auch... mag sein, dass der Eine oder Andere die langsamere Methode übersichtlicher findet und die Geschwindigkeit nicht relevant ist
Ich persönlich nehme Methode 3:
dynamic_cast<> ohne irgendeine Prüfung hinterher oder vorher - ich WEIß schliesslich zu hundert Prozent, wenn ich eine Ereignis-Methode nur einem einzigen Komponententyp zugeordnet habe.
Edit: jetzt kam Micha's Post - sehr vernünftig
*MalMoralApostelSpiel*
-
Wenn du es weißt, dann kannst du auch static_cast nehmen.
Das "angeblich" bei dem Performancaspekt kannst du streichen. Das ist getestet.