[Gelöst] Ereignis einer bestimmten Komponente aufrufen



  • Hallo,

    ich versuche gerade folgendes zu bewerkstelligen:

    • Suche nach einer Komponente auf der Form mit bestimmtne Merkmalen
    • Wenn diese gefunden wurde, führe dessen OnClick-Ereignis auf.

    Das Erste funktioniert, indem ich in einer Schleife die Komponentenliste durchgehe und die Eigenschaften abklopfe. Das ist nicht das Thema. Aber beim zweiten Punkt scheitere ich deshalb, weil jede Komponente ihr eigenes OnClick-Ereignis hat.

    Fällt jemandem etwas eleganteres ein als ein gesammeltes OnClick-Ereignis zu schreiben und darin wiederum die auszuführende Methode anhand der Eigenschaften von "Sender" zu bestimmen?

    VG



  • Hallo,
    wenn Du schon die passende Komponente gefunden hast kannst Du doch das dazugehörige OnClick Ereignis aufrufen!?

    TNotifyEvent ButtonClick;
    ButtonClick = Komponente->OnClick;
    ButtonClick(NULL);
    

    Oder habe ich dich falsch verstanden?



  • Löst es dein Problem, wenn du den Code aus dem Ereignishandler in eine eigene Funktion verschiebst und im Ereignishandler nur die Funktion aufrufst? Dann brauchst du den Ereignishandler nicht direkt aufzurufen. Deine Programmlogik kann dann auch direkt die Funktion aufrufen, ohne über den Handler zu gehen.

    Was genau möchtest du eigentlich machen? Vielleicht gibt es ja da eine andere Möglichkeit, das Problem zu lösen. Die GUI sollte Aktionen in der Programmlogik auslösen, nicht umgekehrt. Wenn die Programmlogik eine Aktion der GUI simulieren muss, um ein bestimmtes Verhalten hervorzurufen, stimmt im Design oft was nicht.



  • Danke für die Ansätze. Der erste gefällt mir, allerdings habe ich inzwischen das gemacht, was ich geschrieben hatte. Aber ich werde das noch einmal ummodeln, weil ich das mit TNotifyEvent wesentlich effizienter finde.

    Es geht konkret um folgendes: Ich habe einen eigenen Stil bezüglich Oberfläche. Da bei TButton der Rand einfach nicht weg zu kriegen ist, habe ich TLabel anstelle von TButton verwendet. Daraus ergibt sich aber nun das Problem, dass man TLabel nicht antabben kann (Steuerung ohne Maus).

    Mein Lösungsansatz: Arbeiten mit Hotkeys (ALT + Buchstabe, der auf dem TLabel unterstrichen ist, indem davor ein & gesetzt ist).

    Das sieht bei mir zzt. folgendermaßen aus:

    void __fastcall TfMain::FormKeyUp(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
            if(Key>=(WORD)'A' && Key<=(WORD)'Z' && (GetKeyState(VK_MENU)|1)==-127)
            {
                    for(int i=0;i<ComponentCount;i++)
                    {
                            if(Components[i]->ClassNameIs("TLabel")
                            && dynamic_cast<TLabel*>(Components[i])->ParentShowHint
                            && dynamic_cast<TLabel*>(Components[i])->Caption.Pos("&"+String((char)Key))>0)
                            {
                                    AllClick(Components[i]);
                            }
                    }
            }
    }
    //---------------------------------------------------------------------------
    void __fastcall TfMain::AllClick(TObject *Sender)
    {
            TComponent *cTmp=dynamic_cast<TComponent*>(Sender);
            if(cTmp->ClassNameIs("TLabel") && dynamic_cast<TLabel*>(cTmp)->ParentShowHint)
            {
                    if(cTmp->Name=="lStart") BtnStartClick(Sender);
                    else if(cTmp->Name=="lSettings") BtnSettingsClick(Sender);
            }
    }
    

    Die Eigenschaft ParentShowHint verwende ich als Ersatz für Enabled , da Enabled den Nachteil hat, dass die Schrift "eingedrückt" wird.

    Das Ganze kann ich dann ja doch wesentlich bequemer und effizienter gestalten. Danke.

    Edit: Damit man einmal sieht, wie man sich das vorstellen kann, hier ein Screenshot: http://abload.de/img/pingmon_v011ioj6.jpg



  • Hallo,

    Diese Kombination von ClassNameIs und dynamic_cast finde ich übertrieben und unübersichtlich. Wenn du mit ClassnameIs schon weißt das der Klassentyp stimmt reicht sicherlich ein static_cast. Oder du machst es so:

    for(int i=0;i<ComponentCount;i++)
    {
        TLabel* label = dynamic_cast<TLabel*>(Components[i]);
       if(label && label->ParentShowHint && label->Caption.Pos("&"+String((char)Key))>0)
       {
          AllClick(Components[i]);
       }
    }
    

    Ähnlich würde ich auch AllClick umbauen.



  • Ich würde dennoch das von DocShoe beschriebene Umsetzen, einfach weil es im optimalfall kein Wissen über die Oberflächencontrols benötigt.

    void __fastcall TfMain::FormKeyUp(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
         if(Key>=(WORD)'A' && Key<=(WORD)'Z' && (GetKeyState(VK_MENU)|1)==-127)
         {
             switch(Key)
             {
                  case (WORD)'A':
                      Start();
                      break;
                  case (WORD)'S':
                      ShowSettings();
                      break;
                  // ...
             }
         }
    }
    
    void __fastcall TfMain::BtnStartClick(TObject *Sender)
    {
        Start();
    }
    
    void __fastcall TfMain::BtnSettingsClick(TObject *Sender)
    {
        ShowSettings();
    }
    


  • Da stimme ich dir voll zu.



  • Danke für die Ausführungen. Das sieht in der Tat übersichtlicher aus, Braunstein. Da werde ich mir einiges von abgucken und das mit TNotifyEvent kombinieren.

    Man kann sich darüber streiten, inflames2k. Ich finde deinen Ansatz natürlich sehr übersichtlich. Von der VCL-Entwicklung her betrachtet wiederum finde ich es bequemer eine eierlegende Wollmilchsau-Funktion zu schreiben, wo ich mich später beim Hinzufügen von weiteren Fake-Buttons um nichts mehr kümmern muss, außer einem OnClick-Event. Deshalb finde ich den Ansatz mit TNotifyEvent für meine Anforderungen besser.

    Ich poste, wenn ich damit durch bin, wie ich das gelöst habe. Vielen Dank soweit.



  • Wäre es nicht einfacher eine Klasse von TButton abzuleiten und die dann wie gewünscht anzupassen?



  • heini schrieb:

    ...
    Deshalb finde ich den Ansatz mit TNotifyEvent für meine Anforderungen besser.
    ...

    Das kann man dann aber auch als Einzeiler realisieren:

    Component->OnClick( Component );
    

    Dann haste auch noch den Absender dabei, falls das irgendwann mal wichtig wird.



  • Million Voices schrieb:

    Wäre es nicht einfacher eine Klasse von TButton abzuleiten und die dann wie gewünscht anzupassen?

    Nein. Allerdings hast du natürlich Recht, wenn du sagst, dass das die sauberere Lösung wäre.

    DocShoe schrieb:

    Das kann man dann aber auch als Einzeiler realisieren:

    Dann haste auch noch den Absender dabei, falls das irgendwann mal wichtig wird.

    Ja, den Sender nehme ich natürlich mit. So war das auch gedacht. 😉

    Und hier nun mein aktueller Stand und wie ich es vermutlich belassen werde:

    void __fastcall TfMain::FormKeyUp(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
            if(Key>=(WORD)'A' && Key<=(WORD)'Z' && (GetKeyState(VK_MENU)|1)==-127)
            {
                    for(int i=0;i<ComponentCount;i++)
                    {
                            TLabel *lTmp=dynamic_cast<TLabel*>(Components[i]);
                            if(lTmp && lTmp->ParentShowHint && lTmp->Caption.Pos("&"+String((char)Key))>0)
                            {
                                    TNotifyEvent ne=lTmp->OnClick;
                                    ne(lTmp);
                            }
                    }
            }
    }
    

Anmelden zum Antworten