简体   繁体   中英

Draw MS Paint User defined Rectangle on mouse move

I'm now working with drawing some shapes on PANEL in C#. I have a problem with updating the current graphics. In other words I don't know how to create a current stage (where I will draw the current, let's say Rectangle) and draw it on Panel. I can draw a rectangle on Mouse_down event of Panel. But how to show the current Rectangle on Mouse_move Event, after the Mouse is pressed on Panel??? I don't want to use Invalidate . Because it clears all the panel drawing that were made before. Help me to show the current Rectangle shape when MOUSE IS MOVED , and draw it on Panel ONLY AFTER MOUSE IS RELEASED.

Pen p_white = new Pen(new SolidBrush(Color.White), pen_thickness);
int w1 = Math.Abs(starx - curx); int h1 = Math.Abs(stary - cury);
Rectangle rec_new = new Rectangle(starx, stary - h1, w1, h1);
gpath.Reset();
gpath.AddRectangle(rec_new);// code that adds Rectangle in MOUSE_MOVE EVENT

g.DrawPath(p, gpath); 
// Drawing the rectangle on Mouse Release Event. g was already binded to Panel.CreateGraphics 

You have to use Invalidate() to call the Paint method.

And you have to move all your drawing there! so this line

g.DrawPath(p, gpath);

goes into the Paint event like this:

e.Graphics.DrawPath(p, gpath);

Since you are building up a GraphicsPath this is a small change. If you build up your drawing like if you create more GraphicsPaths, they all must be drawn there.

You cannot build up a drawing by drawing repeatedly on the panel like you would on paper; you must somehow store the draw actions. This sound tedious but here you really have to move just the one line.

And: as you progress it will give you the chance for unlimited undos, scaling etc..

See this note from MSDN :

Windows Forms controls do not support true transparency. The background of a transparent Windows Forms control is painted by its parent.

Unfortunately this means that we can't do this the simple way - by putting a transparent image control of some sort over another control. WinForms doesn't do it.

One method I've used is to do all temporary drawing (selections, incomplete drawings, etc) inside a 'foreground' buffer, and use the Paint event of the background image control to draw the temporary objects as needed.

Given a PaintBox control that contains the image, you can use the Paint event to draw the foreground buffer as required, giving full transparency options.

public partial class Form1 : Form
{
    public Bitmap Foreground;

    public Form1()
    {
        InitializeComponent();

        // Create foreground buffer same size as picture box
        Foreground = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

        // Draw a blue ellipse in the foreground buffer for something to see
        using (var g = Graphics.FromImage(Foreground))
        {
            g.Clear(Color.Transparent);
            g.DrawEllipse(Pens.Blue, 10, 10, 300, 100);
        }
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.DrawImage(Foreground, 0, 0);
    }
}

Assuming your picture box has something in it, this will draw a Blue ellipse over the top of it.

Whenever you want to change the overlaid foreground image you need to ensure that the PaintBox control will be redrawn. Use the Invalidate method to tell Windows that the control needs to be repainted.

Some more code:

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter)
        {
            e.SuppressKeyPress = true;
            e.Handled = true;

            // draw foreground to background
            using (var g = Graphics.FromImage(pictureBox1.Image))
                g.DrawImage(Foreground, 0, 0);

            // clear foreground
            using (var g = Graphics.FromImage(Foreground))
                g.Clear(Color.Transparent);
        }
        else if (e.KeyCode == Keys.Space)
        {
            e.SuppressKeyPress = true;
            e.Handled = true;

            // a random number source - probably better at form level
            var rnd = new Random();

            // draw a new random ellipse
            using (var g = Graphics.FromImage(Foreground))
            {
                g.Clear(Color.Transparent);
                g.DrawEllipse(Pens.Red, 0, 0, 30 + rnd.Next(500), 30 + rnd.Next(500));
            }

            // tell Windows to redraw the paintBox to show new foreground image
            pictureBox1.Invalidate();
        }
    }

Pressing Enter commits the foreground buffer to the image in the PaintBox , pressing Space generates a random new red ellipse in the foreground buffer.

The same base technique can be used for all sorts of things, like pasting images to specific locations (paste into and move around in the foreground buffer, then copy foreground on top of background when done), showing selection objects, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM