DEV Community

Andris Jansons
Andris Jansons

Posted on

Windows Forms Paint effect (C++)

Simulating a looping function while mouse is pressed

Microsoft paint kind of style:

What this function does is - it makes your function run every 10ms for example while working with Windows forms. Since such an event does not directly exist within the Windows Forms, we can achieve the same result using a few different ones together.

World maker

There are 2 scenarios:

  • Either draw on the grid clicking one pixel at a time with the regular MouseEventHandler(this, &project::panel1_MouseClick);(I know it does not seem as bad on such huge pixels);
  • Or, click and drag for as long as you wish to achieve continuous line (Let me show you how).

For this we are going to need 3 events, although the last one is optional:


this->panel1->MouseDown += gcnew System::Windows::Forms::MouseEventHandler(this, &frmAdventrureMap::panel1_MouseDown);
this->panel1->MouseUp += gcnew System::Windows::Forms::MouseEventHandler(this, &frmAdventrureMap::panel1_MouseUp);
this->panel1->MouseMove += gcnew System::Windows::Forms::MouseEventHandler(this, &frmAdventrureMap::panel1_MouseMove);
Enter fullscreen mode Exit fullscreen mode

And a timer:

private: System::Windows::Forms::Timer^  timerMouseDrag;
this->timerMouseDrag = (gcnew System::Windows::Forms::Timer(this->components));
//Let's add a tick event
this->timerMouseDrag->Tick += gcnew System::EventHandler(this, &frmAdventrureMap::timerMouseDrag_Tick);
//And specify the interval
this->timerMouseDrag->Interval = 10;
Enter fullscreen mode Exit fullscreen mode

To anyone just using Visual Studio Design View, this can not become any easier:
Visual Studio Properties


Now to the fun part

Some of you may already see where I am going with this, because what's left is just 2 lines of code:

private: System::Void panel1_MouseDown(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) 
{
//Mouse pressed - Start the timer
    timerMouseDrag->Start();
}

private: System::Void panel1_MouseUp(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) 
{
//Mouse released - Stop the timer
    timerMouseDrag->Stop();
} 
Enter fullscreen mode Exit fullscreen mode

And finally:

private: System::Void timerMouseDrag_Tick(System::Object^  sender, System::EventArgs^  e) 
{
    //Your code here (This is where I make the drawing happen)
}
Enter fullscreen mode Exit fullscreen mode

That is it! "Simplicity is the ultimate sophistication."(Leonardo da Vinci)

But let's take this a step further

Remember the mouse move event we initialized earlier?
We use that one to pass our mouse position to our timer event or any other function we might call.
Simply creating a private attribute of MouseEventArgs^ or just assigning mouse x and y position:

private:
    System::Windows::Forms::MouseEventArgs^ mouse;
    //or
    int x, y;
Enter fullscreen mode Exit fullscreen mode

And updating them each time MouseMove happens:

private: System::Void panel1_MouseMove(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) 
    {
    mouse = e;
    //Or
    x = e->X;
    y = e->Y;
    }
Enter fullscreen mode Exit fullscreen mode

To anyone thinking the same could be done without the timer but inside the MouseMove event - You're totally right, but what you are missing is the simple option to choose your preferred interval, furthermore MouseMove happens all the time, while our timer is working only when mouse is pressed.

In the end of the day, each and every project has its own methods it works best with.

Hope this helped someone or raised some new ideas, and if so, feel free to comment below.

Top comments (1)

Collapse
 
jansonsa profile image
Andris Jansons

This is my first tutorial, so constructive criticism would be much appreciated. :)