Ereignissse von dynamischen Controls innerhalb einer Klasse



  • Ich hab mir eine neue Klasse erstellt. Innerhalb der Klasse werden dynamisch ein oder mehrere TImage erstellt und verschiedene Eigenschaften zugewiesen. Dann wird das TImage auf einer Form angezeigt.

    Wo und wie kann ich denn nun die Ereignisse abfangen ?

    Ich muß z.B. feststellen, wann die Maus auf dem Contol gedrückt wird und dann entsprechend reagieren (Control verschieben usw).

    Werden die Ergeignisse innerhalb der Klasse verarbeitet oder wie ?



  • Die Ereignisse werden in der Klasse nihct verarbeitet. dafür musst du schon selbst sorgen.

    Wie du es machst, ist geschmacksache.

    1. Benutzung der Methodenpointer (Ereignisse)

    Das ist recht gefährlich, da ein Methodenpointer nicht nach der Zerstörung des Objektes auf NULL gesetzt wird. Es ist möglich, dass eine Methode eines Objekts aufgerufen wird, das gar nicht mehr existiert. Die Folge wäre eine Zugriffsverletztung.
    Das Problem taucht solange nicht auf, wie man die Ereignisspointer im Hintergrund der Anwendung hält. Also dem Anwender der Klasse das Reagieren auf diesen Ereignissen verweigert. Ausserdem muss die Methodenzuweiseung an den Methodenpointern im Destruktor wieder zurückgesetzt werden.

    1. Einklinken in die Nachrichtenschleife des Objektes.

    Eine recht sichere Alternative, die ich bevorzugen würde. Du weisst dem Objekt eine neue WndProc zu und fängst dort die Nachrichten ab. Hierbei muss auch wieder im Destruktor der Ursprung wieder hergestllt werden.

    In der FAQ ist normalerweise ein Artikel von WebFritzi zum Thema Nachrichtenschleifen....



  • Danke für die Anwort. Ich hab mal ein bischen ausprobiert (WindowProc), komm jedoch damit innerhalb einer Klasse nicht klar. Wo muß ich die WindowProc denn eintragen ? Der Compiler schmeißt mir ständig Fehler raus. Hier mal ein kurzer Abriss der Klasse:

    //Header- Datei
    
    #ifndef TBILDOBJEKT_H
    #define TBILDOBJEKT_H
    //---------------------------------------------------------------------------
    
    #include <vcl>
    #include <jpeg.hpp>
    class TGrafObj
    {
       private:
         int        F_Links, F_Oben;
         int        F_Breite, F_Hoehe;
         TImage*    F_Bild;
    
         void setLinks( const int &i_Links)            ;
         void setOben ( const int &i_Oben)             ;
         void setBreite( const int &i_Breite)          ;
         void setHoehe ( const int &i_Hoehe)           ;
    
       public:
         // Eigenschaften des Bildes nach dem Property - Konzept von Borland
         __property AnsiString ObjName    = {read = getObjName,  write = setObjName  };
         __property int        Links      = {read = F_Links,     write = setLinks    };
         __property int        Oben       = {read = F_Oben,      write = setOben     };
         __property int        Breite     = {read = F_Breite,    write = setBreite   };
         __property int        Hoehe      = {read = F_Hoehe,     write = setHoehe    };
    
         TGrafObj( TWinControl *Owner );
    
         ~TGrafObj();
    
    };
    #endif
    
    //CPP - Datei
    
    //----------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "TBildObjekt.h"
    //----------------------------------------------------------
    
    TGrafObj::TGrafObj( TWinControl *Owner )
    {
     // Die Standardmaße für das Bildobjekt setzen
     F_Links = 0; F_Oben = 0; F_Breite = 100; F_Hoehe = 100;
     // Instanz eines neuen Timage erzeugen und dem der Instanz des Owner zuordnen
     F_Bild = new TImage(Owner);
     // Übergeordnetes Objekt setzen
     F_Bild->Parent = Owner;
    }
    //----------------------------------------------------------
    
    TGrafObj:: ~TGrafObj()
    {
    }
    //----------------------------------------------------------
    


  • //Header- Datei
    
    #ifndef TBILDOBJEKT_H
    #define TBILDOBJEKT_H
    //---------------------------------------------------------------------------
    
    #include <vcl>
    #include <jpeg.hpp>
    class TGrafObj
    {
       private:
         int        F_Links, F_Oben;
         int        F_Breite, F_Hoehe;
         TImage*    F_Bild;
         TWndMethod OldImageProc; 
         void setLinks( const int &i_Links)            ;  // warum hier mit Referenzen arbeiten ? 
         void setOben ( const int &i_Oben)             ;
         void setBreite( const int &i_Breite)          ;
         void setHoehe ( const int &i_Hoehe)           ;
      protected: // [Edit] Eingefügt, da virtuelle Methoden nur ab protected was nutzen [/Edit]
         DYNAMIC void __fastcall ImageProc(Messages::TMessage &Message);
    
       public:
         // Da du Standardwerte setzt, default setzen:
         __property AnsiString ObjName    = {read = getObjName,  write = setObjName };
         __property int        Links      = {read = F_Links,     write = setLinks   ,default=0 };
         __property int        Oben       = {read = F_Oben,      write = setOben  ,default=0   };
         __property int        Breite     = {read = F_Breite,    write = setBreite ,default=100  };
         __property int        Hoehe      = {read = F_Hoehe,     write = setHoehe , default=100   };
    
         TGrafObj( TWinControl *Owner );
    
         ~TGrafObj();
    
    };
    #endif
    
    //CPP - Datei
    
    //----------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "TBildObjekt.h"
    //----------------------------------------------------------
    
    TGrafObj::TGrafObj( TWinControl *Owner )
        :F_Links(0),F_Oben(0),FBreite(100),F_Hoehe(100)
    {
     F_Bild = new TImage(Owner);
     F_Bild->Parent = Owner;
     F_Bild->SetBounds(0,0,100,100);
     OldImageProc=F_Bild->WindowProc;
     F_Bild->WindowProc=ImageProc;
    }
    //----------------------------------------------------------
    
    TGrafObj:: ~TGrafObj()
    {
     F_Bild->WindowProc=OldImageProc;
     delete F_Bild;
    }
    //----------------------------------------------------------
    void __fastcall TGrafObj::ImageProc(Messages::TMessage &Message)
    {
    
    if(OldImageProc)OldImageProc(Message);
    
    //mach was
    }
    

    [ Dieser Beitrag wurde am 13.01.2003 um 08:03 Uhr von AndreasW editiert. ]



  • 🙂 Thx, funktioniert alles wunderbar, bis auf die default Werte.
    Compilermeldung: für default ist ein Klassentyp im VCL-Stil erforderlich

    😞 Was fehlt denn hier noch ?

    P.S. Die Referenzen hab ich genommen, damit man ( lt. meinem schlauen Buch, da war ne Vorlage drin) nicht unbeabsichtigt die Werte ändern kann. Ich versteh's zwar auch nicht ganz, aber ich dachte mir, wenn einer ein Buch schreibt, der hat wohl Ahnung ;-)).



  • Original erstellt von spool:
    **:) Thx, funktioniert alles wunderbar, bis auf die default Werte.
    Compilermeldung: für default ist ein Klassentyp im VCL-Stil erforderlich

    😞 Was fehlt denn hier noch ?
    **

    Sorry, du hast nicht von einer VCL- Klasse abgeleitet. Nimm einfach die default- Sachen raus. ( War mein Fehler;Hätte ich sehen müssen).

    Diese Default- Werte sind nämlich nur für Klassen geeignet, die von einer VCL- Klasse abgeleitet wurden.
    Das ist aber nicht erforderlich.

    Original erstellt von spool:
    P.S. Die Referenzen hab ich genommen, damit man ( lt. meinem schlauen Buch, da war ne Vorlage drin) nicht unbeabsichtigt die Werte ändern kann. Ich versteh's zwar auch nicht ganz, aber ich dachte mir, wenn einer ein Buch schreibt, der hat wohl Ahnung ;-)).

    Das hast du falsch verstanden. Wenn man eine Funktion schreibt, die als Parameter Referenzen erwarten, so kann man inerhalb dieser Funktion diese Parameter ändern.

    Beispiel:

    void test( int & AValue)
    {
    AValue=5;
    } 
    
    int main()
    {
    int T=3;
    test(T);
    cout<<T; // Es wird "5" ausgegeben
    return 0;
    }
    

    Um sowas zu verhindern schreibt man ein "const" davor. Konstante Parameter können nicht verändert werden. Du würdest bereits beim Compilieren eine Fehlermeldung bekommen.
    Beispiel:

    void test( const int & AValue)
    {
    AValue=5;
    } 
    
    int main()
    {
    int T=3;
    test(T);
    cout<<T; // Es wird "5" ausgegeben
    return 0;
    }
    

    so wird eine versehentliche Veränderung verhindert.



  • Das DYNAMIC mag der Compiler auch im protected Bereich nicht.
    DYNAMIC ist hier nicht erlaubt (oder so ähnlich).

    zu Referenzen:
    Damit hab ichs noch nicht so (Umsteigerkrankheit vielleicht). Const ist mir klar, das gabs auch bei VB schon.



  • ja,

    DYNAMIC ist ungefähr das selbe wie "virtual". Du kannst also DYNAMIC durch "virtual" ersetzen.
    Du brauchst die Methde aber nur als virtual zu deklarieren, wenn du eine Klasse von dieser ableiten und die Methode überschreiben möchtest. Ansonsten kannst du es auch einfach weglassen.



  • DYNAMIC = virtual

    Aber ich frage mich, warum du nicht gleich eine neue Komponente schreibst. Du könntest sicher die eine oder andere Eigenschaft der einen oder anderen VCL-Klasse gebrauchen. Und warum ist *Owner TWinControl und nicht TComponent? Naja, deine Sache.



  • Huups, da war ja einer viel schneller. 😉



  • jep 🙂

    Und warum ist *Owner TWinControl und nicht TComponent?

    wahrscheinlich möchte er sichergehen, das ein fensterorientiertes Objekt als Parameter übergeben wird 😉

    [ Dieser Beitrag wurde am 14.01.2003 um 23:35 Uhr von AndreasW editiert. ]



  • Na gut, wegen des Parent des Images. Aber dann sollte man den Parameter nicht Owner nennen, weil das was anderes ist in der VCL.



  • Ich bin aber an den Owner aus VB gewöhnt und alte Gewohnheiten hält man halt bei.


Anmelden zum Antworten