Grafik, Events und anderes bei eigener Komponente



  • Ich weiß zwar nicht ob man übersehen nennen kann.hab durch zufall raus gefunden wenn der Component Owner von TGraphicControl kommt, Funktioniert es nicht und wenn der Owner von TWinControl kommt dann funktioniert es. Dasversteh ich zwar nicht ganz weil doch beide von TControl abgeleitet sind in der die Ereignisse und Events enthalten sind.



  • Hi,

    Alternativ bietet sich an, die WndProc-Methode zu benutzen.

    *.h

    //---------------------------------------------------------------------------
    #ifndef main_graphicH
    #define main_graphicH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    
    #include <Buttons.hpp>
    //---------------------------------------------------------------------------
    
    //typedef void __fastcall (__closure *MyClickEvent)(TObject *Sender,TPoint Position);
    
    class TForm1;
    class TMyGraph : public TGraphicControl
    {
    friend class TForm1;
    private:
        POINT points[5];
        //MyClickEvent    FMyOnClick;
    protected:
    
        void __fastcall WndProc(Messages::TMessage &Message);
    
    public:
    
        //void __fastcall MyOnClick(TObject *Sender, TPoint Position);
        /*
        void __fastcall Click()
        { 
            TPoint point;
            GetCursorPos(&point);   // Screen-Koordinaten
            if(FMyOnClick)
                FMyOnClick(this,point);
            TGraphicControl::Click();
        }
        */
        __property Canvas ;  // Zugriff auf Canvas erlauben
    
        __fastcall TMyGraph(TComponent* Owner);
    
    };
    //---------------------------------------------------------------------------
    
    class TForm1 : public TForm
    {
    __published:	// Komponenten, die von der IDE verwaltet werden
        TButton *Button1;
        TButton *Button2;
        TBitBtn *BitBtn1;
        TSpeedButton *SpeedButton1;
        TLabel *Label1;
        TLabel *Label2;
        void __fastcall Button1Click(TObject *Sender);
        void __fastcall Button2Click(TObject *Sender);
    
    private:
    public:
        TMyGraph* MyGraph;
        __fastcall TForm1(TComponent* Owner);
        __fastcall ~TForm1(void);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    

    *.cpp

    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "main_graphic.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    
    #pragma resource "*.dfm"
    TForm1 *Form1;
    
    __fastcall TMyGraph::TMyGraph(TComponent* Owner)
        : TGraphicControl(Owner)
    {
        Width  = 120;
        Height = 120;
        Canvas->Brush->Color = clBlack;
        points[0].x =  0;
        points[0].y =  0;
        points[1].x = Width -1;
        points[1].y =  0;
        points[2].x = Width -1;
        points[2].y = Height -1;
        points[3].x =  0;
        points[3].y = Height -1;
        points[4].x =  0;
        points[4].y =  0;
    
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMyGraph::WndProc(Messages::TMessage &Message)
    {
        switch(Message.Msg) {
            case  WM_PAINT : {
                // Rahmen zeichnen
                Canvas->Pen->Color = clRed;
                Canvas->Polyline(points,4);
            }
            break;
            case WM_LBUTTONDOWN : {
                int X = (LPARAM) Message.LParamLo;
                int Y = (LPARAM) Message.LParamHi;
                // Ausgabe der Koordinaten
                Form1->Label1->Caption = "Klick bei X: " + IntToStr(X);
                Form1->Label2->Caption = "Klick bei Y: " + IntToStr(Y);
            }
            break;
            case WM_MOUSEMOVE : {
                int X = (LPARAM) Message.LParamLo;
                int Y = (LPARAM) Message.LParamHi;
                // Ausgabe der Koordinaten
                Form1->Label1->Caption = "X: " + IntToStr(X);
                Form1->Label2->Caption = "Y: " + IntToStr(Y);
            }
            break;
       }
       TGraphicControl::WndProc(Message);
    }
    //---------------------------------------------------------------------------
    /*
    void __fastcall TMyGraph::MyOnClick(TObject *Sender, TPoint Position)
    {
        int x = Position.x;
        int y = Position.y;
        ShowMessage("Klick in x= " + IntToStr(x) + " und y = " + IntToStr(y));
        TGraphicControl::Click();
    }
    */
    //---------------------------------------------------------------------------
    
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        MyGraph         = new TMyGraph(this);
        MyGraph->Left   = 10;
        MyGraph->Top    = 10;
        MyGraph->Parent = Form1;
    }
    //---------------------------------------------------------------------------
    
    __fastcall TForm1::~TForm1(void)
    {
        delete MyGraph;
    }
    //---------------------------------------------------------------------------
    

    Die erste Variante Klick-Event ist kommentiert.

    mfg
    kpeter



  • Hmm... damit kann man schon was anfangen 🙂

    Wenn ich jetzt mit Canvas eine Linie Male, kann ich dann auch rausfinden ob die Maus gerade auf der Linie ist, oder muss ich das über X/Y coordinaten selber raus suchen?

    nachdem was ich so in der BCB Hilfe gelesen habe, könnte ich mit dem HDC Handle von Canvas vielleicht etwas machen, aber habe nicht rausfinden können wie das gehen soll.



  • JBOpael schrieb:

    Wenn ich jetzt mit Canvas eine Linie Male, kann ich dann auch rausfinden ob die Maus gerade auf der Linie ist, oder muss ich das über X/Y coordinaten selber raus suchen?

    Eigentlich sollte es anders herum sein. Nach den Mauskoordinaten (oder Stift) wird eine Linie gezeichnet. Win API's LineDDA zb.

    edit:

    Damit hier keine Langeweile aufkommt 😃

    einfügen in *.cpp

    // gleich unterhalb Form-Konstruktor
    
    VOID CALLBACK LineDDACallBack( int X, int Y, LPARAM lParam )
    {
       Form1->MyGraph->Canvas->Pixels[X][Y] = RGB(0, 0, 0);
       // Koordinaten ausgeben ( und irgendwann speichern ...)
       // Gimmick
       Form1->Memo1->Lines->Add("X: " + IntToStr(X) + ", Y: " + IntToStr(Y));
    }
    //---------------------------------------------------------------------------
    
    // in WndProc vervollständigen
    
       case WM_MOUSEMOVE : {
          int X = (LPARAM) Message.LParamLo;
          int Y = (LPARAM) Message.LParamHi;
          LineDDA( oldx, oldy, X, Y, (LINEDDAPROC)LineDDACallBack, NULL );
          oldx = X;
          oldy = Y;
          // Ausgabe der Koordinaten
          Form1->Label1->Caption = "X: " + IntToStr(X);
          Form1->Label2->Caption = "Y: " + IntToStr(Y);
       }
       break;
    

    mfg
    kpeter



  • Eigentlich sollte es anders herum sein. Nach den Mauskoordinaten (oder Stift) wird eine Linie gezeichnet. Win API's LineDDA zb.

    Der Sinn dahinter ist ja das ich nicht nur eine Linie Malen kann, sondern diese Linie auch ändern, verschieben und vor allem zuordnen kann.

    Mit dem was du geschieben hast, habe ich ein Problem. da ich das ja versuche in eine Komponente zu packe stoße ich bei dem Callback auf ein Problem.

    Wenn ich den außerhalb meiner klasse als funktion anlege, funktioniert das ich komm aber dann nicht an mein Canvas dran. und wenn ich den Innerhalb meiner klasse anlege bekomme ich die Fehlermeldung:

    [BCC32 Fehler] GraphicControl1.h(175): E2235 Elementfunktion muß aufgerufen oder ihre Adresse übernommen werden
    

    weder die BCB Hilfe noch google gibt mir antworten darauf 😞



  • Dann anders; anstatt LineDDA geht natürlich auch

    // ersatzweise für CALLBACK LineDDA
       POINT points[2];
       points[0].x = oldx;
       points[0].y = oldy;
       points[1].x = X;
       points[1].y = Y;
       this->Canvas->Polyline(points, 1);
       oldx = X;
       oldy = Y;
    

    kpeter



  • Damit kann ich doch nur eine Linie zeichnen und keine gezeichnete Linie erkennen ?!



  • JBOpael schrieb:

    gezeichnete Linie erkennen

    Wie ist das gemeint?



  • Wenn ich mit Canvas eine Linie Zeichne und ich dann mit der Maus auf die linie gehe dann soll ein ereignis ausgelöst werden.

    genau genommen will ich es hin bekommen das die linie einen Focus bekommen kann. quasi so wie man es von Grafikprogrammen kennt. Man malt eine Linie und wenn die Linie angeklickt wird erhält sie den Fokus und ich kann die Linie per maus noch vergrößern, verschieben etc.. So soll das endprodukt aussehen.



  • Linien zeichnen geht ja nun.

    Verbunden mit WM_LBUTTONDOWN und WM_LBUTTONUP (Startpunkt/Endpunkt) können gerade Linien und geometrische Figuren gezeichnet
    werden. Die Pixelpositionen bekommst du ja geliefert.

    Wo ist da das Problem?



  • Wenn ich jetzt mit Canvas eine Linie Male, kann ich dann auch rausfinden ob die Maus gerade auf der Linie ist, oder muss ich das über X/Y coordinaten selber raus suchen?

    Das ist das was ich hier gefragt hatte. ich muss also die pixel coordinaten mit den Maus coordinaten vergleichen und wenn die die maus auf der linie ist das event auslösen.



  • Das bekommt man hin, Mauskoord. mit Liniekoord. vergleichen. Aber deshalb bekommt diese
    Linie sicher keinen Fokus oder wird gar markiert.

    Das spielt jetzt wieder in den anderen Thread hinein...

    mfg
    kpeter



  • class TMyGraphic : public TGraphicControl
    {
    ...
    
        public:
             __fastcall TMyGraphic(TComponent* Owner) : TGraphicControl(Owner)
            {
                Widht=100;
                Height=100;
            }
    
    }
    
    class PACKAGE TGundgrafik : public TWinControl
    {
    private:
    
            TMyGraphic *MeineGrafik;
    public:
    	__fastcall TGundgrafik(TComponent* Owner) :TWinControl(Owner)
    	{
    		MeineGrafik = new TMyGraphic(this);
    
    		MeineGrafik->Parent=this;
    		MeineGrafik->Left=0;//this->Left;
    		MeineGrafik->Top=0;//this->Top;
    //		MeineGrafik->Width=130;//this->Width ;
    //		MeineGrafik->Height=130;//this->Height;
    
            }
    }
    

    Beim Anlegen soll TMyGraphic so groß sein wie TGundgrafik.

    1.Problem: Wie komme ich an die größe von Owner? Left, Widht etc ist im Konstruktor noch 0.

    2. Problem: Wo muss ich das definieren. wenn ich das aus dem Konstuktor von TMyGraphic Weg lasse und bei TGundgrafik hinzufüge dann macht der das nicht.



  • Hi,

    die Eigenschaft auf Align = alClient; setzen

    edit:
    an die Grösse kommst du über einen Zeiger:

    TForm1* MyOwner;
       MyOwner = static_cast<TForm1*>(Form1);
       int w = MyOwner->Width;
    

    mfg
    kpeter



  • Auf Align hätte ich auch selber kommen können 🙂

    aber wiso ist im Konstruktor die breite des Objects noch nicht bekannt?

    __fastcall TGundgrafik(TComponent* Owner) :TWinControl(Owner)
        {
    
            int breite=this->Widht;  // breite ist 0
        }
    


  • Du muss deiner Grundgrafik doch erst mal sagen, wie gross sie sein soll.
    Und das, bevor du die dyn. Komponente erzeugst.

    class PACKAGE TGundgrafik : public TWinControl
    {
    private:
    
            TMyGraphic *MeineGrafik;
    public:
        __fastcall TGundgrafik(TComponent* Owner) :TWinControl(Owner)
        {
            this->Width  = 100;
            this->Height = 100;
            // nimm SetBounds ;)
    
            MeineGrafik = new TMyGraphic(this);
    
            MeineGrafik->Parent=this;
            MeineGrafik->Align = alClient;
    
            //MeineGrafik->Left=0;//this->Left;
            //MeineGrafik->Top=0;//this->Top;
            //MeineGrafik->Width=130;//this->Width ;
            //MeineGrafik->Height=130;//this->Height;
    
            }
    }
    


  • Ich raff das einfach nicht woher die die größenangaben nimmt. Wenn ich die komponente auf Form ziehe, dann sind doch in den eigenschaften (dfm datei) die größen angegeben. Aber es scheint so als ob erst der konstruktor aufgerufen wird und dann die Eigenschaften ausliest!?

    So funktioniert es auf jeden fall nicht

    class TMyGraphic : public TGraphicControl
    {
    
    public:
    		std::vector<TDWShape*> Shapes;
    		TDWCircle *Kreis;
    		TDWSquare *Kreis2;
    		POINT points[5];
    public:
    
    	__fastcall TMyGraphic(TComponent* Owner) : TGraphicControl(Owner)
    	{
    		Shapes.resize(0);
    		Kreis = new TDWCircle;
    		Kreis2 = new TDWSquare;
    
                       //this->Align= alClient    bringt auch nichts  
    		Canvas->Brush->Color = clBlack;
    		points[0].x =  0;
    		points[0].y =  0;
    		points[1].x = Width -1;  //Whidth ist 0 warum???
    		points[1].y =  0;
    		points[2].x = Width -1;
    		points[2].y = Height -1;
    		points[3].x =  0;
    		points[3].y = Height -1;
    		points[4].x =  0;
    		points[4].y =  0;
    
        }
    ...
    };
    
    class PACKAGE TGundgrafik : public TWinControl
    {
    private:
    	TMyGraphic *MeineGrafik;
    
    public:
    	__fastcall TGundgrafik(TComponent* Owner) :TWinControl(Owner)
    	{
    	   this->Top=10;
    	   this->Left=10;
    	   this->Height=100;
    	   this->Width=200;
    
    		MeineGrafik = new TMyGraphic(this); 
    		MeineGrafik->Parent=this;
    		MeineGrafik->BoundsRect=this->BoundsRect; //hier übergebe ich die größe, aber der Konstruktor ist ja schon durchlaufen!? ist also was spät
    	}
    };
    


  • JBOpael schrieb:

    MeineGrafik->BoundsRect=this->BoundsRect; //hier übergebe ich die größe, aber der Konstruktor ist ja schon durchlaufen...
    

    Der Konstruktor wird schon zwei Zeilen vorher bei new TMyGraphic(this) aufgerufen.
    Damit sind die Werte im points-Array wirkungslos.

    Um das Array richtig zu füllen und auch bei Grössenänderungen aktuell zu halten, kannst du es in die WM_PAINT reinschreiben.

    Im übrigen rate ich dir, dich zum Thema Komponentenentwicklung weiter zu informieren. Vieles wird dir dann schon mal klarer.

    mfg
    kpeter



  • Woher bekomme ich den die infos über komponentenentwicklung? bei google finden man nur wenig infos darüber. und bücher zu dem thema hab ich auch keins gefunden.

    die meisten erwähnen nur das man eine eine neue komponete erstellen kann von z.B Tedit ableiten kann um dann kleinigkeiten zu ändern. Aber wenns tiefer in die Materie geht ist dann auch schon ende.

    die besten infos die ich bis jetzt gefunden habe kommen von hier :

    http://bcb-tutorial.c-plusplus.net/inhalt.html

    Ansonsten hab ich halt nur die möglichkeit im forum nach zu fragen. Mir wäre es auch lieber wenn ich eine quelle hätte wo ich mich genauer informieren kann.

    Bin dir deswegen echt dankbar das du mir soviele tips und hilfestellungen gegeben hast.



  • JBOpael schrieb:

    Woher bekomme ich den die infos über komponentenentwicklung?

    In der Dokumentation, Kapitel "Komponentenentwicklung".

    Falls du eine neuere Version als C++Builder 6 benutzt, lade die C++Builder 6-Hilfedateien hier herunter.


Anmelden zum Antworten