!!请参阅下面的更新!
Hans' link https://msdn.microsoft.com/en-us/library/system.drawing.texturebrush(v=vs.110).aspx should point you in the right direction, namely toward TextureBrushes https://msdn.microsoft.com/en-us/library/system.drawing.texturebrush(v=vs.110).aspx.
为了进一步帮助您,请注意以下几点:
TextureBrush is a brush, not a pen. So you can't follow a path, like the mouse movements to draw along that curve. Instead, you need to find an area to fill with the brush.
This also implies that you need to decide how and when to trigger the drawing; basic options are by time and/or by distance. Usually, the user can set parameters for these often called 'flow' and 'distance'..
Instead of filling a simple shape and drawing many of those, you can keep adding the shapes to a GraphicsPath https://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.graphicspath(v=vs.110).aspx and fill that path.
To create a TextureBrush you need a pattern file that has transparency. You can either make some or download them from the web where loads of them are around, many for free.
大多数都是 Photoshop 画笔格式“abr”;如果它们不是太新(abrMate将它们转换为 png 文件。
您可以将一组画笔加载到 ImageList,设置足够大的尺寸(最大 256x256)和 32bpp 以允许 Alpha。
大多数图案都是带有 Alpha 的黑色,因此如果您想要颜色,则需要创建当前画笔图像的彩色版本(可能使用 ColorMatrix)。
您可能还想更改其透明度(最好也使用 ColorMatrix)。
您需要将大小更改为当前画笔大小。
Update
在做了一些测试之后,我不得不撤回最初的假设,即“TextureBrush”是使用纹理笔尖进行绘图的合适工具。
对于填充区域来说是可以的,但是对于徒手绘制它就无法正常工作。有几个原因..:
See here https://stackoverflow.com/questions/40105910/fill-texture-brush-using-image-not-tile/40112000?s=4%7C28.3185#40112000举个你的例子don't想要在工作中。
解决方案非常简单,上面的大部分内容仍然适用:
- 你所做的几乎是常规绘图,但最后,你做了一个
DrawImage
与准备好的“画笔”图案。
常规绘图涉及:
- A
List<List<Point>> curves
保存所有已完成的鼠标路径
- A
List<Point> curentCurve
对于当前路径
In the Paint
如果您绘制所有曲线,如果有任何点,也绘制当前路径。
对于用图案进行绘画,还需要了解when画画which图案版本。
如果我们确保不泄漏它们,我们可以缓存画笔图案......:
Bitmap brushPattern = null;
List<Tuple<Bitmap,List<Point>>> curves = new List<Tuple<Bitmap,List<Point>>>();
Tuple<Bitmap, List<Point>> curCurve = null;
这是一种简单/简单化的缓存方法。为了提高效率,您可以使用Dictionary<string, Bitmap>
使用命名方案,根据图案索引、大小、颜色、alpha 以及可能的旋转角度生成字符串;这样每个模式将只存储一次。
这是一个工作中的例子:
一些注意事项:
在 MouseDown 中我们创建一条新的当前曲线:
curCurve = new Tuple<Bitmap, List<Point>>(brushPattern, new List<Point>());
curCurve.Item2.Add(e.Location);
在 MouseUp 中,我将当前曲线添加到曲线列表中:
curves.Add(new Tuple<Bitmap, List<Point>>(curCurve.Item1, curCurve.Item2.ToList()));
由于我们要清除当前曲线,因此需要复制其点列表;这是通过以下方式实现的ToList()
call!
在 MouseMove 中,我们只需添加一个新点即可:
if (e.Button == MouseButtons.Left)
{
curCurve.Item2.Add(e.Location);
panel1.Invalidate();
}
Paint 会覆盖所有曲线,包括当前曲线:
for (int c = 0; c < curves.Count; c++)
{
e.Graphics.TranslateTransform(-curves[c].Item1.Width / 2, -curves[c].Item1.Height / 2);
foreach (var p in curves[c].Item2)
e.Graphics.DrawImage(curves[c].Item1, p);
e.Graphics.ResetTransform();
}
if (curCurve != null && curCurve.Item2.Count > 0)
{
e.Graphics.TranslateTransform(-curCurve.Item1.Width / 2, -curCurve.Item1.Height / 2);
foreach (var p in curCurve.Item2)
e.Graphics.DrawImage(curCurve.Item1, p);
e.Graphics.ResetTransform();
}
它确保图案居中绘制。
ListView 设置为 SmallIcons,其 SmallImageList 指向原始 ImageList 的较小副本。
重要的是让面板双缓冲! https://stackoverflow.com/questions/44185298/update-datagridview-very-frequently/44188565#44188565以避免闪烁!
Update:代替Panel
,这是一个Container
控制而不是真正意味着绘制你可以使用Picturebox
or a Label
(with Autosize=false
);两者都有DoubleBuffered
属性开箱即用,并且支持绘图比Panels
do.
顺便说一句:上面的快速而肮脏的示例只有 200 行(未注释)。添加画笔旋转、预览、步进距离、保存按钮并实现画笔缓存,使其达到 300 行。