c++vclc++builder-xe5

How to implement OnClick, OnMouseDown, OnMouseUp Events of a new component created from TPaintBox?


I am trying to create a new component from the TPaintBox. New component size is Rect(0,0,160,248). I drew two rectangles on newly component and I would like to implement events to each of above rectangle.

Get rectangle is located at Rect(102,43,157,63) and I would like to implement events like OnGetClick , OnGetMouseDown , OnGetMouseUp for this rectangle area .

Set rectangle is located at Rect(102,69,157,89) and I would like to implement events like OnSetClick, OnSetMouseDown, OnSetMouseUp for this rectangle area.

Rest of the new component area is going display values related to the VGauge and I am not included in below code.

class PACKAGE TVGauge : public TPaintBox
{
   public:
     virtual void __fastcall Paint(void) ;
};
void __fastcall TVGauge::Paint(void)
{
  int ind1, ind2 ;
  TRect tempR ;
  String str;
  Canvas->Font->Size  = 8 ;

  //whole rect
  Canvas->Pen->Color        = clSilver ;
  Canvas->Brush->Color      = clBtnFace ;
  Canvas->Rectangle(ClientRect) ; //Rect(0,0,160,248)

  //----------
  Canvas->Pen->Color    = clMedGray ;
  Canvas->Font->Color   = clWindowText ;
  Canvas->Brush->Color  = clWhite ;

  //Get Button ; draw a rectangle and it should act like a button
  Canvas->Rectangle(102 , 43  , 157 , 63 ) ;
  Canvas->TextOut(112,  48 ,L"Get");

  //Set Button ; draw a rectangle and it should act like a button
   Canvas->Rectangle(102 , 69  , 157 , 89 ) ;
   Canvas->TextOut(112,  74 ,L"Set");

  //display values related to the VGauge 
  //..
  //..

   if(OnPaint != NULL)  OnPaint(this) ;
}

I don't have any idea, how to implement above events for a new component. So, I am hoping to get suggestions to implement this component.


Solution

  • Override the virtual MouseDown() and MouseUp() methods, eg:

    enum TVGaugeButton { tvgGetBtn, tvgSetBtn };
    
    typedef void __fastcall (__closure *TVGaugeMouseEvent)(TObject *Sender, TVGaugeButton GaugeButton, TMouseButton MouseButton, TShiftState Shift, int X, int Y);
    typedef void __fastcall (__closure *TVGaugeClickEvent)(TObject *Sender, TVGaugeButton GaugeButton);
    
    class PACKAGE TVGauge : public TPaintBox
    {
        typedef TPaintBox inherited;
    
    private:
        bool FMouseDown[2];
    
        TVGaugeMouseEvent FOnGaugeButtonMouseDown;
        TVGaugeMouseEvent FOnGaugeButtonMouseUp;
        TVGaugeClickEvent FOnGaugeButtonClick;
    
        TRect __fastcall GetButtonRect(TVGaugeButton WhichButton);
    
    protected:
        DYNAMIC void __fastcall MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y);
        DYNAMIC void __fastcall MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y);
        virtual void __fastcall Paint();
    
    public:
        __fastcall TVGauge(TComponent *Owner);
    
        virtual void __fastcall SetBounds(int ALeft, int ATop, int AWidth, int AHeight);
    
    __published:
        __property TVGaugeClickEvent OnGaugeButtonClick = {read=FOnGaugeButtonClick, write=FOnGaugeButtonClick};
        __property TVGaugeMouseEvent OnGaugeButtonMouseDown ={read=FOnGaugeButtonMouseDown, write=FOnGaugeButtonMouseDown};
        __property TVGaugeMouseEvent OnGaugeButtonMouseUp = {read=FOnGaugeButtonMouseUp, write=FOnGaugeButtonMouseUp};
    };
    

    __fastcall TVGauge::TVGauge(TComponent *Owner)
        : TPaintBox(Owner)
    {
    }
    
    void __fastcall TVGauge::SetBounds(int ALeft, int ATop, int AWidth, int AHeight)
    {
        inherited::SetBounds(ALeft, ATop, 160, 248);
    }
    
    TRect __fastcall TVGauge::GetButtonRect(TVGaugeButton WhichButton)
    {
        switch (WhichButton)
        {
            case tvgGetBtn:
                return Rect(102, 43, 157, 63);
    
            case tvgSetBtn:
                return Rect(102, 69, 157, 89);
        }
    
        return Rect(0, 0, 0, 0);
    }
    
    void __fastcall TVGauge::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y)
    {
        inherited::MouseDown(Button, Shift, X, Y);
    
        for (int i = tvgGetBtn; i <= tvgSetBtn; ++i)
        {
            TVGaugeButton myBtn = (TVGaugeButton) i;
    
            TRect r = GetButtonRect(myBtn);
            if (PtInRect(&r, Point(X, Y)))
            {
                if (Button == mbLeft)
                    FMouseDown[i] = true;
    
                if (FOnGaugeButtonMouseDown)
                    FOnGaugeButtonMouseDown(this, myBtn, Button, Shift, X-r.Left, Y-r.Top);
    
                break;
            }
        }
    }
    
    void __fastcall TVGauge::MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y)
    {
        inherited::MouseDown(Button, Shift, X, Y);
    
        for (int i = tvgGetBtn; i <= tvgSetBtn; ++i)
        {
            TVGaugeButton myBtn = (TVGaugeButton) i;
    
            TRect r = GetButtonRect(myBtn);
            if (PtInRect(&r, Point(X, Y)))
            {
                bool bClicked = false;
    
                if (Button == mbLeft)
                {
                    FMouseDown[i] = false;
                    bClicked = true;
                }
    
                if (FOnGaugeButtonMouseUp)
                    FOnGaugeButtonMouseUp(this, myBtn, Button, Shift, X-r.Left, Y-r.Top);
    
                if ((bClicked) && (FOnGaugeButtonClick))
                    FOnGaugeButtonClick(this, myBtn);
    
                break;
            }
        }
    }
    
    void __fastcall TVGauge::Paint()
    {
        TRect tempR;
    
        Canvas->Font->Size = 8;
    
        //whole rect
        Canvas->Pen->Color = clSilver;
        Canvas->Brush->Color = clBtnFace;
        Canvas->Rectangle(ClientRect);
    
        //----------
        Canvas->Pen->Color = clMedGray;
        Canvas->Font->Color = clWindowText;
        Canvas->Brush->Color = clWhite;
    
        //Get Button ; draw a rectangle and it should act like a button
        tempR = GetButtonRect(tvgGetBtn);
        Canvas->Rectangle(tempR);
        Canvas->TextRect(tempR, tempR.Left + 10, tempR.Top + 5, _D("Get"));
    
        //Set Button ; draw a rectangle and it should act like a button
        tempR = GetButtonRect(tvgSetBtn);
        Canvas->Rectangle(tempR);
        Canvas->TextRect(tempR, tempR.Left + 10, tempR.Top + 5, _D("Set"));
    
        //display values related to the VGauge 
        //..
        //..
    
        if (OnPaint)
            OnPaint(this);
    }
    

    On a side note, you really should derive your component from TGraphicControl directly instead of from TPaintBox. The only difference between TPaintBox and TGraphicControl is that TPaintBox exposes an OnPaint event, where it overrides Paint() to trigger OnPaint. You don't really need the OnPaint event in your component at all, since you are doing all of your own painting (unless you really want users drawing over top of our painting).