绘制圆后如何将其视为控件? - 移动和选择形状
How can I treat the circle as a control after drawing it? - Moving and selecting shapes
实际上,我希望在点击每个圆圈后改变它的颜色,例如,我希望它变成红色,总的来说,我想把它当作控件。
我知道如何在双击图片框时绘制代表图形节点的圆圈。我正在使用以下代码:
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);
}
}
}
您需要执行命中测试来检查一个点是否在圆内。作为一个选项,您可以将圆添加到路径的 GraphicsPath
and the use IsVisible
方法中,以检查该点是否在圆中。
例如,将点 p
作为直径为 d
的圆的左上角位置,您可以检查当前点击的点是否在圆中或这样:
var result = false;
using (var path = new GraphicsPath())
{
path.AddEllipse(p.X, p.Y, d, d);
result = path.IsVisible(e.Location);
}
示例代码
我看到您就此主题提出了多个问题。所以在这里我分享一些代码来帮助你朝着正确的方向前进。
为填充颜色、选定的填充颜色、圆圈大小、边框宽度等定义变量,以便能够在需要时轻松更改它们。
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;
双击
此处将圈子添加到 Shapes
列表。将圆的边界矩形添加到列表中就足够了。
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();
}
点击
这里执行hit-test,检查点是否在circles.Check中,如果点击时Ctrl键按下,进行选择,然后设置找到索引为 selectedIndex
以在绘画时使用它。
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();
}
绘画
将图形对象的 SmoothingMode
设置为 AntiAlias
以获得更流畅的绘图。然后在 for 循环中绘制形状,注意 selectedIndex
为所选形状使用不同的填充颜色。
要绘制文本,您不需要使用 label
,您可以简单地使用 TextRenderer
class.
绘制文本
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);
}
}
一些笔记
最好将代码封装在从PictureBox
或派生Control
派生的新控件中,并将DoubleBuffered
设置为true
将Circle
封装在Circle
class中是一个很好的选择,它执行圆的命中测试和渲染。特别是如果你想稍后移动它们或执行一些其他交互或让每个圆圈都有自己的属性,如颜色等。
样本圈Class
这是一个示例圆 class 可以作为一个很好的起点。
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);
}
}
实际上,我希望在点击每个圆圈后改变它的颜色,例如,我希望它变成红色,总的来说,我想把它当作控件。
我知道如何在双击图片框时绘制代表图形节点的圆圈。我正在使用以下代码:
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);
}
}
}
您需要执行命中测试来检查一个点是否在圆内。作为一个选项,您可以将圆添加到路径的 GraphicsPath
and the use IsVisible
方法中,以检查该点是否在圆中。
例如,将点 p
作为直径为 d
的圆的左上角位置,您可以检查当前点击的点是否在圆中或这样:
var result = false;
using (var path = new GraphicsPath())
{
path.AddEllipse(p.X, p.Y, d, d);
result = path.IsVisible(e.Location);
}
示例代码
我看到您就此主题提出了多个问题。所以在这里我分享一些代码来帮助你朝着正确的方向前进。
为填充颜色、选定的填充颜色、圆圈大小、边框宽度等定义变量,以便能够在需要时轻松更改它们。
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;
双击
此处将圈子添加到 Shapes
列表。将圆的边界矩形添加到列表中就足够了。
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();
}
点击
这里执行hit-test,检查点是否在circles.Check中,如果点击时Ctrl键按下,进行选择,然后设置找到索引为 selectedIndex
以在绘画时使用它。
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();
}
绘画
将图形对象的 SmoothingMode
设置为 AntiAlias
以获得更流畅的绘图。然后在 for 循环中绘制形状,注意 selectedIndex
为所选形状使用不同的填充颜色。
要绘制文本,您不需要使用 label
,您可以简单地使用 TextRenderer
class.
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);
}
}
一些笔记
最好将代码封装在从
PictureBox
或派生Control
派生的新控件中,并将DoubleBuffered
设置为true将
Circle
封装在Circle
class中是一个很好的选择,它执行圆的命中测试和渲染。特别是如果你想稍后移动它们或执行一些其他交互或让每个圆圈都有自己的属性,如颜色等。
样本圈Class
这是一个示例圆 class 可以作为一个很好的起点。
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);
}
}