VC++(十一)图形的保存和重绘

  • Invalidate使整个窗口客户区无效。
    窗口的客户区无效意味着需要重绘。Windows会在应用程序的消息队列里放置WM_PAINT消息。

  • UpdateWindow()的作用是使窗口立即重绘,可使WM_PAINT消息被直接发送到目标窗口,从而导致窗口立即重绘。

  • 坐标空间和转换
    Win32应用程序编程接口(API)使用四种坐标空间:世界坐标系空间、页面空间、设备空间、和物理设备空间。应用程序运用世界坐标系空间对图形输出进行旋转、斜切或者反射。
    Win32 API把世界坐标系空间和页面空间称为逻辑空间;最后一种坐标空间(即物理设备空间)通常指应用程序窗口的客户区;但是它也包括整个桌面、完整的窗口(包括框架、标题栏和菜单栏)或打印机的一页或绘图仪的一页纸。物理设备的尺寸随显示器、打印机或绘图仪所设置的尺寸而变化。

  • 如果该应用程序调用了SetWorldTransform函数,那么映射就从应用程序的世界坐标系空间开始;否则,映射在页面空间中进行。实际编程中,主要处理的是从页面空间到设备空间的转换。

  • 逻辑坐标和设备坐标
    几乎在所有的GDI函数中使用的坐标值都是采用的逻辑单位。Windows必须将逻辑单位转换为“设备单位”,即像素。这种转换是由映射方式、窗口和视口的原点以及窗口和视口的范围所控制的。
    Windows对所有的消息(如WM_SIZE、WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_LBUTTONUP),所有的非GDI函数和一些GDI函数(例如GetDeviceCaps函数),永远使用设备坐标。

  • 窗口和视口
    窗口是基于逻辑坐标的,逻辑坐标以cm mm为单位
    视口是基于设备坐标的,设备坐标以像素为单位

  • 两个原则:
    1.总是由窗口原点映射为视口原点。即无论你窗口的原点和视口的原点怎么变,窗口的原点总是映射到视口的原点。(记住:映射方向是窗口到视口,而不是视口向窗口映射)
    2.不管利用函数(如:SetViewportOrgExt和SetWindowOrgEx)对窗口和视口的原点做怎么改变,设备点(0,0)始终是客户区的左上角。

  • 移动窗口和视口的原点
    SetWindowOrg(100, -300)则逻辑点(100,-300)映射为设备点(0,0)
    SetViewportOrg(100, -300)则逻辑点(0,00)映射为设备点(100,-300)
    不管原点怎么变化,永远都是原点映射到原点。

  • CPtrArray对象存储多个对象的地址。

  • OnPaint 和 OnDraw
    窗口重绘时会发送一个WM_PAINT消息:消息响应函数OnPaint().
    CView类派生自CWnd类。
    OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。
    OnDraw()是CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你用VC成的程序代码时,在视图类只有 OnDraw没有OnPaint的原因。

  • 要想在屏幕上绘图或显示图形,首先需要建立设备环境DC。其实DC是一个数据结构,它包含输出设备的绘图属性的描述。MFC提供了CPaintDC类和CWindwoDC类来实时的响应,而CPaintDC支持重画。

  • 当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint 处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调用视图的 OnDraw 成员函数。通常我们不必编写重写的 OnPaint 处理成员函数。

//CView默认的标准的重画函数
void CView::OnPaint()
{
    CPaintDC dc(this);
    OnPreparDC(&dc);
    OnDraw(&dc); //调用了OnDraw
}

既然OnPaint最后也要调用OnDraw,因此我们一般会在OnDraw函数中进行绘制。下面是一个典型的程序

///视图中的绘图代码首先检索指向文档的指针,然后通过DC进行绘图调用。
void CMyView::OnDraw( CDC* pDC )
{ 
    CMyDoc* pDoc = GetDocument(); 
    CString s = pDoc->GetData(); // Returns a CString
    CRect rect;
    GetClientRect( &rect ); 
    pDC->SetTextAlign( TA_BASELINE | TA_CENTER ); 
    pDC->TextOut( rect.right / 2, rect.bottom / 2, s, s.GetLength() );
}

  • 设备环境(Device Context)(设备上下文)

  • 设备上下文DC是一个Windows数据结构,它包含了某个设备的绘制属性。通常,绘制调用都是借助于上下文对象,而这些设备上下文对象封装了用于画线、形状、文本等的Windows API。设备上下文是设备无关的,所以它既可以用于绘制屏幕,也可以用于绘制打印机甚至元文件。设备上下文在内存中创建,而内存经常受到扰动,所以它的地址是不固定的。因此,一个设备上下文句柄不是直接指向设备上下文对象,而是指向另外一个跟踪设备上下文地址的指针。

  • 我个人认为设备上下文相当于画图过程中的画布(画纸),在VC中,这个画布可以是显示器,也可以使打印机,设备上下文决定了画布的属性,而且封装了在画布上画画的方法,比如画线,画点,等等,例如: pDc->LineTo(512,0); //从左下角到右上角的一条红色直线 。我们在VC中画图时,首先要得到这块画布才可以画画,所以要进行获取设备环境。

常见设备上下文及区别:

  • CClientDC,CPaintDC,CWindowDC

  • CClientDC:(客户区设备上下文)用于客户区的输出,与特定窗口关联,可以让开发者访问目标窗口中客户区,其构造函数中包含了GetDC,析构函数中包含了ReleaseDC。只能在客户区绘制图形。

  • CPaintDC:只能在客户区绘制图形。
    (1)CPaintDC类是CDC类的一个派生类,该类一般用在响应WM_PAINT消息的函数OnPaint()中。
    (2)WM_PAINT消息是当窗口的某个区域需要重画时激发的窗口消息。当程序中的消息循环接到WM_PAINT消息时就自动调用消息处理函数OnPaint(),如果在OnPaint函数内定义了CPaintDC类的对象,通过这个类对象就可以使用CDC类的成员函数完成视图客户区中的图形绘制操作。
    (3)CPaintDC用于响应窗口重绘消息(WM_PAINT)时的绘图输出。CPaintDC在构造函数中调用BeginPaint()取得设备上下文,在析构函数中调用EndPaint()释放设备上下文。EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT消息。因此,在处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消息队列中清除,将引起不断的窗口重画。CPaintDC也只能用在WM_PAINT消息处理之中。

  • CWindowsDC:
    (1)可在非客户区绘制图形,而CClientDC,CPaintDC只能在窗口的客户区绘制图形。
    (2)坐标原点是在窗口的左上角,CClientDC,CPaintDC下坐标原点是在客户区的左上角。

CDC:GetDC,ReleaseDC
CClientDC:GetDC,ReleaseDC封装起来,只能访问客户区
CWindowDC:GetDC,ReleaseDC封装起来,不仅仅可以访问客户区 
CPaintDC:窗口重绘时会发送一个WM_PAINT消息:消息响应函数OnPaint,调用CPaintDC

下面介绍一下获得这块画布的方法,即获取设备上下文的方法:

1、通过OnDraw()函数获得CPaintDC:在OnDraw()函数中入口参数CDC *pDC,传入操作的设备上下文,这个上下文是CPaintDC。
他是通过OnPaint()构建,并传入OnDraw(),View类如果没有重载OnPaint(),则窗口刷新时自动调用MFC底层代码的OnPaint()函数,
从而调用OnDraw()。我们就可以通过OnDraw()在客户区进行初始化的绘制。
2、通过CClientDC,CPaintDC,CWindowDC定义一个DC。
例如:CClientDC dc(this);创建一个dc,
在当前对象的客户区。创建一个CWindowDC类的对象:CWindowDC dc(this);
3、通过HDC GetDC(HWND hWnd);hWnd:设备上下文环境被检索的窗口的句柄,如果该值为NULL,
GetDC则检索整个屏幕的设备上下文环境,返回值是hdc,
即一个DC描述符,入口参数是一个窗口类型的句柄。

例如: pWnd=GetDlgItem(IDC_STATIC_PIC); //IDC_STATIC_PIC是对话框图片空间的一个标识号

pWnd->SetWindowPos(NULL,0,0,512,120,SWP_NOZORDER|SWP_NOMOVE); //调整长宽为(512,120)
pDc=pWnd->GetDC();
GDI及GDI函数
GDI对象就是绘画时用的工具,比如画笔,画刷,字体,位图,调色板。
如果绘图的时候,需要先把相应的GDI设备选入设备环境,就是为画图选个画笔,工具。
注意MFC中,GDI和CDC是两个独立的类
  • 窗口滚动功能的实现
    OnInitialUpdate
    视图窗口完全建立后第一个被框架调用的函数。框架在第一次调用OnDraw前会调用OnInitialUpdate,因此OnInitialUpdate是设置滚动视图的逻辑尺寸和映射模式的最合适的地方。

OnCreate()后窗口产生, 然后才是视图的OnInitialUpDate,一般在这里对视图的显示做初始化。

一、OnCreate和OnInitialUpDate

  • OnCreate()只是产生VIEW的基本结构和变量.OnCreate()不产生窗口,只是在窗口显示前设置窗口的属性如风格位置等。create负责注册并产生窗口。
    OnInitialUpDate()中,主要初始化视图中控件等。对各个变量进行初始化操作。

  • OnCreate()是生成结构的
    OnInitialUpDate()是对结构进行初始化。
    两个一个相当于硬件一个相当于软件,功能和作用完全不同。

  • OnCreate
    oncreate 消息响应函数,是用来“表示一个窗口正在生成”。
    在CWnd::Create中,又会调用OnCreate函数,但是实际上这个时候Create函数还没有退出,CWnd的某些部分还没有创建好。

  • create()不是对应于消息wm_create的,oncreate()才是。
    create()只用于产生窗口,像动态创建控件中的create()一样。

  • 设备坐标(0,0)点始终位于窗口客户区的左上角。

  • 两种保存图形和重绘图形的方式:元文件和兼容设备描述表
    元文件
    元文件设备上下文类:CMetaFileDC
    元文件并没有包含所绘图形的图形数据,它包含的是图形的绘制命令。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Windows 95中文输入法编辑器(IME) 微软 翻译:TBsoft Software Studio ...
    returntrue阅读 2,621评论 0 3
  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低...
    ShanJiJi阅读 1,523评论 0 20
  • 5.20 正如我用卑微的姿态祈求的,结果也以卑微的姿态呈现在我面前。 只是想让室友们帮忙分享一下我写的东西,可笑的...
    十八岁的花边阅读 317评论 0 0
  • 我的孩子今年五年级了,但他的书写总是不那么美观。每次写作业,我都告诉他,认真书写。他总是时好时坏。 ...
    向小雅阅读 724评论 0 3