Drawing shapes in runtime

AnissGharib49

Member
Joined
May 24, 2021
Messages
8
Programming Experience
Beginner
I have a Form to developp.i want to draw some shapes on the panel in the form . The size of the shape depend on users Mouse Down/Up and from any point in any direction on the drawing panel. I dont want drawed shapes getting from button event click that get showed on the panel ( i already code it) i want that the user could draw this shapes in the runtime
 
So track the Mouse Down, Mouse Move, and Mouse Up events. I don't see what the problem is. If you know how to handle a Mouse Click event, then you would also know how to handle the other mouse events.
 
C#:
public partial class Form1 : Form
    {
        int x;
        int y;
        Graphics graphics;
        Color col = Color.Red;
        public int X { get {return x; } set { x = value; } }
        public int Y { get { return y; } set { y = value; } }
        public new int Height { get; set; }
        public int Weight { get; set; }
        public float WidthPen { get; set; }
        public Color DrwaingColor { get { return col; } set { col = value; Invalidate(); } }

        Pen pen = new Pen(Color.Red, 3);
        public Form1()
        {
            InitializeComponent();
            DoubleBuffered = true;
        }

        private void drawPagepanel_MouseDown(object sender, MouseEventArgs e)
        {
            x = e.X;
            y = e.Y;
        }
              
        private void drawPagepanel_MouseUp(object sender, MouseEventArgs e)
        {
            Height = e.X;
            Weight = e.Y;
            if (FullyXCrossShapeRb.Checked)
            {

                using (graphics = drawPagepanel.CreateGraphics())
                {
                    graphics.SmoothingMode = SmoothingMode.HighQuality;
                    graphics.DrawLine(pen, new Point(Height, Weight), new Point(Height + 30, Weight));
                    graphics.DrawLine(pen, new Point(Height, Weight), new Point(Height +30, Weight +30));
                    graphics.DrawLine(pen, new Point(Height+30, Weight), new Point(Height, Weight + 30));
                    graphics.DrawLine(pen, new Point(Height + 30, Weight+30), new Point(Height, Weight+30));

                }

            }
            if (DoubleTriangleSetShapeRb.Checked)
            {

                using (graphics = drawPagepanel.CreateGraphics())
                {
                   //To Do
                }

            }


        }
 
Last edited by a moderator:
Don't just post code with no explanation. Are you suggesting that that code is the solution to your problem? Are you suggesting that that code is your attempt but it doesn't achieve your aim? We shouldn't have to read the code to work that out. Use your words. Don't expect us to do anything that can be avoided by you providing an explanation. ALWAYS do everything you can to help us help you.
 
That said, there's a major problem with that code at the outset. NEVER call CreateGraphics. The way GDI+ drawing on controls should ALWAYS work is like this:
  1. Store the data that represents the drawing in one or more fields.
  2. Handle the Paint event of the control you want to draw on and use the Graphics object provided to draw using the data in those fields.
  3. When you want to change the drawing, modify the data in those fields and call the Invalidate method of the control you want to draw on.
The Invalidate method tells the control to raise a Paint event, so the drawing will get updated based on the new data.

The reason that you need to handle the Paint event is that GDI+ drawing gets erased and repainted each time that event is raised. If you call CreateGraphics and draw once, that drawing will likely get erased on the next Paint event and those events happen regularly.

Note that, while it may be simpler to call Invalidate with no arguments, you should generally invalidated the smallest area possible to include the area(s) that have (or may have) changed in the drawing. That's because, while the entire drawing gets performed each time, only the pixels in the invalidated area get repainted because it's the actual repainting that is the slow part. When you see a control flickering, that's because it is being repainted in its entirety too often.

Here's a simple example of drawing boxes on a form:
C#:
private readonly List<Rectangle> boxes = new();
private Point? startPoint = null;

private void Form1_MouseDown(object sender, MouseEventArgs e)
{
    startPoint = e.Location;
}

private void Form1_MouseUp(object sender, MouseEventArgs e)
{
    if (this.startPoint.HasValue)
    {
        // Create a box within the bounds of the points at which the user depressed and released the mouse button.
        var startPoint = this.startPoint.Value;
        var endPoint = e.Location;
        var box = new Rectangle(Math.Min(startPoint.X, endPoint.X),
                                Math.Min(startPoint.Y, endPoint.Y),
                                Math.Abs(startPoint.X - endPoint.X),
                                Math.Abs(startPoint.Y - endPoint.Y));

        boxes.Add(box);

        // We must invalidate the area of the box plus an extra pixel down and to the right.
        var invalidationBox = new Rectangle(box.X,
                                            box.Y,
                                            box.Width + 1,
                                            box.Height + 1);

        // Force a repaint.
        Invalidate(invalidationBox);
    }
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
    // Draw all boxes every time.
    foreach (var box in boxes)
    {
        e.Graphics.DrawRectangle(Pens.Black, box);
    }
}
 
That said, there's a major problem with that code at the outset. NEVER call CreateGraphics. The way GDI+ drawing on controls should ALWAYS work is like this:
  1. Store the data that represents the drawing in one or more fields.
  2. Handle the Paint event of the control you want to draw on and use the Graphics object provided to draw using the data in those fields.
  3. When you want to change the drawing, modify the data in those fields and call the Invalidate method of the control you want to draw on.
The Invalidate method tells the control to raise a Paint event, so the drawing will get updated based on the new data.

The reason that you need to handle the Paint event is that GDI+ drawing gets erased and repainted each time that event is raised. If you call CreateGraphics and draw once, that drawing will likely get erased on the next Paint event and those events happen regularly.

Note that, while it may be simpler to call Invalidate with no arguments, you should generally invalidated the smallest area possible to include the area(s) that have (or may have) changed in the drawing. That's because, while the entire drawing gets performed each time, only the pixels in the invalidated area get repainted because it's the actual repainting that is the slow part. When you see a control flickering, that's because it is being repainted in its entirety too often.

Here's a simple example of drawing boxes on a form:
C#:
private readonly List<Rectangle> boxes = new();
private Point? startPoint = null;

private void Form1_MouseDown(object sender, MouseEventArgs e)
{
    startPoint = e.Location;
}

private void Form1_MouseUp(object sender, MouseEventArgs e)
{
    if (this.startPoint.HasValue)
    {
        // Create a box within the bounds of the points at which the user depressed and released the mouse button.
        var startPoint = this.startPoint.Value;
        var endPoint = e.Location;
        var box = new Rectangle(Math.Min(startPoint.X, endPoint.X),
                                Math.Min(startPoint.Y, endPoint.Y),
                                Math.Abs(startPoint.X - endPoint.X),
                                Math.Abs(startPoint.Y - endPoint.Y));

        boxes.Add(box);

        // We must invalidate the area of the box plus an extra pixel down and to the right.
        var invalidationBox = new Rectangle(box.X,
                                            box.Y,
                                            box.Width + 1,
                                            box.Height + 1);

        // Force a repaint.
        Invalidate(invalidationBox);
    }
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
    // Draw all boxes every time.
    foreach (var box in boxes)
    {
        e.Graphics.DrawRectangle(Pens.Black, box);
    }
}
Thank u so much for ur Effort but i think u dont understand me wht i am going to say the punkt is the the drawing prosess is dynamic not to define the form/size of shape the direction nooo at all its depend on the user and wht he want from any point (mouseDown) from any direction( right *Top/left*bottom) its must be drawed with the event mouseMove event and not with mouseDown and u have a drwaed shape in front of your eyes ! The result what your code product, I'd it already .i had comment this in the previous Comment i dont want this .In my code that i ve poste before , i draw the shapes but the user could not custum his own shape , so i am looking to make it better.
 
Do you want the user to draw the lines that define the shape?

Or is there a fixed shape (from a set of possible shapes) that you want to scale up or down depending on how the user moves the mouse?
 
Do you want the user to draw the lines that define the shape?

Or is there a fixed shape (from a set of possible shapes) that you want to scale up or down depending on how the user moves the mouse?
 

Attachments

  • Screenshot_20210813-183737_Office.jpg
    Screenshot_20210813-183737_Office.jpg
    169.5 KB · Views: 24
Back
Top Bottom