看着你的代码恐怕我不得不说:这是都错了.
抱歉这么直白,但是你绝对不能使用control.CreateGraphics!
- 首先要做的就是扔掉
Graphics objgraphics
object.
存储a(几乎)总是错误的Graphics
object!
相反,您必须使用从e.Graphics
中的参数Paint
您的控件的事件。
注意Graphics
不包含任何图形,它是一个用于绘制到关联的工具Bitmap
或控件的表面。
- 接下来要做的就是了解手绘线条。通常人们可以看到您拥有的代码;但这是无用的,只是你在介绍中发现了多少愚蠢的事情的一个例子。忘了它。它总是看起来像垃圾,因为圆圈看起来永远不会平滑,一旦你更快地移动鼠标,伪线就会完全崩溃。
有一个不错的方法DrawCurve
这将画出平滑的线条。你喂它一个Pen
和一个数组Points
.
这就是我们将要使用的。
让我们回到基础知识:如何创建图形?现在我们知道您需要致电DrawCurve
in the Paint
event:
e.Graphics.DrawCurve(somePen, somePointsArray);
这就提出了接下来的问题:
还有一个隐藏的第三个问题:
第一个很简单;你创建一个Pen
笔划宽度为 5.5 像素
Pen somePen = new Pen(Color.Blue, 5.5f);
如果你愿意,你也可以给它一个线条样式(破折号)。
现在来说说数组:以最简单的形式,这也很容易。
In the MouseMove
您存储当前的事件Location
在点列表中。首先,我们在类级别声明它:
List<Point> currentLine = new List<Point>();
然后我们只要按下左键就开始填充:
private void panel1_MouseMove_1(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
currentLine.Add(e.Location);
panel1.Invalidate();
}
}
注意最后一行:调用Invalidate
在控件上触发system调用Paint
事件。它可能看起来很复杂,但这是唯一正确的方法,因为它保证当某些情况下也会发生完全相同的绘图other理性使得它成为必要。
We需要绘制,因为我们更改了应该绘制的数据。但也有很多outside原因,最出名的是Minimize/maximize
序列将清除绘图并触发Paint
事件,也。所以我们需要合作随路windows绘制其控件!只有这样图形才会persist.
另外,请注意,我们不使用数组,因为我们不知道有多少Points
我们会需要。相反,我们使用List
然后将其投射到Array
.
让我们编写代码Paint
我们简单案例的事件:
private void panel1_Paint(object sender, PaintEventArgs e)
{
using (Pen somePen = new Pen(Color.Blue, 5.5f) )
if (currentLine.Count > 1) e.Graphics.DrawCurve(yourPen , currentLine.ToArray());
}
请注意,我已经创建了Pen
in a using
条款。这是一种廉价且安全的方法,可确保Pen
已妥善处置。
另请注意我们如何投射List
to an Array
!
仅上面的代码就可以工作并允许您徒手画一条线。
但是下一行呢?它不应该连接到第一个,所以我们不能只是添加更多点!
所以我们不仅需要one点列表但是more除此之外,事实上,需要一个点列表的列表:
List<List<Point>> curves = new List<List<Point>>();
每当释放鼠标时,我们都会将当前曲线添加到其中:
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
if (currentLine.Count > 1) curves.Add(currentLine.ToList()); // copy!!
currentLine.Clear();
panel1.Invalidate();
}
请注意我如何使用来自List
to List
强制执行副本,否则仅分配引用,然后在下一行中清除..
我们再次触发Paint
事件作为最后要做的事情。
我们现在应该改变Paint
显示所有线条的事件,包括当前正在绘制的线条和所有先前绘制的线条..:
private void panel1_Paint(object sender, PaintEventArgs e)
{
using (Pen somePen = new Pen(Color.Blue, 5.5f) )
{
if (currentLine.Count > 1) e.Graphics.DrawCurve(somePen, currentLine.ToArray());
foreach (List<Point> lp in curves)
if (lp.Count > 1) e.Graphics.DrawCurve(somePen, lp.ToArray());
}
}
现在我们的手绘部分已经基本完成了。
所以我们回到你原来的问题:如何将绘图复制到second Panel
?
好吧,你已经将所有内容存储在curves
数据结构。
所以你有两个选择:要么简单地使用相同的数据panel2_Paint
事件或者如果您需要复制和更改数据,也许会适应不同的大小。
以下是仍然缺少的东西:
- 保存数据,保存绘图(
Serialize
, DrawToBitMap
)
- 用不同的笔和颜色绘图(创建一个
drawAction
类来存储您需要的所有内容)
- 使用其他工具,如直线或矩形(创建一个
drawAction
class)
- 清除绘图(见下文)
- 撤消和重做(查看
Stacks
an Queues
)
- 当有大量行时进行缓存(将第一部分绘制到
BackgroundImage Bitmap
)
这是一个清除代码:
curves.Clear(); currentLine .Clear(); panel1.Invalidate();
我注意到您的原始代码允许您使用左右按钮以两种不同的笔画宽度进行绘制。仅此一点就说明这段代码不是很好。谁会a)想到这一点并且b)只满足于两个笔划宽度。
请阅读这个帖子 https://stackoverflow.com/questions/28714411/update-a-drawing-without-deleting-the-previous-one/28716887?s=5%7C0.1873#28716887我在其中解释了一些关于创建一个可以存储笔宽度、颜色等的类,以便您可以在绘制的线条之间进行更改。