码迷,mamicode.com
首页 > Windows程序 > 详细

【Win 10 应用开发】UI Composition 札记(四):绘制图形

时间:2017-11-09 14:24:13      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:引用   ima   rect   send   position   bsp   nta   绘制   并且   

使用 Win 2D 组件,就可以很轻松地绘制各种图形,哪怕你没有 D2D 相关基础,也不必写很复杂的 C++ 代码。

先来说说如何获取 Win 2D 组件。很简单,创建 UWP 应用项目后,你打开“解决方案资源管理器”窗口,然后在【引用】节点上右击,从快捷菜单中选择【管理 Nuget 程序包】命令,在打开的窗口中搜索“Win 2D”,然后安装带有 uwp 标识的那个就可以了。

技术分享

 

顺便说一下,nuget 的包缓存在你的用户文件夹下,就是系统盘下的 \users\xxx,xxx是你登录系统的用户名,在文件夹下有个 .nuget 目录,\packages 子目录下就是缓存的包,大小取决你安装的组件,大的时候 4、5 个G也有的。

 

在你的应用项目中,VS 只是创建了一个 JSON 文件来描述你引用的组件,Win 2D 添加引用成功后,你的引用列表应该是这样的。

技术分享

你如果看到 Win2D.uwp 这个项目,那就没问题了。

 

不过,你得注意,直接双击它是无法在“对象浏览器”中查看的,你可以这样:打开“对象浏览器”窗口,然后把浏览的子集改为“我的解决方案”,这样,你就能看到你当前项目中所有引用的组件的类型结构了。

技术分享

 

 现在,你就能看到 Win2D 库的基本内容了。

技术分享

Microsoft.Graphics.Canvas 以及它的子命名空间都是 Win2D 组件中的类型。

 

其实,使用 Win2D 组件,你完全可以很简单地绘制各种玩意儿,因为在 Microsoft.Graphics.Canvas.UI.Xaml 命名空间下,直接就提供了一些控件,你可以直接用到 XAML 文档中,然后要画什么就用代码画就行了。比如,我介绍两个比较典型的。

* CanvasControl —— 可以绘制各种你想要的东东,它就相当于一块画布,用代码绘制时须处理 Draw 事件,然后就在事件处理代码中随便 draw。

* CanvasAnimatedControl —— 跟上面的那个家伙差不多,只是它可以在你绘制的内容上产生动画。

大伙会看到,这两个控件都有一个 CreateResources 事件,用来干什么鸟的呢?它的作用是这样的,你可以在处理这个事件的代码中实例化一些资源,这些资源一般在绘制过程不会频繁改动的,比如加载的某个图片,某个画刷等。

 

下面给大伙简单演示一下 CanvasControl 控件的用法。

在 XAML 文档中先要引入命名空间。

<Page
    ……
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" …… xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"> </Page>

然后就可以用了。

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <canvas:CanvasControl Draw="OnDraw"/>
    </Grid>

接着处理 Draw 事件,我们画上几笔试试手。要画东东,我们要用到 Microsoft.Graphics.Canvas 命名空间下的另一个类——CanvasDrawingSession,它公开了许多 Draw 和 Fill 方法,Draw 是画出某个东东,Fill 是填充一个区域。

        private void OnDraw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
        {
            using (CanvasDrawingSession dss = args.DrawingSession)
            {
                // 画线
                dss.DrawLine(12f, 15f, 335f, 408f, Colors.DarkBlue, 5.5f);
                // 画矩形
                dss.DrawRectangle(55f, 190f, 465f, 369f, Colors.Gold, 8f);
                // 画圆
                dss.DrawEllipse(350f, 350f, 200f, 260f, Colors.Orange, 5f);
            }
        }

随便画几下,纯属鬼画符。效果如下图所示。

技术分享

 

但是,我们今天的主题是跟 UI Composition 有关的,虽然上述绘图法很超逸,却不是咱们今天的主题。我们下面要做的,是使用 Composition API 来呈现自己绘制的内容。

大伙伴们可以思考一下,要在 Composition 组装的对象上画东西,需要什么?前面咱们说过,你得有个 Brush,在 Composition API 中,只有一个画刷可以呈现自己绘制的内容,那就是 CompositionSurfaceBrush。

要创建 CompositionSurfaceBrush 实例容易,调用一下 Compositor.CreateSurfaceBrush 方法就行了。但问题的核心不在此,而在于,CompositionSurfaceBrush 画刷创建后是空的,要能够呈现内容,还得需要给 Surface 属性赋个值,它是一个实现了 ICompositionSurface 接口的类型,在 Composition API 中,实现了该接口的只有一个类:CompositionDrawingSurface。然而,你看到了,这个类是没有构造函数公开的,它是由 CompositionGraphicsDevice 类的 CreateDrawingSurface 方法创建的。

好,现在我们可以理一下思路了。

1、你必须想方设法得到一个 CompositionGraphicsDevice 实例,可该类没公开的构造函数,咋办?所以才要使用 Win2D,稍后再说,Win2D 会有办法获得这个实例的。

2、调用 CompositionGraphicsDevice 实例的 CreateDrawingSurface 或 CreateDrawingSurface2 方法创建 CompositionDrawingSurface

实例。

3、在新创建的 CompositionDrawingSurface 实例上画东西。这个也要用到 Win2D。

4、使用 Compositor 的静态方法直接创建 CompositionSurfaceBrush 对象,并与上面画好的 CompositionDrawingSurface 关联。

5、把这个画刷(CompositionSurfaceBrush)与可视化元素关联,比如,SpriteVisual类就有一个 Brush 属性。

 

如此一来,我们找到了两个难点:a、如何创建 CompositionGraphicsDevice ; b、如何在 Surface 上画东西(此 Surface 非彼 Surface)。

借助 Win2D,可以解决以上两个难题。我们不讲理论的,下面用实例来说明。

首先,在 XAML 文档中随便声明一个元素,只要是 UIElement 的子类就行。

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Canvas Name="myCvs"/>
    </Grid>

记得分配一个名字,待会在代码中要访问。

 

随后,我们就可以开始作画了。

        void DrawSomething()
        {
            // 获取 XAML 元素上的 Visual
            Visual canvasVisual = ElementCompositionPreview.GetElementVisual(myCvs);
            // 获取 Compositor 对象
            Compositor compos = canvasVisual.Compositor;
            // 创建 GraphicsDevice 
            CompositionGraphicsDevice graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compos, CanvasDevice.GetSharedDevice());
            // 创建 Surface
            // 画布的大小
            SizeInt32 cvsize = new SizeInt32
            {
                Width = 600,
                Height = 400
            };
            CompositionDrawingSurface surface = graphicsDevice.CreateDrawingSurface2(cvsize, Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized, Windows.Graphics.DirectX.DirectXAlphaMode.Premultiplied);
            // 开始绘画
            using (CanvasDrawingSession dss = CanvasComposition.CreateDrawingSession(surface))
            {
                // 刷墙,把墙面刷成黑色
                dss.Clear(Colors.Black);
                // 画一个圆
                dss.DrawEllipse(210f, 190f, 80f, 80f, Colors.Yellow, 4f);
                // 再画一个椭圆
                dss.DrawEllipse(230f, 200f, 160f, 95f, Colors.SkyBlue, 3.5f);
                // 填充一块区域
                dss.FillRectangle(400f, 250f, 150f, 100f, Colors.Pink);
            }
            // 创建 surface 画刷
            CompositionSurfaceBrush sfbrush = compos.CreateSurfaceBrush(surface);
            // 创建一个支持画刷的可视化对象
            SpriteVisual newVisual = compos.CreateSpriteVisual();
            // 设置画刷
            newVisual.Brush = sfbrush;
            // 注意要设置可视化对象的大小
            ExpressionAnimation anim = compos.CreateExpressionAnimation();
            anim.Expression = "parn.Size";
            anim.SetReferenceParameter("parn", canvasVisual);
            newVisual.StartAnimation("Size", anim);
            // 最后别忘了把新的可视化对象插入对象树
            ElementCompositionPreview.SetElementChildVisual(myCvs, newVisual);
        }

我们上篇中讲过的,与 XAML 交互,使用 ElementCompositionPreview辅助类可以获得与 XAML 元素对应的 Visual 实例,这样我们也能得到相关的 Compositor 对象了。

注意创建 CompositionGraphicsDevice 实例要借助 Win2D 的 CanvasComposition 类(位于 Microsoft.Graphics.Canvas.UI.Composition 命名空间),在调用 CreateCompositionGraphicsDevice 方法时,你除了得提供关联的 Compositor 对象外,还得有一个兼容的 CanvasDevice 对象。这个 CanvasDevice 对象有个很TMD简单的获取方法,就是直接调用它的 GetSharedDevice 静态方法。

好了,有了 CompositionGraphicsDevice 实例,那创建 CompositionDrawingSurface对象就好办了,就像这样。

 CompositionDrawingSurface surface = graphicsDevice.CreateDrawingSurface2(cvsize, Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized, Windows.Graphics.DirectX.DirectXAlphaMode.Premultiplied);

CreateDrawingSurface 和 CreateDrawingSurface2 都可以,带“2”的是使用整数来表示像素值。

调用这个方法最麻烦的后面两个参数,它们都是枚举值,如果值设置不当会发生异常,所以,如果出错了,你就得调整了。一般来说,在屏幕上显示的东东,我们会选择 BGRA 的顺序,因为这个顺序呈现出来不会偏色,尤其是图像,如果用 RGBA 就会偏色。B8G8R8A8 表示都用8位的值,也就是一个字节,这个我们平时处理一般图形也够用了(即32位颜色)。

接下来就是用 CanvasDrawingSession 来画你想画的各种玩意儿,画完后要创建一个 CompositionSurfaceBrush 对象,并且要与刚刚画好的 surface 对象关联。

最后用这个画刷填充一个支持画刷的可视化对象即可,如 SpriteVisual。记住,一定要设置对象的 Size 属性,因为默认值是0,不然它不会显示出来的,这里呢,我直接用一个表达式动画,让它的大小跟随 Canvas 的大小。

 

这个方法封装好后,可以在适当的地方调用,以绘制内容,比如页面类的构造函数中。

        public MainPage()
        {
            this.InitializeComponent();
            DrawSomething();
        }

 

好了,看看效果吧。

技术分享

 

 OK,今天的内容就说到这里了。

 

【Win 10 应用开发】UI Composition 札记(四):绘制图形

标签:引用   ima   rect   send   position   bsp   nta   绘制   并且   

原文地址:http://www.cnblogs.com/tcjiaan/p/7808377.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!