windows7的触摸功能开辟了一个电脑的全新世纪。从此,您可以丢掉鼠标和键盘,直接用手在屏幕上玩游戏、用笔来写字编辑文档,聊天。

windows7最重要特性之一就是:支持多点触摸。比尔盖茨说,不久,鼠标键盘会消失。
Windows 7 使用户无需使用中间设备,通过手指触摸方式就能够管理应用程序。与其他指点设备不同,这种新功能支持在不同指点位置上同时发生多个输入事件,支持复杂的场景,比如通过十指或由多个并行用户管理应用程序。然而,要成功实现此功能,我们必须调整应用程序的用户界面和行为,以支持这种新的输入模式。
       下面我们来看下Windows7下多点触摸图片处理应用程序的具体酷炫操作界面:

画布功能的操作界面


多点触摸--将图片自由缩放
当我们选择好一张图片后,通过红外线触控功能使用手指可以将图片移动到屏幕内的任意位置。再通过多点触摸功能,使用两根手指就可以轻松的将图片进行自由的旋转、缩小和放大。


选择多个图片进行操作

多图片为一体时任意移动
还可以同时选择多个图片一起操作。在自己想操作的所有图片范围内,用手指以一个起点开始画圈,最后终点要与起点重合,这样就可以自由触控被选中的所有图片,不过此时这些图片是一体化的,如果想取消全选只需要点击另外任何一张图片或者屏幕内的黑色范围就可取消。

选择并拖拽文件夹内的图片


给图片加以标签说明


将标签导入图片上

在屏幕的下半部分,单击左侧的图片文件夹,会弹出该文件夹内所有的图片,通过手指上下移动,可以对所有的图片进行浏览,如果选择好其中的一张图片,直接用手指拖拽到操作界面上即可。另外通过屏幕中间最下方右边的标签功能,再结合触摸式键盘输入信息,可以给每一张图片添加标签说明,而被添加上标签的图片会自动保存到标签文件夹里,这样方便用户对图片的统一分配和整理。
      好了上面介绍了这么多关于Windows7的多点触摸图片应用程序,下面我们来打造自己的多点触摸图片处理应用程序,目标是将一个基于鼠标的简单图片操作应用程序升级为支持多点触摸的现代应用程序,类似于 Microsoft Surface 行为。

开发多点触摸图片处理应用程序

要理解如何管理多点触摸输入,我们首先需要理解如何处理(基于鼠标的)单点输入。为此,我们准备了一个基于鼠标的图片处理应用程序,就是多点触摸动手实验初始应用程序。

了解解决方案 

1.   打开位于 %TrainingKitInstallDir%/MultiTouch/Ex1-PictureHandling/Begin 下的初始解决方案,选择想要使用的语言C#。

2.   编译并运行它。可以进行的操作有:通过单击挑选一张图片;按住鼠标左键并移动鼠标来拖动图片;使用鼠标滚轮缩放图片。每次选择一张图片时,该图片就会出现在最前面。在开始编码之前,首先了解一下初始应用程序。

该应用程序用于处理图片。每张图片由一个 Picture 用户控件表示。这是一个非常简单的控件,它基于 WPF。Picture 用户控件的 XAML 如下:

XAML<UserControl x:Class="MultitouchHOL.Picture"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Image Source="{Binding Path=ImagePath}" Stretch="Fill" Width="Auto"Height="Auto"  RenderTransformOrigin="0.5, 0.5"><Image.RenderTransform><TransformGroup><RotateTransform Angle="{Binding Path=Angle}"></RotateTransform><ScaleTransform ScaleX="{Binding Path=ScaleX}" ScaleY="{Binding Path=ScaleY}"></ScaleTransform><TranslateTransform X="{Binding Path=X}" Y="{Binding Path=Y}"/></TransformGroup></Image.RenderTransform></Image></UserControl>

注意: 此用户控件的代码仅包括 ImagePath、Angle、ScaleX、ScaleY、X 和 Y 依赖属性的声明。ImagePath 是有效的图像文件或资源的路径。Angle 是图像的旋转角度。ScaleX 和 ScaleY 是图像的缩放系数,而 X、Y 是图像的中心位置。

3.  现在看一下 MainWindow 类。此 XAML 文件声明 MainWindow:

XAML<Window x:Class="MultitouchHOL.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="MultitouchHOL" Height="300" Width="300" WindowState="Maximized"xmlns:mt="clr-namespace:MultitouchHOL"><Canvas Name="_canvas"></Canvas></Window>

注意:此窗口仅包含一个画布元素 (_canvas)。画布是包含 Picture 用户控件实例的面板。

4.   现在打开 MainWindow.xaml.cs 。如果用户按住鼠标左键,_picture 成员将拥有当前跟踪的图片;否则,它将拥有空值。_prevLocation 是 Mouse Move 事件报告的上一个位置,用于计算偏移量。

5.   MainWindow 构造函数创建主窗口,注册各种事件处理函数。

public MainWindow(){InitializeComponent();//启用笔触事件和加载图片this.Loaded += (s, e) => { LoadPictures(); };//注册鼠标事件MouseLeftButtonDown += ProcessDown;MouseMove += ProcessMove;MouseLeftButtonUp += ProcessUp;MouseWheel += ProcessMouseWheel;}

6.    LoadPictures() 函数从用户的图片文件夹加载图片,并为所有图片创建一个 Picture 控件。它只在初始化画布之后才执行此操作。下面看一下 LoadPictures() 代码。

7.   现在看一下如何处理鼠标事件。

private void ProcessDown(object sender, MouseButtonEventArgs args){_prevLocation = args.GetPosition(_canvas);_picture = FindPicture(_prevMouseLocation);BringPictureToFront(_picture);}

按下鼠标左键将启动一个新的图片拖动会话。首先我们必须获得相对于画布的指针位置。我们将此信息保存在 _prevLocation 数据成员中。

8.  下一步是在该位置找到一张图片。FindPicture() 函数利用 WPF VisualTree 点击测试功能来找到最顶层的图片。如果鼠标所在位置没有图片,则返回空值。

9.    BringPictureToFront() 将所选图片的 Z 轴次序设置在其他图片的最顶层。

此处理程序的处理结果是 _picture 数据成员“记住”了所选的图片,_prevLocation 获取鼠标位置的代码片段。我们看一下当鼠标移动时会发生什么情况:

private void ProcessMove(object sender, MouseEventArgs args){if (args.LeftButton == MouseButtonState.Released || _picture == null)return;Point newLocation = args.GetPosition(_canvas);_picture.X += newLocation.X - _prevMouseLocation.X;_picture.Y += newLocation.Y - _prevMouseLocation.Y;_prevLocation = newLocation;}

如果用户未按下鼠标左键或者未选择任何图片,该函数将不执行任何操作。否则,该函数将计算平移量并更新图片的 X 和 Y 属性。它还将更新 _prevLocation。

10.  我们需要注意的最后一个函数是 ProcessMouseWheel:

private void ProcessMouseWheel(object sender, MouseWheelEventArgs args){Point location = args.GetPosition(_canvas);Picture picture = FindPicture(location);if (picture == null)return;BringPictureToFront(picture);double scalingFactor = 1 + args.Delta / 1000.0;picture.ScaleX *= scalingFactor;picture.ScaleY *= scalingFactor;}

将鼠标事件替换为触摸事件  

我们将删除鼠标事件并将其替换为触摸事件,以便使用我们的手指处理图片。

1. 将以下代码行添加到 MainWindow.xaml.cs 文件 (C#) 开头:

using Windows7.Multitouch;using Windows7.Multitouch.WPF;Visual BasicImports Windows7.MultitouchImports Windows7.Multitouch.WPF

2.  我们想要在 WPF 3.5 SP1 中实现多点触摸事件。为此,必须告诉系统以触笔事件的形式发出触摸事件。Windows 7 Integration Library 的 WPF Factory 类拥有一个函数来实现此功能,那就是 EnableStylusEvent。在 MainWindow Loaded 事件处理程序中添加对此函数的调用:

public MainWindow(){...//启用笔触事件和加载图片this.Loaded += (s, e) => { Factory.EnableStylusEvents(this); LoadPictures(); };...

3. 删除 ProcessMouseWheel 事件处理程序及相应的事件注册(我们将在稍后处理缩放)。

4. (仅适用于 C# 用户)删除 MouseLeftButtonDown、MouseMove 和 MouseLeftButtonUp 的事件注册代码。MainWindow 构造函数应该类似于以下代码:

public MainWindow(){InitializeComponent();if (!Windows7.Multitouch.TouchHandler.DigitizerCapabilities.IsMultiTouchReady){MessageBox.Show("Multitouch is not availible");Environment.Exit(1);}this.Loaded += (s, e) => { Factory.EnableStylusEvents(this); LoadPictures(); };}

5.   更改以下事件处理程序的签名和代码:

注意:此事件处理程序的签名已经更改。我们使用StylusEventArgs 代替与鼠标相关的事件参数。

(代码片段 – MultiTouch – StylusEventHandlers CSharp)

public void ProcessDown(object sender, StylusEventArgs args){_prevLocation = args.GetPosition(_canvas);_picture = FindPicture(_prevLocation);BringPictureToFront(_picture);}public void ProcessMove(object sender, StylusEventArgs args){if (_picture == null)return;Point newLocation = args.GetPosition(_canvas);_picture.X += newLocation.X - _prevLocation.X;_picture.Y += newLocation.Y - _prevLocation.Y;_prevLocation = newLocation;}public void ProcessUp(object sender, StylusEventArgs args){_picture = null;}

6. 注册触笔事件。

public MainWindow(){...//注册(触摸)事件StylusDown += ProcessDown;StylusUp += ProcessUp;StylusMove += ProcessMove;}

7.  编译并运行。使用手指代替鼠标!

注意: 如果尝试使用多个手指会发生什么情况?为什么?

 同时处理多张图片 

在本任务中,我们将添加多点触摸支持。触摸屏幕的每个手指都会获得一个唯一的触摸 ID。只要这根手指继续触摸屏幕,系统就会将相同的触摸 ID 与该手指关联。当手指离开屏幕表面时,该触摸 ID 将被系统释放并可被硬件再次使用。在我们的示例中,当一根手指触摸图片时,应该将该手指的唯一触摸 ID 与该图片关联,直到该手指离开屏幕。如果两个或更多手指同时触摸屏幕,那么每个手指都可以操作相关的图片。

当使用 Stylus 事件作为触摸事件时,可以从 Stylus 事件参数中提取出触摸 ID:args.StylusDevice.Id

WPF 将使用相关的 StylusDevice.Id(触摸 ID)不断为每个触摸屏幕的手指触发事件。

1.  我们需要同时跟踪多张图片。对于每张图片,触摸 ID、上一个位置与图片用户控件之间必须保持关联。我们将首先添加一个新的 PictureTracker 类:

注意:PictureTracker 类也在 %TrainingKitInstallDir%/MultiTouch/Assets/PictureHandling下以实验资源的形式提供,请选择您想要使用的语言(C#)。

/// <summary>/// 跟踪单个图片/// </summary>class PictureTracker{private Point _prevLocation;public Picture Picture { get; set; }public void ProcessDown(Point location){_prevLocation = location;}public void ProcessMove(Point location){Picture.X += location.X - _prevLocation.X;Picture.Y += location.Y - _prevLocation.Y;_prevLocation = location;}public void ProcessUp(Point location){//什么都不做,可能有另一个触摸ID仍下跌}}

2.  现在我们需要一个词典,以将活动的触摸 ID 映射到相应的 PictureTracker 实例。我们将创建一个 PictureTrackerManager 类来包含该词典并处理各种触摸事件。无论何时触发了触摸事件,PictureTrackerManager 都将尝试找到关联的 PictureTracker 实例并要求它处理该触摸事件。换言之,PictureTrackerManager 将获得触摸事件。它寻找作为实际事件目标的 PictureTracker 实例并将触摸事件分派给它。现在的问题是如何找到正确的 PictureTracker 实例。我们需要考虑一些不同的场景:

a.  发生 ProcessDown 事件时,有 3 种选择:

i.              手指触摸一个空位置。不会发生任何事件。

ii.             手指触摸新图片。必须创建一个新 PictureTracker 实例,必须在触摸 ID 映射中创建一个新条目。

iii.            第 2 个(或更多)手指触摸已经被跟踪的图片。我们必须将新的触摸 ID 与相同的 PictureTracker 实例相关联。

b.            发生 ProcessMove 事件时,有 2 种选择:

i.              手指的触摸 ID 未与一个 PictureTracker 相关联。不应该发生任何事件。

ii.             手指的触摸 ID 与一个 PictureTracker 关联。我们需要将事件转发给它。

c.             发生 ProcessUp 事件时,有 2 种选择:

i.              删除了一个手指触摸 ID,但是至少还存在一个相关的触摸 ID。我们需要从映射中删除此条目。

ii.             删除了最后一个相关的触摸 ID。我们需要从映射中删除该条目。图片跟踪器不再使用并且会被当作垃圾收集走。

3.            通过分析这些情形,我们可以定义 PictureTrackerManager 的设计条件:

a.            它必须拥有一个映射:触摸 ID PictureTracker

private readonly Dictionary<int, PictureTracker> _pictureTrackerMap

4.   添加以下 PictureTrackerManager 类:

注意:PictureTrackerManager 类也以实验资产的形式在 %TrainingKitInstallDir%/MultiTouch/Assets/PictureHandling 下提供,

class PictureTrackerManager{//图片之间的接触和ID跟踪private readonly Dictionary<int, PictureTracker> _pictureTrackerMap = new Dictionary<int, PictureTracker>();private readonly Canvas _canvas;public PictureTrackerManager(Canvas canvas){_canvas = canvas;}public void ProcessDown(object sender, StylusEventArgs args){Point location = args.GetPosition(_canvas);PictureTracker pictureTracker = GetPictureTracker(args.StylusDevice.Id, location);if (pictureTracker == null)return;pictureTracker.ProcessDown(location);}public void ProcessUp(object sender, StylusEventArgs args){Point location = args.GetPosition(_canvas);PictureTracker pictureTracker = GetPictureTracker(args.StylusDevice.Id);if (pictureTracker == null)return;pictureTracker.ProcessUp(location);_pictureTrackerMap.Remove(args.StylusDevice.Id);}public void ProcessMove(object sender, StylusEventArgs args){PictureTracker pictureTracker = GetPictureTracker(args.StylusDevice.Id);if (pictureTracker == null)return;Point location = args.GetPosition(_canvas);pictureTracker.ProcessMove(location);}private PictureTracker GetPictureTracker(int touchId){PictureTracker pictureTracker = null;_pictureTrackerMap.TryGetValue(touchId, out pictureTracker);return pictureTracker;}private PictureTracker GetPictureTracker(int touchId, Point location){PictureTracker pictureTracker;//我们已经根据笔触ID追踪到了图片if (_pictureTrackerMap.TryGetValue(touchId, out pictureTracker))return pictureTracker;//获取图片下的触摸位置Picture picture = FindPicture(location);if (picture == null)return null;//我们根据其他ID来追踪图片pictureTracker = (from KeyValuePair<int, PictureTracker> entry in _pictureTrackerMapwhere entry.Value.Picture == pictureselect entry.Value).FirstOrDefault();//第一次if (pictureTracker == null){//创建pictureTracker = new PictureTracker();pictureTracker.Picture = picture;BringPictureToFront(picture);}//记得接触ID和图片之间的相关性实证分析_pictureTrackerMap[touchId] = pictureTracker;return pictureTracker;}/// <summary>/// 在触摸位置中找到图片/// </summary>/// <param name="pointF">触摸位置</param>/// <returns>空的图片或照片,如果没有在触摸位置存在</returns>private Picture FindPicture(Point location){HitTestResult result = VisualTreeHelper.HitTest(_canvas, location);if (result == null)return null;Image image = result.VisualHit as Image;if (image == null)return null;return image.Parent as Picture;}private void BringPictureToFront(Picture picture){if (picture == null)return;var children = (from UIElement child in _canvas.Childrenwhere child != pictureorderby Canvas.GetZIndex(child)select child).ToArray();for (int i = 0; i < children.Length; ++i){Canvas.SetZIndex(children[i], i);}Canvas.SetZIndex(picture, children.Length);}}

5.   将以下字段声明添加到 MainWindow 类的开头:

private readonly PictureTrackerManager _pictureTrackerManager;

6.   修改 MainWindow 构造函数:

a.   在调用 InitializeComponent() 之后,添加管理器初始化:

_pictureTrackerManager = new PictureTrackerManager(_canvas);

b.  更改触笔事件注册代码

//Register for stylus (touch) eventsStylusDown += _pictureTrackerManager.ProcessDown;StylusUp += _pictureTrackerManager.ProcessUp;StylusMove += _pictureTrackerManager.ProcessMove;

7.   从 MainWindow 类删除 ProcessDown、ProcessMove 和 ProcessUp 事件处理程序。这里将不再需要它们,因为它们现在已包含在 PictureTrackerManager 类中。

8.    编译并运行。尝试同时抓取多张图片。尝试使用多个手指抓取一张图片。发生了什么情况?为什么?

<本内容未完待续...>

原文链接: http://blog.csdn.net/yincheng01/article/details/5546668

转载于:https://my.oschina.net/junwong/blog/47929

基于Visual C#2010开发Windows7应用 多点触摸图片处理应用程序(1)-同时处理多张图片...相关推荐

  1. 基于Visual C 2010开发Windows7应用 多点触摸图片处理应用程序 1 同时处理多张图片

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! wind ...

  2. 基于Visual C++ 2010开发Windows7应用 开发多点触控MFC应用程序

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 当下计算 ...

  3. 基于VisualC++2010开发Windows7杀毒应用程序范例(2)---检测并遍历所有进程的线程信息...

    作为一个杀毒软件,必须扫描所有的进程的每一个线程,才能分析出病毒的行为! 下面我们演示下,基于Visual C++2010开发基于Windows7杀毒应用程序范例, 检测所有的进程线程信息 打开VS2 ...

  4. 本人新书 Visual C#2010开发权威指南出版-感谢大家一如既往的支持-感谢CSDN总裁蒋涛以及他率领的CSDN团队提供的支持!

    http://book.360buy.com/11111014.html <visual c#2010开发权威指南>  第1章.net 4.0 框架和visual studio 2010开 ...

  5. 基于Visual C++2010与windows SDK fo windows7开发Windows 7的多点触摸特性应用程序(1)

    2008年5月28日,微软即将退休的精神领袖比尔·盖茨和首席执行官史蒂夫·鲍尔默共同在北圣地亚哥四季艾维亚拉洲际度假村举办的2008 D6 All Things数字化大会上向到场的嘉宾展示了windo ...

  6. CSDN著名技术专家Visual C++2010开发体验心得——从Visual C++6 0到Visual C++201

    IT业是一个创造奇迹的行业,IT业也是一个年轻的行业,IT业更是一个不断更新的行业.在2009年,微软已经连续推出Visual Studio2010 beta1 与 Visual Studio2010 ...

  7. CSDN著名技术专家Visual C++2010开发体验心得——从Visual C++6.0到Visual C++2010见证VC++辉煌时刻

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! IT业是 ...

  8. 基于Visual Graph快速开发出电力系统

    一.如何快速拥有自主知识产权的高品质的电力系统 每一个与电力相关的公司都想拥有自主知识产权的电力系统产品,让公司的价值能得到快速的提升,让公司在同行的竞争力大幅度提高,让公司的产品技术水平迅速达到同行 ...

  9. 为 Visual Studio 2010 开发扩展插件

    之前看到有国外的大神开发了一些非常好玩的 Visual Studio 扩展插件,觉得非常有意思,自己也参考了别人的代码做了一个插件. 首先需要安装 Visual Studio SDK ,安装不需要其它 ...

最新文章

  1. html5移动站点是什么,浅谈移动站点优化之痛-HTML5 什么是html5?
  2. MDX学习笔记(整理) MDX语法
  3. android ViewPager页面左右滑动切换
  4. h2 mysql 差别_h2内存数据库和mysql数据库的区别
  5. how you can go to attend eap freely?
  6. delphi xe http 收不到反馈消息_好消息接二连三!苹果将在双·11当天举办发布会_笔记本新闻...
  7. java接口等待几秒再返回_怎样才能在UI线程中等待okhttp返回结果才进行下一步
  8. stein法求gcd 学习笔记
  9. java default parameter_Java Parameter.DefaultBounds方法代码示例
  10. 汇编语言笔记(一):基础
  11. 云漫圈 | 计数排序,你真的了解么?
  12. 【SQL 数据库】将一张数据表信息复制到另一张数据表
  13. PGPDesktopWin32-10.2.0 加密与签名-软件实验8
  14. python的jira库操作
  15. 装系统:主分区、扩展分区、逻辑分区,引导(启动)分区、系统分区、活动分区
  16. ES6模板字符串中使用变量
  17. 第一行代码-第二版(郭霖著)笔记七(Content Provider)
  18. 小升初 择校简历标准
  19. 数字小写到英文大写的转换
  20. MIUI打开相册怎么默认显示全部照片_小米手机让相册默认展示所有图片怎么设置?

热门文章

  1. 物联网终端安全自动化扫描系统
  2. a标签去下划线或文字添加下修饰_a标签下划线(如何去掉a标签下划线)
  3. Premiere Pro 2.0 添加视频滤镜
  4. # Linux系统操作(九)
  5. stata解决内生性问题--样本选择
  6. 相机标定序列——基于3D立体靶标标定
  7. ASP.NET-酒店管理系统
  8. php react ssr,React-SSR
  9. 关于Vue中常用指令总结
  10. 指定未知的错误:0x80240037