c# - ¿Cómo puedo tratar el círculo como un control después de dibujarlo?-Mover y seleccionar formas
.net winforms (1)
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
GraphicsPath
y usar el método
IsVisible
de la ruta para verificar si el punto está en círculo.
Por ejemplo, teniendo un punto
p
como ubicación superior izquierda de un círculo con diámetro
d
, puede verificar si el punto de clic actual está en el círculo o con esta:
var result = false;
using (var path = new GraphicsPath())
{
path.AddEllipse(p.X, p.Y, d, d);
result = path.IsVisible(e.Location);
}
Código de muestra
Veo que has hecho múltiples preguntas en este tema. Así que aquí comparto un código para ayudarlo 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, etc., para poder cambiarlos simplemente si lo necesita.
List<Rectangle> Shapes = new List<Rectangle>();
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í agregue 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í realice una prueba de golpe para verificar si el punto está en uno de los círculos. Verifique si la tecla
Ctrl
está presionada al hacer clic, para hacer la selección, luego configure el índice encontrado como
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
del objeto gráfico en
AntiAlias
para tener un dibujo más suave.
Luego dibuje formas en un bucle 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
oControl
derivado y establecerDoubleBuffered
en true. -
Es una buena opción encapsular
Circle
en una claseCircle
que realiza pruebas de impacto y renderiza 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 el color, etc.
Clase de muestra 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);
}
}
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<Point> points = new List<Point>();
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);
}
}
}