¿Cómo puedo tratar el círculo como control después de dibujarlo? – Mover y seleccionar formas

En realidad, después de hacer clic en cada círculo, quiero que se cambie su color, por ejemplo, quiero que se vuelva rojo. En general, quiero tratarlo como control.

Sé cómo dibujar los círculos que representan los nodos del gráfico cuando hago doble clic en el cuadro de imagen. Estoy usando el siguiente código:

public Form1() { InitializeComponent(); pictureBox1.Paint += new PaintEventHandler(pic_Paint); } public Point positionCursor { get; set; } private List points = new List(); public int circleNumber { get; set; } private void pictureBox1_DoubleClick(object sender, EventArgs e) { positionCursor = this.PointToClient(new Point(Cursor.Position.X - 25, Cursor.Position.Y - 25)); points.Add(positionCursor); Label lbl = new Label(); lbl.BackColor = Color.Transparent; lbl.Font = new Font("Arial", 7); lbl.Size = new Size(20, 15); if (circleNumber >= 10) { lbl.Location = new Point(points[circleNumber].X + 3, points[circleNumber].Y + 6); } else { lbl.Location = new Point(points[circleNumber].X + 7, points[circleNumber].Y + 7); } lbl.Text = circleNumber.ToString(); pictureBox1.Controls.Add(lbl); circleNumber++; pictureBox1.Invalidate(); } private void pic_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; using (var pen = new Pen(Color.DimGray, 2)) { foreach (Point pt in points) { g.FillEllipse(Brushes.White, pt.X, pt.Y, 25, 25); g.DrawEllipse(pen, pt.X, pt.Y, 26, 26); } } } 

enter image description here

    Debe realizar una prueba de impacto para verificar si un punto está en un círculo. Como opción, puede agregar un círculo a un GraphicsPath y usar el método IsVisible de la ruta para verificar si el punto está en círculo.

    Por ejemplo, tener un ponit p como la ubicación superior izquierda de un círculo con un diámetro d , puede verificar si el punto seleccionado actualmente está en el círculo o de esta manera:

     var result = false; using (var path = new GraphicsPath()) { path.AddEllipse(pX, pY, d, d); result = path.IsVisible(e.Location); } 

    Código de muestra

    Veo que ha hecho varias preguntas en este tema. Así que aquí comparto un código para ayudarte a estar en la dirección correcta.

    defina variables para el color de relleno, el color de relleno seleccionado, el tamaño del círculo, el ancho del borde y etc., para poder cambiarlos simplemente si lo necesita.

     List Shapes = new List(); int selectedIndex = -1; Size size = new Size(25, 25); Color fillColor = Color.White; Color selectedfillCOlor = Color.Red; Color borderColor = Color.Gray; int borderWidth = 2; 

    Haga doble clic

    Aquí agrega círculos a la lista de Shapes . Es suficiente agregar el rectángulo delimitador de un círculo a la lista.

     private void pic_MouseDoubleClick(object sender, MouseEventArgs e) { var p = e.Location; p.Offset(-size.Width / 2, -size.Height / 2); Shapes.Add(new Rectangle(p, size)); pic.Invalidate(); } 

    Hacer clic

    Aquí realiza una prueba de impacto para verificar si el punto está en uno de los círculos. Comprueba si la tecla Ctrl está presionada al hacer clic, para hacer una selección, luego configura el índice encontrado como índice selectedIndex para usarlo al pintar.

     private void pic_MouseClick(object sender, MouseEventArgs e) { if (ModifierKeys != Keys.Control) return; selectedIndex = -1; for (int i = 0; i < Shapes.Count; i++) { using (var path = new GraphicsPath()) { path.AddEllipse(Shapes[i]); if (path.IsVisible(e.Location)) selectedIndex = i; } } pic.Invalidate(); } 

    Pintar

    Establezca SmoothingMode of graphics object en AntiAlias para obtener un dibujo más suave. Luego dibuje las formas en un ciclo for y preste atención a selectedIndex para usar un color de relleno diferente para la forma seleccionada.

    Para dibujar el texto, no necesita usar una label y simplemente puede dibujar texto usando la clase TextRenderer .

     private void pic_Paint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; for (int i = 0; i < Shapes.Count; i++) { var selected = (selectedIndex == i); using (var brush = new SolidBrush(selected ? selectedfillCOlor : fillColor)) e.Graphics.FillEllipse(brush, Shapes[i]); using (var pen = new Pen(borderColor, borderWidth)) e.Graphics.DrawEllipse(pen, Shapes[i]); TextRenderer.DrawText(e.Graphics, (i + 1).ToString(), this.Font, Shapes[i], Color.Black, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter); } } 

    Algunas notas

    • Es mejor encapsular códigos en un nuevo control derivado de PictureBox o Control derivado y establecer DoubleBuffered en true.

    • Es una buena opción para encapsular el Circle en una clase de Circle que realiza pruebas de impacto y la representación de un círculo. Especialmente si desea moverlos más tarde o realizar otras interacciones o dejar que cada círculo tenga sus propias propiedades como color, etc.

    Clase de ejemplo de círculo

    Aquí hay una clase de círculo de muestra que puede ser un buen punto de partida.

     public class Circle { private Color selectedFillColor = Color.Red; private Color normalFillColor = Color.Red; private Color borderColor = Color.Red; private int borderWidth = 2; public Point Location { get; set; } public int Diameter { get; set; } public Rectangle Bounds { get { return new Rectangle(Location, new Size(Diameter, Diameter)); } } public bool HitTest(Point p) { var result = false; using (var path = new GraphicsPath()) { path.AddEllipse(Bounds); result = path.IsVisible(p); } return result; } public bool Selected { get; set; } public void Draw(Graphics g) { using (var brush = new SolidBrush( Selected ? selectedFillColor : normalFillColor)) g.FillEllipse(brush, Bounds); using (var pen = new Pen(borderColor, 2)) g.DrawEllipse(pen, Bounds); } }