4

I need help with a problem that I don't know how to solve it. I have my own class that extends from PictureBox, I can show my rectangle correctly and I can move it without problems.

But when I try to draw a circle arround the rectangle, I have a problem. I want to draw the circle when the users make a mouseclickevent. It draws a circle, but on the rectangle. I don't know if you understand me... I put my code below and also the results that I have and the results that I want to have.

My code:

OnClick event:

//Métodos para mover la unidad
    bool unidadPulsada = false;
    private Point MouseDownLocation;
    protected override void OnMouseDown(MouseEventArgs e)
    {
        unidadPulsada = true;
        base.OnMouseDown(e);
        MouseDownLocation = e.Location;
        DibujarLimites();
    }

Method that set the pictureBox:

public void Colocar(Control control, Unidad unidad, Point p)
    {
        unidad.Location = p;
        control.Controls.Add(unidad);
    }

Methods that draw:

public void DibujarLimites()
    {
        using (Graphics g = CreateGraphics())
        {
            using (Pen pen = new Pen(Color.Red, 2))
            {
                float[] dashValues = { 5, 2, 15, 4 };
                pen.DashPattern = dashValues;
                DrawCircle(g, pen, 0, 0, 20);
            }
        }
    }

    public void DrawCircle(Graphics g, Pen pen, float centerX, float centerY, float radius)
    {
        g.DrawEllipse(pen, centerX - radius, centerY - radius,
                      radius + radius, radius + radius);
    }

The results I have: The left rectangle is the pictureBox with the circle draw on it. The right rectangle is the pictureBox without the circle, the original rectangle. enter image description here

The results I want to have: The circle drawed arround the rectangle.

enter image description here

EDIT for Youri:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
using WHF.Properties;

namespace WHF
{
public class Unidad : PictureBox
{
    //Constructor
    public Unidad(string nombre, string tipo, int movimiento, int ha, int hp, int fuerza, int resistencia, int heridas, int iniciativa, int ataques, int liderazgo, int coste, string rutaImagen)
    {
        tipoUnidad = tipo;
        movimientoUnidad = movimiento;
        nombreUnidad = nombre;
        costeUnidad = coste;
        haUnidad = ha;
        hpUnidad = hp;
        fuerzaUnidad = fuerza;
        resistenciaUnidad = resistencia;
        iniciativaUnidad = iniciativa;
        ataquesUnidad = ataques;
        liderazgoUnidad = liderazgo;
        rutaImagenUnidad = rutaImagen;
    }

    //Propiedades
    public string nombreUnidad { get; set; }
    public string tipoUnidad { get; set; }
    public int movimientoUnidad { get; set; }
    public int costeUnidad { get; set; }
    public int haUnidad { get; set; }
    public int hpUnidad { get; set; }
    public int fuerzaUnidad { get; set; }
    public int resistenciaUnidad { get; set; }
    public int heridasUnidad { get; set; }
    public int iniciativaUnidad { get; set; }
    public int ataquesUnidad { get; set; }
    public int liderazgoUnidad { get; set; }
    public string rutaImagenUnidad { get; set; }

    //Método para dibujar unidad
    public void Colocar(Control control, Unidad unidad, Point p)
    {
        unidad.Location = p;
        control.Controls.Add(unidad);
    }


    //Métodos para mover la unidad
    bool unidadPulsada = false;
    private Point MouseDownLocation;
    protected override void OnMouseDown(MouseEventArgs e)
    {
        unidadPulsada = true;
        base.OnMouseDown(e);
        MouseDownLocation = e.Location;
        //DibujarLimites();

        float x = Location.X + e.X;
        float y = Location.Y + e.Y;

        Graphics graphics = CreateGraphics();

        PointF center = new PointF(x, y);//this.ClientSize.Width / 2F, this.ClientSize.Height / 2F);
        float radius = 100;

        PointF rectOrigin = new PointF(center.X - radius, center.Y - radius);
        RectangleF r = new RectangleF(rectOrigin, new SizeF(radius * 2F, radius * 2F));

        using (Pen p = new Pen(Color.Red, 4))
        {
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            graphics.DrawEllipse(p, r);
        }
    }
    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        if (unidadPulsada)
        {
            Left = e.X + Left - MouseDownLocation.X;
            Top = e.Y + Top - MouseDownLocation.Y;
        }
    }
    protected override void OnMouseUp(MouseEventArgs e)
    {
        unidadPulsada = false;
        base.OnMouseDown(e);
        LimpiarLimites();
    }

    //Método para dibujar la zona límite de movimiento de la unidad
    public void DibujarLimites()
    {
        using (Graphics g = CreateGraphics())
        {
            using (Pen pen = new Pen(Color.Red, 2))
            {
                float[] dashValues = { 5, 2, 15, 4 };
                pen.DashPattern = dashValues;
                DrawCircle(g, pen, 0, 0, 20);
            }
        }
    }

    //Método para limpiar el dibujo de la zona límite
    public void LimpiarLimites()
    {

    }

    public void DrawCircle(Graphics g, Pen pen, float centerX, float centerY, float radius)
    {
        g.DrawEllipse(pen, centerX - radius, centerY - radius, radius + radius, radius + radius);
    }

    public void FillCircle(Graphics g, Brush brush, float centerX, float centerY, float radius)
    {
        g.FillEllipse(brush, centerX - radius, centerY - radius, radius + radius, radius + radius);
    }
}
}
Imrik
  • 674
  • 2
  • 14
  • 32
  • See [this](http://stackoverflow.com/questions/42274719/c-sharp-draw-circle-around-label/42275309#42275309). – Berkay Yaylacı Mar 06 '17 at 14:38
  • Do you want the circle be drawn on your `PicureBox` or around it? – Reza Aghaei Mar 06 '17 at 14:42
  • Around it, it doesn't move with the pictureBox. I want it to see the limit zone of movement of the pictureBox. – Imrik Mar 06 '17 at 14:43
  • So if you want to see it around the `PictureBox` then you need to paint over its parent surface instead of drawing over the control. – Reza Aghaei Mar 06 '17 at 14:45
  • Yes, but I need to draw it when the user make a mouseclickevent on the picture box, and that event is on my Unidad.cs class. Unidad extends pictureBox. – Imrik Mar 06 '17 at 14:46
  • I put more code on the question, hope it helps. – Imrik Mar 06 '17 at 14:48
  • Instead of using a `PictureBox` I recommend to create a custom `Shape` class (and different implementations like `PictureShape` and so on) then draw all shapes which you want on a drawing surface. – Reza Aghaei Mar 06 '17 at 14:50
  • Here is an example: [How can I treat the circle as a control after drawing it? - Moving and selecting shapes](http://stackoverflow.com/q/38345828/3110834). Another one: [How to drag and move shapes in C#](http://stackoverflow.com/q/38747027/3110834) or Another one: [How to save shapes which I draw on a Panel as binary](http://stackoverflow.com/q/40575663/3110834) providing save feature for drawing surface. – Reza Aghaei Mar 06 '17 at 14:52
  • let see, thanks! :) – Imrik Mar 06 '17 at 14:56
  • Also take a look at this example: [In C# Winforms is there a way to put dotted border around all controls and show grip points upon selection of specific controls at runtime?](http://stackoverflow.com/a/40209045/3110834) – Reza Aghaei Mar 06 '17 at 15:01

3 Answers3

1

Okay here is an example, I tried to apply the same way as you did, I have created my own picture box,

class MyPBox : PictureBox
    {
    public MyPBox()
    {
        this.BackColor = Color.Red; // for see better
        this.Location = new Point(50, 50); // set location at form

    }
    protected override void OnPaint(PaintEventArgs pe)
    {
        if (this.Parent != null)
        {
            this.Parent.Paint += Parent_Paint; // picturebox's paint means it added to parent so we need to trigger parent's paint event
        }
        base.OnPaint(pe);

    }
    bool clickPerformed = false; // to catch control has mouse down
    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        clickPerformed = true; // set mouse down
        Control tempSender =  this.Parent; // get sender
        tempSender.Invalidate(); // invalidate to trigger paint event

    }

    private void Parent_Paint(object sender, PaintEventArgs e)
    {
        if (clickPerformed)
        {
            using (Graphics g = e.Graphics)
            {
                using (Pen pen = new Pen(Color.Black, 2))
                {
                    float locationX = this.Location.X + this.Size.Width / 2;
                    float locationY = this.Location.Y + this.Size.Height / 2;
                    float radius = (this.Size.Height + this.Size.Width) / 2;

                    float[] dashValues = { 5, 2, 15, 4 };
                    pen.DashPattern = dashValues;
                    DrawCircle(g, pen, locationX
                        , locationY
                        , radius); // draw circle 
                    clickPerformed = false; // process done so set it to false
                }
            }
        }
        base.OnPaint(e);

    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        this.Parent.Invalidate(); // mouse up circle should be erased, so invalidate again to trigger paint, but this time clickPerformed is false
        // so it won't draw circle again
        base.OnMouseDown(e);
    }
    public void DrawCircle(Graphics g, Pen pen, float centerX, float centerY, float radius)
    {
        g.DrawEllipse(pen, centerX - radius, centerY - radius, radius + radius, radius + radius);
    }

}

Result(I am clicking on picturebox btw :) );

enter image description here

Hope helps,

Berkay Yaylacı
  • 4,383
  • 2
  • 20
  • 37
0

Put this in your onclick event of the picturebox and you should be fine

float x = Location.X + e.X;
float y = Location.Y + e.Y;

Form form = (Form)this.FindForm();
Graphics graphics = form.CreateGraphics();

PointF center = new PointF(x, y);//this.ClientSize.Width / 2F, this.ClientSize.Height / 2F);
float radius = 100;

PointF rectOrigin = new PointF(center.X - radius, center.Y - radius);
RectangleF r = new RectangleF(rectOrigin, new SizeF(radius * 2F, radius * 2F));

using (Pen p = new Pen(Color.Blue, 4))
{
     p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
     graphics.DrawEllipse(p, r);
}
Youri Leenman
  • 228
  • 2
  • 8
  • No, I explain it better on the edited question. I want to draw a circle when the users make a mouseclickevent and this event is on myUnidad.cs class, that extends pictureBox. So I can't solve with your answer because it draws the circle into the pictureBox, no? – Imrik Mar 06 '17 at 14:49
  • I try it, but I can't see anything. I mean, I think it doesn't draw the circle or I can't see it drawed. Can you help me? – Imrik Mar 06 '17 at 15:11
  • I can see the circle now. It is a little part of a complete circle on the bottom right corner of the picture box. It is on the picture box, not outside. – Imrik Mar 06 '17 at 15:13
  • Could you post the method where you implemented my code? – Youri Leenman Mar 06 '17 at 15:14
  • Yes, you have it on the question. Thanks! – Imrik Mar 06 '17 at 15:16
  • I see. It might have to do with the fact that you use "Location" instead of "PictureBox.Location" cause "Location" stands for the x and y coordinates of the form and not the picturebox control – Youri Leenman Mar 06 '17 at 15:20
  • OK. How can I take the pictureBox location? I don't know. – Imrik Mar 06 '17 at 15:25
  • I mean, I have the unidad.Location property, but I cannot know it on this other method and I can't pass the unidad value throught these method. – Imrik Mar 06 '17 at 15:26
  • You can get the sender. I will show this in my answer – Youri Leenman Mar 06 '17 at 15:27
  • I see your answer, I know what do you mean but I haven't got a sender on my method: protected override void OnMouseDown(MouseEventArgs e) – Imrik Mar 06 '17 at 15:32
  • I see. I believe you could change `protected override void OnMouseDown(MouseEventArgs e)` to `protected override void OnMouseDown(object sender, MouseEventArgs e)` but if you can't maybe you canuse `this.Location` – Youri Leenman Mar 06 '17 at 15:37
  • If none of the above work please post your whole extended picturebox class – Youri Leenman Mar 06 '17 at 15:38
  • I post the whole class, because none of the above work. Wait a minute, please. – Imrik Mar 06 '17 at 15:39
  • I believe I figured it out. I forgot that `CreateGraphics` writes on the picturebox itself. You must get the parent and create graphics from that like this `Form form = (Form)this.Parent; Graphics graphics = form.CreateGraphics();` I also edited my answer – Youri Leenman Mar 06 '17 at 15:49
  • You should rarely use CreateGraphics since it's a temporary drawing. Minimizing the form will erase it. Always use the paint event. – LarsTech Mar 06 '17 at 15:52
  • Yes but I believe this drawing is not meant to last if I interpreted @Imrik's intentions right – Youri Leenman Mar 06 '17 at 15:54
  • Yes, you interperted my intentions rightm. I try with this solution, wait :) – Imrik Mar 06 '17 at 16:07
  • I still have the sender problem. I cannot access to that. – Imrik Mar 06 '17 at 16:09
  • Oops my bad that can be left out. I updated my answer – Youri Leenman Mar 06 '17 at 16:12
  • If I erase the conflictive lines it give me this error: 'System.InvalidCastException' at this line :"Form form = (Form)this.Parent;" it said that it cannot convert picturebox to form – Imrik Mar 06 '17 at 16:12
  • I try with your new answer and I have the same error. – Imrik Mar 06 '17 at 16:13
  • That means that the parent of your picturebox control is not a form. Find it by using `Form form = (Form)this.FindForm();` – Youri Leenman Mar 06 '17 at 16:20
0

0,0 is the upper left hand corner of the picturebox. What you want to do is

public void DibujarLimites()
{
    using (Graphics g = CreateGraphics())
    {
        using (Pen pen = new Pen(Color.Red, 2))
        {
            float[] dashValues = { 5, 2, 15, 4 };
            pen.DashPattern = dashValues;
            DrawCircle(g, pen, this.height/2, this.width/2, 20);
        }
    }
}
  • No, I explain it better on the edited question. I want to draw a circle when the users make a mouseclickevent and this event is on myUnidad.cs class, that extends pictureBox. So I can't solve with your answer because it draws the circle into the pictureBox, no? – Imrik Mar 06 '17 at 14:49