Do you want to develop a Paint like application on windows? In this project we will develop a simple paint application in Modern C++ for windows. Before this we would like to recommend you our previous posts about Bitmap Operations In C++ Builder (FireMonkey) and Quickly Learn How To Use Canvas Drawing In C++ On Windows.
This example is good to learn how to use graphics. When you code in C++ about graphics if you are doing drawings anims etc. you understand well how C++ is strong and faster on these operations. In this simple Paint example we will use C++ Builder. Here we go;
1. Create a new RAD Studio, C++ Builder Multi-Device FireMonkey Project. Save all Project and Units to MyPaintApp folder.
2. Drag a new Image (TImage) from Tools Palette on to your Form, Change WrapMode to Original, Position and size it, give some space (left side, right side or top etc.) for buttons. We will use its bitmap to draw on it.
3. Drag a another Image (TImage) from Tools Palette on to your Form, Change WrapMode to Original, Position on the previous Image in same Width and Height. We will use this as a transparent layer to draw things.
Now we will add some buttons to this space to draw things.
4. Add four Buttons from the Tools Palette right side, shape them like squares,
Change Text property of Button1 to “.” , this button will draw pixels,
Change Text property of Button2 to “/“, this button will draw lines,
Change Text property of Button3 to “[]“, this button will draw rectangles,
Change Text property of Button4 to “O“, this button will draw circles,
5. Add three more Buttons from the Tools Palette right side;
Change Text property of Button5 to “New“, this button will clear the Bitmap,
Change Text property of Button6 to “Load“, this button will load the Bitmap,
Change Text property of Button7 to “Save“, this button will save the Bitmap,
6. Now lets add two ComboColorBoxes to define Fill Brush Color and Bitmap Background colors. You can add Labels to show them as Pen and BackGround colors.
7. Add a TrackBar from the Tools Palette. We will use this to define Opacity level of Brush that we draw.
8. Add OpenDialog and SaveDialog components from the Tools Palette
9. Double click to Button1 to Buton4 add these lines respectively as below;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void __fastcall TForm1::Button1Click(TObject *Sender) { draw_mode=0; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { draw_mode=1; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button3Click(TObject *Sender) { draw_mode=3; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button4Click(TObject *Sender) { draw_mode=4; } |
10. Lets create a bitmap and copy it to form when form is being created. Change this Form line as below
1 2 3 4 5 6 7 8 9 10 |
//--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { bmp=new TBitmap(Image1->Width,Image1->Height); Image1->Bitmap->Assign(bmp); Image2->Bitmap->Assign(bmp); bmp->Free(); // we copied this and we don't need it, needs to be delete from the memory } |
11. Double to our “New” Button, write this line to clear bitmap();
1 2 3 4 5 6 |
void __fastcall TForm1::Button5Click(TObject *Sender) { Image1->Bitmap->Clear(ComboColorBox1->Color); } |
12. Double to “Load” and “Save” Buttons, and write these lines to load and save image;
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void __fastcall TForm1::Button6Click(TObject *Sender) { OpenDialog1->Execute(); Image1->Bitmap->LoadFromFile(OpenDialog1->FileName); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button7Click(TObject *Sender) { SaveDialog1->Execute(); Image1->Bitmap->SaveToFile(SaveDialog1->FileName); } |
13. Lets define some globals for this Form. To do this, we will change the header of this unit. Click to Unit1.h header tab at the bottom and add lines to public section as below;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
//--------------------------------------------------------------------------- #ifndef Unit1H #define Unit1H //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <FMX.Controls.hpp> #include <FMX.Forms.hpp> #include <FMX.Colors.hpp> #include <FMX.Objects.hpp> #include <FMX.Types.hpp> #include <FMX.Controls.Presentation.hpp> #include <FMX.StdCtrls.hpp> #include <FMX.Dialogs.hpp> //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // IDE-managed Components TImage *Image1; TComboColorBox *ComboColorBox1; TButton *Button1; TButton *Button2; TButton *Button3; TButton *Button4; TComboColorBox *ComboColorBox2; TButton *Button5; TButton *Button6; TButton *Button7; TOpenDialog *OpenDialog1; TSaveDialog *SaveDialog1; TTrackBar *TrackBar1; TImage *Image2; void __fastcall Button1Click(TObject *Sender); void __fastcall Button2Click(TObject *Sender); void __fastcall Button3Click(TObject *Sender); void __fastcall Button4Click(TObject *Sender); void __fastcall Button5Click(TObject *Sender); void __fastcall Button6Click(TObject *Sender); void __fastcall Button7Click(TObject *Sender); void __fastcall Image2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, float X, float Y); void __fastcall Image2MouseMove(TObject *Sender, TShiftState Shift, float X, float Y); void __fastcall Image2MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, float X, float Y); private: // User declarations public: // User declarations __fastcall TForm1(TComponent* Owner); void __fastcall DrawbyMouse(TCanvas *C, float X, float Y); TBitmap *bmp; int LX, LY, draw_mode=0; bool drawing=false; }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif |
Here we defined new public variables and functions.
LX and LY are to remember Last X and Y positions of mouse when mouse down.
draw_mode is to define tool number
drawing is to know if mouse is pressed and we are drawing to transparent image (Image2), finally will draw to the backward image (Image1) when mouse is up.
14. Now let’s Go back to Unit1.cpp by clicking Unit1.cpp tab at the bottom. Let’s define our DrawbyMouse(…) drawing function as below. , add this to the end of Unit1.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
//--------------------------------------------------------------------------- void __fastcall TForm1::DrawbyMouse(TCanvas *C, float X, float Y) { float opacity = TrackBar1->Value/100.0; // opacity is between 0 to 1.0 C->Stroke->Color=ComboColorBox2->Color; C->Fill->Color =ComboColorBox2->Color; C->Fill->Kind=TBrushKind::bkSolid; C->BeginScene(); // start to draw on canvas switch(draw_mode) { case 0: C->DrawLine( TPointF(X,Y), TPointF(X+1,Y), opacity); break; case 1: C->DrawLine( TPointF(LX,LY), TPointF(X,Y), opacity); break; case 2: C->FillRect( TRectF(LX,LY,X,Y), 0,0, AllCorners, opacity); break; case 3: C->FillEllipse( TRectF(LX,LY,X,Y), opacity); break; } C->EndScene(); // we finish all drawings, now lets display the final } |
15. Finally we will draw selected thing by using mouse. Note that Image2 is a transparent bitmap over Image1. Technique here is; we will get mouse down, move and up events from Image2. When we click first we will get LX and LY positions and we set drawing=true; . When mouse button is being pressed ( if(drawing==true) ) we will keep drawing to this transparent Image2 bitmap. When mouse is up, finally we will draw the final shape to Image1 bitmap.
To do all these operations, we need Down, Up and Move Mouse events. Go to Image2 Event Properties, double click to OnMouseDown, OnMouseMove and OnMouseUp events. And modify lines as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
void __fastcall TForm1::Image2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, float X, float Y) { LX= X; LY= Y; drawing=true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Image2MouseMove(TObject *Sender, TShiftState Shift, float X, float Y) { if(drawing) { Image2->Bitmap->Clear(0x0); DrawbyMouse(Image2->Bitmap->Canvas, X, Y); } } //--------------------------------------------------------------------------- void __fastcall TForm1::Image2MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, float X, float Y) { if(drawing) { Image2->Bitmap->Clear(0x0); DrawbyMouse(Image1->Bitmap->Canvas, X, Y); drawing=false; } } |
16. Now we can run by Run , Run with Debugging or by Hitting F9
Final Words
When you learn basics of C++ Builder it is very easy to develop applications in Modern C++. C++ is very fast on these operations. It’s FireMonkey framework is very powerful to use bitmaps, transparency. It has many tools, color components. You can also make your applications glorious by using many shiny Styles on Forms and components.
In this technique we clear the whole transparent Image2 on on MouseMove event. Professionally you should clean and draw the only part of changes.