Quatre 2D的绘图功能的三个步骤(上下文,绘图,渲染)

一、qurza2d是怎么将绘图信息和绘图的属性绘制到图形上下文中去的?

说明:

新建一个项目,自定义一个view类和storyboard关联后,重写该类中的drowrect方法。

画线的三个步骤:

(1)获取上下文

(2)绘图

(3)渲染

要求:画两条单独的线

代码和效果图:

 1 - (void)drawRect:(CGRect)rect
 2 {
 3     //获取上下文
 4     CGContextRef ctx=UIGraphicsGetCurrentContext();
 5     //绘图
 6     //第一条线
 7     CGContextMoveToPoint(ctx, 20, 100);
 8     CGContextAddLineToPoint(ctx, 100, 320);
 9
10     //第二条线
11     CGContextMoveToPoint(ctx, 40, 200);
12     CGContextAddLineToPoint(ctx, 80, 100);
13     //渲染
14     CGContextStrokePath(ctx);
15
16 }

效果图:

设置线段的宽度:两头为圆形,颜色等。

代码和效果图(发现第二条线也被渲染成第一条线的样式和状态)

 1 - (void)drawRect:(CGRect)rect
 2 {
 3     //获取上下文
 4     CGContextRef ctx=UIGraphicsGetCurrentContext();
 5     //绘图
 6     //第一条线
 7     CGContextMoveToPoint(ctx, 20, 100);
 8     CGContextAddLineToPoint(ctx, 100, 320);
 9
10     //设置第一条线的状态
11     //设置线条的宽度
12     CGContextSetLineWidth(ctx, 12);
13     //设置线条的颜色
14     [[UIColor brownColor]set];
15     //设置线条两端的样式为圆角
16     CGContextSetLineCap(ctx,kCGLineCapRound);
17     //对线条进行渲染
18     CGContextStrokePath(ctx);
19
20     //第二条线
21     CGContextMoveToPoint(ctx, 40, 200);
22     CGContextAddLineToPoint(ctx, 80, 100);
23     //渲染
24     CGContextStrokePath(ctx);
25
26 }

效果图:

新的需求:要让两条线的颜色不一样,要求第二条线变成原版的样子。要达到上面的要求,有以下几种做法:

第一种做法:

在对第二条线进行设置的时候,清空它的状态

 1 - (void)drawRect:(CGRect)rect
 2 {
 3     //获取上下文
 4     CGContextRef ctx=UIGraphicsGetCurrentContext();
 5     //绘图
 6     //第一条线
 7     CGContextMoveToPoint(ctx, 20, 100);
 8     CGContextAddLineToPoint(ctx, 100, 320);
 9
10     //设置第一条线的状态
11     //设置线条的宽度
12     CGContextSetLineWidth(ctx, 12);
13     //设置线条的颜色
14     [[UIColor brownColor]set];
15     //设置线条两端的样式为圆角
16     CGContextSetLineCap(ctx,kCGLineCapRound);
17     //对线条进行渲染
18     CGContextStrokePath(ctx);
19
20     //第二条线
21     CGContextMoveToPoint(ctx, 40, 200);
22     CGContextAddLineToPoint(ctx, 80, 100);
23
24     //清空状态
25     CGContextSetLineWidth(ctx, 1);
26     [[UIColor blackColor]set];
27     CGContextSetLineCap(ctx,kCGLineCapButt);
28
29     //渲染
30     CGContextStrokePath(ctx);
31
32 }

第二种做法:

把第一条线从开始绘制到渲染的代码剪切到第二条线渲染完成之后,这样先绘制并渲染了第一条线,该线并没有对绘制信息进行过设置,显示出来的第二条线即位系统默认的效果。

 1 - (void)drawRect:(CGRect)rect
 2 {
 3     //获取上下文
 4     CGContextRef ctx=UIGraphicsGetCurrentContext();
 5     //绘图
 6
 7     //第二条线
 8     CGContextMoveToPoint(ctx, 40, 200);
 9     CGContextAddLineToPoint(ctx, 80, 100);
10
11     //清空状态
12     //    CGContextSetLineWidth(ctx, 1);
13     //    [[UIColor blackColor]set];
14
15     //    CGContextSetLineCap(ctx,kCGLineCapButt);
16
17     //渲染
18     CGContextStrokePath(ctx);
19
20     //第一条线
21     CGContextMoveToPoint(ctx, 20, 100);
22     CGContextAddLineToPoint(ctx, 100, 320);
23
24     //设置第一条线的状态
25     //设置线条的宽度
26     CGContextSetLineWidth(ctx, 12);
27     //设置线条的颜色
28     [[UIColor brownColor]set];
29     //设置线条两端的样式为圆角
30     CGContextSetLineCap(ctx,kCGLineCapRound);
31     //对线条进行渲染
32     CGContextStrokePath(ctx);
33 }

两种方式完成的效果相同:

但是有的情况下,必须要先画第一条线再画第二条线,要求在交叉部分,第二条线盖在第一条线的上面。如果要求是这样,那么只能使用第一种做法,但是如果现在有新的需求,要求在这个基础上再画两条线,那就需要清空ctx中的状态很多次,很麻烦。为了解决这个问题,下面给大家介绍图形上下文栈。

二、绘图的完整过程

程序启动,显示自定义的view。当程序第一次显示在我们眼前的时候,程序会调用drawRect:方法,在里面获取了图形上下文(在内存中拥有了),然后利用图形上下文保存绘图信息,可以理解为图形上下文中有一块区域用来保存绘图信息,有一块区域用来保存绘图的状态(线宽,圆角,颜色)。直线不是直接绘制到view上的,可以理解为在图形上下文中有一块单独的区域用来先绘制图形,当调用渲染方法的时候,再把绘制好的图形显示到view上去。

在绘制图形区域,会去保存绘图状态区域中查找对应的状态信息(线宽,圆角,颜色),然后在绘图区域把对第一条直线绘制完成。其实在渲染之前,就已经把直线在绘制图形区域画好了。

如图:

     

说明:这些示意图和本文中的程序代码块,不具备一一对应关系,只是为了说明绘图的完整过程。

调用渲染方法的时候,把绘制图形区域已经画好的图形直接显示到view上,就是我们看到的样子了。

如图:

   

画第二条的时候,如果没有对绘图状态进行重新设置,那么可以发现画第一天线的时候使用的绘图状态还保存在图形上下文中,在第二条线进行渲染之前,会根据第一条线(上一份绘图状态)对第二条线进行相应的设置,渲染后把第二条线显示到屏幕上。

参考代码:

 1 - (void)drawRect:(CGRect)rect
 2 {
 3     //获取上下文
 4     CGContextRef ctx=UIGraphicsGetCurrentContext();
 5     //绘图
 6     //第一条线
 7     CGContextMoveToPoint(ctx, 20, 100);
 8     CGContextAddLineToPoint(ctx, 100, 320);
 9
10     //设置第一条线的状态
11     //设置线条的宽度
12     CGContextSetLineWidth(ctx, 12);
13     //设置线条的颜色
14     [[UIColor brownColor]set];
15     //设置线条两端的样式为圆角
16     CGContextSetLineCap(ctx,kCGLineCapRound);
17     //对线条进行渲染
18     CGContextStrokePath(ctx);
19
20     //第二条线
21     CGContextMoveToPoint(ctx, 40, 200);
22     CGContextAddLineToPoint(ctx, 80, 100);
23     //渲染
24     CGContextStrokePath(ctx);
25 }

如果清空了状态,则在渲染之前,在绘制图形区域对第二条线进行绘制的时候,会去查找当前的绘图信息(已经更改——清空),根据绘图信息对第二条线进行绘制,调用渲染方法的时候把第二条线显示到view上。

参考代码:

 1 - (void)drawRect:(CGRect)rect
 2 {
 3     //获取上下文
 4     CGContextRef ctx=UIGraphicsGetCurrentContext();
 5     //绘图
 6     //第一条线
 7     CGContextMoveToPoint(ctx, 20, 100);
 8     CGContextAddLineToPoint(ctx, 100, 320);
 9
10     //设置第一条线的状态
11     //设置线条的宽度
12     CGContextSetLineWidth(ctx, 12);
13     //设置线条的颜色
14     [[UIColor brownColor]set];
15     //设置线条两端的样式为圆角
16     CGContextSetLineCap(ctx,kCGLineCapRound);
17     //对线条进行渲染
18     CGContextStrokePath(ctx);
19
20     //第二条线
21     CGContextMoveToPoint(ctx, 40, 200);
22     CGContextAddLineToPoint(ctx, 80, 100);
23
24     //清空状态
25     CGContextSetLineWidth(ctx, 1);
26     [[UIColor blackColor]set];
27     CGContextSetLineCap(ctx,kCGLineCapButt);
28
29     //渲染
30     CGContextStrokePath(ctx);
31 }

三、图形上下文栈

1.简单说明

在获取图形上下文之后,通过

CGContextSaveGState(ctx);

方法,把当前获取的上下文拷贝一份,保存一份最纯洁的图形上下文。

在画第二条线之前,使用CGContextRestoreGState(ctx);方法,还原开始的时候保存的那份最纯洁的图形上下文。

代码:

 1 - (void)drawRect:(CGRect)rect
 2 {
 3     //获取上下文
 4     CGContextRef ctx=UIGraphicsGetCurrentContext();
 5     //保存一份最初的图形上下文
 6     CGContextSaveGState(ctx);
 7
 8     //绘图
 9     //第一条线
10     CGContextMoveToPoint(ctx, 20, 100);
11     CGContextAddLineToPoint(ctx, 100, 320);
12
13     //设置第一条线的状态
14     //设置线条的宽度
15     CGContextSetLineWidth(ctx, 12);
16     //设置线条的颜色
17     [[UIColor brownColor]set];
18     //设置线条两端的样式为圆角
19     CGContextSetLineCap(ctx,kCGLineCapRound);
20     //对线条进行渲染
21     CGContextStrokePath(ctx);
22
23     //还原开始的时候保存的那份最纯洁的图形上下文
24     CGContextRestoreGState(ctx);
25     //第二条线
26     CGContextMoveToPoint(ctx, 40, 200);
27     CGContextAddLineToPoint(ctx, 80, 100);
28
29     //清空状态
30 //    CGContextSetLineWidth(ctx, 1);
31 //    [[UIColor blackColor]set];
32 //    CGContextSetLineCap(ctx,kCGLineCapButt);
33
34     //渲染
35     CGContextStrokePath(ctx);
36 }

2.图形上下文栈机制

画第一条线的时候,会把当前的图形上下文拷贝一份保存到图形上下文栈中。

画第二条线的时候,去图形上下文栈中取出栈顶的绘图信息,作为第二条线的状态信息,第二条线的状态信息也是据此(最初保存的那份图形上下文)进行绘制。

          

注意:在栈里保存了几次,那么就可以取几次(比如不能保存了1次,取两次,在取第二次的时候,栈里为空会直接挂掉)。

时间: 2024-09-28 22:47:06

Quatre 2D的绘图功能的三个步骤(上下文,绘图,渲染)的相关文章

Delphi 的绘图功能[10] - TFONT 类

Delphi 的绘图功能[10] - TFONT 类 //TFont 类的常用属性: {Name: 字体名称} {Color: 颜色} {Size.Height: 字号与字体高度, 都可以设定字体大小} {Style: 字体样式; 是个集合值, 是下面可选值或它们的组合:}fsBoldfsItalicfsUnderlinefsStrikeOut {Pitch: 是字间距相关的, 有三个枚举值可选(不过我没测试出效果):}fpDefaultfpVariablefpFixed {Charset: 字

Matlab学习笔记——基本绘图功能

MATLAB两种基本绘图功能:二维平面图形和三维立体图形 一.二维平面图形 1.基本图形函数 plot是绘制二维图形的最基本函数,它是针对向量或矩阵的列来绘制曲线的.也就是说,使用plot函数之前,必须首先定义好曲线上每一点的x 及y 坐标,常用格式为: (1)plot(x) 当x 为一向量时,以x元素的值为纵坐标,x的序号为横坐标值绘制曲线.当x为一实矩阵时,则以其序号为横坐标,按列绘制每列元素值相对于其序号的曲线,当x 为m× n 矩阵时,就由n 条曲线. (2)plot(x,y) 以x 元

用函数实现登陆功能(三次机会),然后在主函数中根据调用后的结果判断 登陆成功与否。

/*3.用函数实现登陆功能(三次机会),然后在主函数中根据调用后的结果判断登陆成功与否.*/#include <string.h>int numb(char use[] ,char password[] ){ if((strcmp(use,"zhouyi")==0)&&(strcmp(password,"nb")==0)) { return 1; } else { return 0; } } #include <stdio.h>

(原)SQL Server 系统提供功能的三个疑惑

本文目录列表: 1.SQL Server系统提供的部分疑惑概述2.系统函数调用时DEFAULT代替可选参数使用不统一3.队列字段列message_enqueue_time记录的是UTC日期时间 4.@@Pack_Received系统函数提示信息有错误 5.总结语6.参考清单列表 正文: 1.SQL Server系统提供的部分疑惑概述   近来工作之余一直在系统地学习和研究SQL Server 数据库引擎这一整块,发现了一些原来没有太注意的东西,感觉SQL Server 光数据库引擎这块就有很多要

Matlab中利用mex编译Opencv实现画板绘图功能

图形绘制是标记和可视化数据的重要方法. 通过在Matlab中集成画板绘图功能, 可为科学计算提供便利. 1 设置Matlab支持Opencv编译 操作系统: 麒麟14.04(基于Ubuntu 14.04) 命令: mex -v -> mexopts.sh sourced from directory (DIR = $MATLAB/bin) FILE = /usr/local/MATLAB/R2013a/bin/mexopts.sh --------------------------------

Java实现ping功能的三种方法

Java实现ping功能的三种方法 检测设备的运行状态,有的是使用ping的方式来检测的.所以需要使用java来实现ping功能. 为了使用java来实现ping的功能,有人推荐使用java的 Runtime.exec()方法来直接调用系统的Ping命令,也有人完成了纯Java实现Ping的程序,使用的是Java的NIO包(native io, 高效IO包).但是设备检测只是想测试一个远程主机是否可用.所以,可以使用以下三种方式来实现: 1.Jdk1.5的InetAddresss方式 自从Jav

使用snmp4j实现Snmp功能(三)

相关链接:Snmp学习笔记使用snmp4j实现Snmp功能(一)使用snmp4j实现Snmp功能(二)使用snmp4j实现Snmp功能(三) 前两篇文章讲了如何使用Snmp4j实现Set.Get(使用snmp4j实现Snmp功能(一))以及发送.接收Trap(使用snmp4j实现Snmp功能(二)) 功能. 在我们前面的实现中,如果访问MIB库中不存在的OID,Get方式的话,我们会得到一个Null值,而Set方式时Agent端会把我们发过去的 PDU原封不动的返回回来.当然多数情况下这不是我们

Kivy 中文教程 实例入门 简易画板 (Simple Paint App):2. 实现绘图功能

1. 理解 kivy 坐标系统 上一节中,咪博士带大家实现了画板程序的基础框架,以及一个基本的自定义窗口部件(widget).在上一节的末尾,咪博士留了一道关于 kivy 坐标系统的思考题给大家.通过点击窗口的 4 个角落,观察相应的控制台输出,我们可以推断出 kivy 的坐标原点位于窗口的左下角,x 轴正方向为水平向右,y 轴正方向为竖直向上.这和我们中学数学中常见的平面直角坐标系是一模一样的. 2. 绘制圆点 了解了 kivy 的坐标系统,本节咪博士将教大家实现简易画板的核心功能:绘图. 重

pandas.DataFarme内置的绘图功能参数说明

可视化是数据探索性分析及结果表达的一种非常重要的形式,因此打算写一个python绘图系列,本文是第一篇,先说一下pandas.DataFrame.plot()绘图功能. pandas.DataFrame.plot() 在0.23.4版本的pandas中,pandas.DataFrame.plot()中常用的参数有以下几个 x:横坐标上的标签,一般是DataFrame中某个column的名称,默认为None y:纵坐标上要显示的column,如果不指定column,则默认会绘制DataFrame中