WPF中的画笔功能,实现直实线、弯实线、直虚线、弯虚线
1、InkCanvas类。
实现画板需要用到InkCanvas。一般情况下不需任何代码就可以在上面画线了。
如果需要设置画笔颜色、笔尖大小等就需要设置DefaultDrawingAttributes,例如:
DrawingAttributes attributes = new DrawingAttributes(); attributes.Color = Colors.Black; attributes.Height = 50; attributes.Width = 50; attributes.FitToCurve = true;
2、在InkCanvas上画直线
方法:在StrokeCollected事件中进行修正,StrokeCollected事件在单个笔画结束后触发。可以取出笔画的起始点(BeginPoint)和终点(EndPoint),然后使用该两点新建笔画即可。
代码如下:
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
if (e.Stroke.StylusPoints.Count > 1)
{
UpdateLine(e.Stroke);
}
}
private void UpdateLine(Stroke currentStroke)
{
StylusPoint beginPoint = currentStroke.StylusPoints[0];//起始点
StylusPoint endPoint = currentStroke.StylusPoints.Last();//终点
packageCanvas.Strokes.Remove(currentStroke);//移除原来的笔画
List<Point> pointList = new List<Point>();
pointList.Add(new Point(beginPoint.X, beginPoint.Y));
pointList.Add(new Point(endPoint.X, endPoint.Y));
StylusPointCollection point = new StylusPointCollection(pointList);
Stroke stroke = new Stroke(point);//用两点实现笔画
stroke.DrawingAttributes = packageCanvas.DefaultDrawingAttributes.Clone();
InkCanvas.Strokes.Add(stroke);
}
3、在InkCanvas上画直虚线
方法:还是跟上面一样取起始点和终点,不同点是:在两点间绘制许多点,然后将相邻的两点连接成一个笔画。这样一个直虚线变好了。
代码如下:
private void UpdateLine(Stroke currentStroke)
{
InkCanvas.Strokes.Remove(currentStroke);//移除原来笔画
int dotTime = 0;
int intervalLen=6;//步长
double lineLen = Math.Sqrt(Math.Pow(beginPoint.X - endPoint.X, 2) + Math.Pow(beginPoint.Y - endPoint.Y, 2));//线的长度
Point currentPoint = new Point(beginPoint.X, beginPoint.Y);
double relativaRate = Math.Abs(endPoint.Y - beginPoint.Y) * 1.0 / Math.Abs(endPoint.X - beginPoint.X);
double angle = Math.Atan(relativaRate) * 180 / Math.PI;//直线的角度大小,无需考虑正负
int xOrientation = endPoint.X > beginPoint.X ? 1 : -1;//判断新生成点的X轴方向
int yOrientation = endPoint.Y > beginPoint.Y ? 1 : -1;
if (lineLen < intervalLen)
{
return;
}
while (dotTime * intervalLen < lineLen)
{
double x = currentPoint.X + dotTime * intervalLen * Math.Cos(angle * Math.PI / 180) * xOrientation;
double y = currentPoint.Y + dotTime * intervalLen * Math.Sin(angle * Math.PI / 180) * yOrientation;
List<Point> pL = new List<Point>();
pL.Add(new Point(x, y));
x += intervalLen * Math.Cos(angle * Math.PI / 180) * xOrientation;
y += intervalLen * Math.Sin(angle * Math.PI / 180) * yOrientation;
pL.Add(new Point(x, y));
StylusPointCollection spc = new StylusPointCollection(pL);//相邻两点作为一个笔画
Stroke stroke = new Stroke(spc);
stroke.DrawingAttributes = packageCanvas.DefaultDrawingAttributes.Clone();
InkCanvas.Strokes.Add(stroke);
dotTime+=2;
}
}
4、在InkCanvas上画弯虚线
方法:在InkCanvas_StrokeCollected方法的参数属性中可以获得线上的点的坐标。
2)生成StylusPointCollection collection=currentStroke.StylusPoints,用来存放当前笔画的所有点
2)生成一个List<Point> allPointList,用来存放最终生成的点
2) 将起始点=》allPointList,起始点-》currentPoint
3)遍历collection,IF currentPoint与找到点(item)的距离==步长 THEN item=>allPointList;item=>currentPoint,取下一个点
IF currentPoint与找到点(item)的距离>步长 THEN 在currentPoint与item线上找到一个点,使得与currentPoint的距离=步长,item=>allPointList;item=>currentPoint,继续当前点
IF currentPoint与找到点(item)的距离<步长 取下一个点
代码如下:
private void UpdateLine(Stroke currentStroke)
{
InkCanvas.Strokes.Remove(currentStroke);
StylusPointCollection collection = currentStroke.StylusPoints;
List<Point> allSelectedPoint = new List<Point>();
Point currentPoint = new Point(collection[0].X, collection[0].Y);
allSelectedPoint.Add(currentPoint);
for (int i = 0; i < collection.Count; i++)
{
var item = collection[i];
double length = Math.Sqrt(Math.Pow(item.X - currentPoint.X, 2) + Math.Pow(item.Y - currentPoint.Y, 2));
if ((int)(length + 0.5) == (int)intervalLen || length == intervalLen)
{
currentPoint = new Point(item.X, item.Y);
allSelectedPoint.Add(currentPoint);
}
else if (length > intervalLen)
{
double relativaRate = Math.Abs(item.Y - currentPoint.Y) * 1.0 / Math.Abs(item.X - currentPoint.X);
double angle = Math.Atan(relativaRate) * 180 / Math.PI;
int xOrientation = item.X > currentPoint.X ? 1 : -1;
int yOrientation = item.Y > currentPoint.Y ? 1 : -1;
double x = currentPoint.X + intervalLen * Math.Cos(angle * Math.PI / 180) * xOrientation;
double y = currentPoint.Y + intervalLen * Math.Sin(angle * Math.PI / 180) * yOrientation;
currentPoint = new Point(x, y);
allSelectedPoint.Add(currentPoint);
i--;//很重要,继续当前点
}
}
for (int j = 0; j < allSelectedPoint.Count; j++)
{
List<Point> p = new List<Point>();
p.Add(allSelectedPoint[j]);
if (j < allSelectedPoint.Count - 1)
{
j++;
}
p.Add(allSelectedPoint[j]);
StylusPointCollection spc = new StylusPointCollection(p);
Stroke stroke = new Stroke(spc);
InkCanvas.Strokes.Add(stroke);
}
}
以上是测试过的代码,不足之处是:只能在当前笔画完成后在进行修正,因为代码写在InkCanvas_StrokeCollected中。