这是个简单的支持多点触摸的画板控件, 绘制功能基于WPF InkCanvas,也是我drawTool系列文章的开篇。

阅读该文章后可能产生一些问题:

1. 如果对生成的笔迹对象进行控制

如果要对生成的stroke笔迹进行控制,这里需要单独用一个基于UIElement的对象关联到笔迹对象,例如Polyline元素的points绑定到stroke的点集合,这样对笔记的对象控制就转化为对UIlement对象的控制了

2. 如何给笔迹对象添加控制边框

在1的基础上给对象添加边框其实就变成给UIElement对象添加边框了,在WPF中可以使用装饰器来实现,包括对对象的控制,例如旋转,拉伸等等

ps:1,2问题会在后面文章实现~  上个简单的图~

    /// PenType = 画笔类型,支持普通画笔,荧光笔,点擦除,后面我扩充到支持图像笔,纹理笔以及flash笔,至于排笔的实现其实只要上何止width和height不同就可以了
/// PenColor = 画笔的颜色
/// EraseWidth = 橡皮擦粗细

直接上源码,代码理解起来还是很简单的(MultiTouchCanvas)

/// <summary>
/// 支持多点触摸的InkCanvas
/// </summary
public class MultiTouchCanvas : FrameworkElement
{
private InkCanvasProxy _inkCanvas = new InkCanvasProxy();
private Grid transparentOverlay = new Grid();
private StrokeType _strokeType = StrokeType.Stroke;
private Dictionary<object, StrokeCollection> _strokes = new Dictionary<object, StrokeCollection>();
private Dictionary<object, Stroke> _currentStroke = new Dictionary<object, Stroke>(); private Color _penColor = Colors.Green;
public Color PenColor{
get{
return this._inkCanvas.DefaultDrawingAttributes.Color;
}
set{
this._penColor = value;
this._inkCanvas.DefaultDrawingAttributes.Color = value;
if (this.PenType == StrokeType.HighlighterStroke)
{
value.ScA = System.Convert.ToSingle(0.5);
this._inkCanvas.DefaultDrawingAttributes.Color = value;
}
}
} private double _penWidth = 4.0;
public double PenWidth
{
get { return this._penWidth; }
set
{
this._penWidth = value;
this._inkCanvas.DefaultDrawingAttributes.Width = value;
this._inkCanvas.DefaultDrawingAttributes.Height = value;
}
} private double _eraseWidth = 30.0;
public double EraseWidth
{
get
{
return this._eraseWidth;
}
set
{
this._eraseWidth = value;
this._inkCanvas.DefaultDrawingAttributes.Height = value;
this._inkCanvas.DefaultDrawingAttributes.Width = value;
}
} public StrokeType PenType
{
get { return this._strokeType; }
set
{
this._strokeType = value;
if (this._strokeType == StrokeType.Stroke || this._strokeType == StrokeType.HighlighterStroke)
{
this._inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
this._inkCanvas.DefaultDrawingAttributes.Width = this.PenWidth;
this._inkCanvas.DefaultDrawingAttributes.Height = this.PenWidth;
this._inkCanvas.DefaultDrawingAttributes.Color = this.PenColor;
} if (this._strokeType == StrokeType.HighlighterStroke)
{
Color dColor = this.PenColor;
dColor.ScA = System.Convert.ToSingle(0.5);
this._inkCanvas.DefaultDrawingAttributes.Color = dColor;
} if (this._strokeType == StrokeType.EraseByPoint)
{
this._inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
this._inkCanvas.DefaultDrawingAttributes.Width = this.EraseWidth;
this._inkCanvas.DefaultDrawingAttributes.Height = this.EraseWidth;
}
}
} public Brush Background
{
get { return this._inkCanvas.Background; }
set
{
this._inkCanvas.Background = value;
}
} protected override int VisualChildrenCount
{
get
{
return ; //grid + inkcanvas
}
} public MultiTouchCanvas(){
base.IsManipulationEnabled = true;
this.transparentOverlay.Background = Brushes.Transparent;
base.IsEnabled =true; this.InitInkCanvasPropertys();
this._inkCanvas.DefaultDrawingAttributes = new DrawingAttributes();
this._inkCanvas.DefaultDrawingAttributes.Color = Colors.Green;
this._inkCanvas.DefaultDrawingAttributes.Width = ;
this._inkCanvas.DefaultDrawingAttributes.Height = ; this.PenType = StrokeType.Stroke;
} public void ClearStrokes(object device)
{
if (this._strokes.ContainsKey(device) && this._inkCanvas.Strokes != null && this._inkCanvas.Strokes.Count > )
{
StrokeCollection sc = this._strokes[device];
this._inkCanvas.Strokes.Remove(sc);
this._strokes.Remove(device);
}
} public StrokeCollection GetStrokes(object device)
{
return this._strokes.ContainsKey(device) ? this._strokes[device] : null;
} #region Event handle
protected override void OnPreviewTouchDown(TouchEventArgs e)
{
TouchPoint tp = e.GetTouchPoint(this);
if (this._inkCanvas.EditingMode == InkCanvasEditingMode.Ink)
{
this._startStroke(e.Device, tp.Position);
}
else
{
if (this._inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
this._removeStroke(e.Device, tp.Position);
}
} e.Handled = true;
base.Focusable = true;
base.Focus();
base.Focusable = false;
e.TouchDevice.Capture(this);
} protected override void OnPreviewTouchMove(TouchEventArgs e)
{
_handleTouchMove(e);
} protected override void OnTouchUp(TouchEventArgs e)
{
e.TouchDevice.Capture(null); //
} protected override void OnMouseDown(MouseButtonEventArgs e)
{
if (base.Visibility == System.Windows.Visibility.Visible)
{
if (this._inkCanvas.EditingMode == InkCanvasEditingMode.Ink)
{
this._startStroke(e.Device, e.GetPosition(this));
}
else
{
if (this._inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
this._removeStroke(e.Device, e.GetPosition(this));
}
} e.MouseDevice.Capture(this);
}
} protected override void OnMouseMove(MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (this._inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
this._removeStroke(e.Device, e.GetPosition(this));
return;
}
if (this._strokes.ContainsKey(e.Device) && this._currentStroke.ContainsKey(e.Device))
{
this._addPointToStroke(e.Device, e.GetPosition(this));
}
else
{
this._startStroke(e.Device, e.GetPosition(this));
}
}
} protected override void OnMouseUp(MouseButtonEventArgs e)
{
e.MouseDevice.Capture(null);
}
#endregion protected override Visual GetVisualChild(int index)
{
switch (index)
{
case : return this._inkCanvas;
case : return this.transparentOverlay;
default:
throw new ArgumentOutOfRangeException("index");
}
} protected override Size MeasureOverride(Size availableSize)
{
this._inkCanvas.Measure(availableSize);
this.transparentOverlay.Measure(availableSize);
return this._inkCanvas.DesiredSize;
} protected override Size ArrangeOverride(Size finalSize)
{
this._inkCanvas.Arrange(new Rect(finalSize));
this.transparentOverlay.Arrange(new Rect(finalSize));
return base.ArrangeOverride(finalSize); } protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
base.AddVisualChild(this._inkCanvas);
base.AddVisualChild(this.transparentOverlay);
}
private void _handleTouchMove(TouchEventArgs e)
{
if(this._inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint){
this._removeStroke(e.Device , e.GetTouchPoint(this).Position);
e.Handled = true;
return ;
} if(this._strokes.ContainsKey(e.Device) && this._currentStroke.ContainsKey(e.Device))
{
Stroke stroke = this._currentStroke[e.Device];
StylusPointCollection sps = stroke.StylusPoints;
if(sps != null){
TouchPoint tp = e.GetTouchPoint(this);
Point p = tp.Position;
this._addPointToStroke( e.Device , p);
}
}
else
{
TouchPoint tp = e.GetTouchPoint(this);
this._startStroke( e.Device ,tp.Position);
}
e.Handled = true;
} private void _addPointToStroke(object device, Point position)
{
Stroke stroke = this._currentStroke[device];
if (stroke != null)
{
StylusPointCollection spc = stroke.StylusPoints;
if (spc != null)
{
spc.Add(new StylusPoint(position.X, position.Y, 0.5f));
}
}
} private void _removeStroke(object device, Point position)
{
for (int i = ; i < this._inkCanvas.Strokes.Count; i++)
{
Stroke stroke = this._inkCanvas.Strokes[i];
StrokeCollection sc = stroke.GetEraseResult(new Rect(position.X, position.Y, this._inkCanvas.DefaultDrawingAttributes.Width, this._inkCanvas.DefaultDrawingAttributes.Height));
this._inkCanvas.Strokes.Replace(stroke, sc);
}
} private void _startStroke(object device, Point inputPosition)
{
StylusPointCollection stylusPointCollection = new StylusPointCollection();
stylusPointCollection.Add(new StylusPoint(inputPosition.X, inputPosition.Y, 0.5f)); if (stylusPointCollection.Count > )
{
Stroke stroke = new Stroke(stylusPointCollection);
stroke.DrawingAttributes.Width = this._inkCanvas.DefaultDrawingAttributes.Width;
stroke.DrawingAttributes.Height = this._inkCanvas.DefaultDrawingAttributes.Height;
stroke.DrawingAttributes.Color = this._inkCanvas.DefaultDrawingAttributes.Color;
this._inkCanvas.Strokes.Add(stroke);//添加到canvas
if (this._currentStroke.ContainsKey(device))
{
this._currentStroke.Remove(device);
}
this._currentStroke.Add(device, stroke); if (this._strokes.ContainsKey(device))
{
this._strokes[device].Add(this._currentStroke[device]);
return;
} this._strokes.Add(device, new StrokeCollection { this._currentStroke[device] });
}
} private void InitInkCanvasPropertys(){
this._inkCanvas.Focusable = base.Focusable;
this._inkCanvas.Background = Brushes.Transparent;
this._inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
this._inkCanvas.UseCustomCursor = true;
}
}

InkCanvasProxy和StrokeType的代码

    public enum StrokeType
{
Stroke,
HighlighterStroke,
EraseByPoint
} public class InkCanvasProxy : InkCanvas
{
public InkCanvasProxy()
: base()
{
// base.IsHitTestVisible = false;
// base.StylusPlugIns.Remove(base.DynamicRenderer);
}
}

实例demo,调用: 新建一个WPF程序,然后在mainwindow.xaml添加

<Window x:Class="Metro.G.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="600"
xmlns:ll="clr-namespace:Metro.G">
<Canvas Name="container" >
<ll:MultiTouchCanvas Width="600" Height="600" x:Name="_canvas"></ll:MultiTouchCanvas>
</Canvas>
</Window>

画笔的类型,颜色以及粗细通过MultiTouchCanvas的属性设置

多点触摸画板(MultiTouchCanvas)的更多相关文章

  1. 基于Qt QGraphicsView的多点触摸绘图

    本应用于基于QGraphicsView框架,实现多点触摸. 工程仅仅演示了多点触摸绘图,源自我前段时间一款基于Qt的绘图软件. 工程结构: kmp.h 定义了枚举 slide.h/cpp 定义了派生于 ...

  2. 第29章 电容触摸屏—触摸画板—零死角玩转STM32-F429系列

    第29章     电容触摸屏—触摸画板 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  3. 多点触摸(MT)协议(翻译)

    参考: http://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt 转自:http://www.arm9home.ne ...

  4. 移动web开发,12个触摸及多点触摸事件常用Js插件

    如今移动互联网已经占据了主流地位,越来越多的开发者开始从桌面转向移动平台.与桌面开发不同的是,在移动领域中,不同的操作系统.大量不同屏幕尺寸的移动设备.触摸手势操作等,这都给开发者带来了一定的难度和挑 ...

  5. 毫无保留开源我写的:IOS Android Ipad 多点触摸通用js 库

    毫无保留开源我写的:IOS Android Ipad 多点触摸通用js 库 在线演示地址: http://m.yunxunmi.com/ 支持 IOS Android Ipad 等不同操作系统的手持或 ...

  6. Android 中多点触摸协议

    http://blog.csdn.net/zuosifengli/article/details/7398661 Android 中多点触摸协议: 参考: http://www.kernel.org/ ...

  7. Android 手势滑动,多点触摸放大缩小图片

    效果展示: 基本思路: <1>首先写一个图片控制类ImageControl,实现对图片控制的的基本操作,我们的图片控制类ImageControl是继承自ImageView自定义的视图: & ...

  8. ios开发——实用技术篇Swift篇&多点触摸与手势识别

    多点触摸与手势识别 //点击事件 var atap = UITapGestureRecognizer(target: self, action: "tapDo:") self.vi ...

  9. WPF中的多点触摸事件

    UIElement在WPF4下添加了很多支持多点触摸的事件,通过它们可以在硬件支持的情况下处理多点触摸,以下通过代码来说明通过处理这些事件,我们可以做些什么: 一.触摸相关的多种事件,跟鼠标事件是对应 ...

随机推荐

  1. Cocos2d-x下Lua调用自定义C++类和函数的最佳实践[转]

    Cocos2d-x下Lua调用C++这事之所以看起来这么复杂.网上所有的文档都没讲清楚,是因为存在5个层面的知识点: 1.在纯C环境下,把C函数注册进Lua环境,理解Lua和C之间可以互相调用的本质 ...

  2. 二模10day1解题报告

    T1.阅览室(reading) 有一个0~T时间内开放的阅览室,n个读者来读书每人k本,编号和看完所需时间在输入中.其中喜欢度降序排列(不考虑数值),每个人先看喜欢的,如果没有(被人拿走了)就继续找第 ...

  3. javascript设计模式-桥接模式

    在系统中,某些类由于自身逻辑,具有两个或两个以上维度的变化,如何使得该类型可以沿多个方向变化,但又不引入额外的复杂度,这就是桥接模式要解决的问题. 定义:桥接模式(Bridge),将抽象部分与它的实现 ...

  4. oracle:触发器,自治事务 trigger

    create or replace trigger TRI_FC83_INSERT before insert ON FC83 FOR EACH ROW declare PRAGMA AUTONOMO ...

  5. MFC读取XML文件并解析

    现在经常会对XML文件进行操作,怎么在MFC下去读和解析XML文件呢?直接上代码: 首先得等在stdafx.h中加入这句,以引入MSXML命名空间 #import <msxml3.dll> ...

  6. Windows Phone开发(12):认识一下独具个性的磁贴(转)

    对"磁贴"的理解是一点也不抽象的,为什么呢?只要你愿意启动WP系统,无论你是在模拟器中还是在真机中,是的,桌面上那一块块像地板的玩意儿,就是磁贴了.(图:磁贴) 在上图中,我们很直 ...

  7. 探秘Java中String、StringBuilder以及StringBuffer

    探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问 到的地方,今天就来和大家一起学习 ...

  8. JavaScript学习小结(一)——JavaScript入门基础

    一.JavaScript语言特点 1.1.JavaScript是基于对象和事件驱动的(动态的) 它可以直接对用户或客户输入做出响应,无须经过Web服务程序.它对用户的响应,是采用以事件驱动的方式进行的 ...

  9. 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(八)-- 多环境开发

    本篇将演示Asp.Net Core如何在多环境下进行开发适配. 在一个正规的开发流程里,软件开发部署将要经过三个阶段:开发.测试.上线,对应了三个环境:开发.测试.生产.在不同的环境里,需要编写不同的 ...

  10. CentOS编译安装lamp

    LAMP环境搭建(编译安装CentOS+httpd2.2+mysql5.5+php5.4) 首先准备以下压缩包 <ignore_js_op> (1)编译安装apache 1.配置防火墙,开 ...