VC++例说Windows窗口、视口以及GDI映射模式2011-04-28 11:31:54|分类:默认分类|标签:窗口 视口 vc++ |字号大中小订阅在Windows应用程序中,只要进行绘图,就要使用GDI坐标系统Windows提供了几种映射方式,每一 种映射都对应着一种坐标系例如,绘制图形时,必须给出图形各个点在客户区的位置,其位置用x和y 两个坐标表示,x表示横坐标,y表示纵坐标在所有的GDI绘制函数中,这些坐标使用的是一种“逻辑单 位”当GDI函数将结果输出送到某个物理设备上时,Windows将逻辑坐标转换成设备坐标(如屏幕或打 印机的像素点)本文讨论了图形环境中的各个映射模式,包括它们是什么,怎么工作的,以及它们真正 的含义一、窗口、视口以及映射模式基本概念强调一个网上和教科书上没有将清楚但是至关重要的概念:窗口和视口其实是同一块矩形区域,两者坐标 系的原点是同一个点窗口和视口的区别仅仅是单位不同窗口和视口都不是指显示屏或打印机上的区域, 我们看到显示屏上的物体实际上是显示在“设备环境”上的,由于视口 (也就是窗口)区域与设备环境的左手 坐标系第一象限xoy平面有交集,我们才能看到视口中的物体。
窗口的变换和视口的变换的目的是一样的, 都是为了将物体显示在设备环境中,只不过由于视口中使用像素作为单位也就是显示屏的设备坐标,所以 往往在视口中进行调整de比较直观一些一) 逻辑坐标逻辑坐标即是世界坐标系下的坐标逻辑坐标与设备无关,客观世界中的场景可以由世 界窗口或视口中进行描述,在窗口中进行描述时使用世界坐标系中的坐标单位也即逻辑坐标,在视口中进 行描述使用的是设备坐标二) 设备坐标图形输出时‘Windows将GDI函数中指定的逻辑坐标映射为设备坐标在屏幕显示的设 备坐标系统中,单位以像素点为准,水平值从左到右增大(正方向向右),垂直值从上到下增大(正方向 向下)注意设备坐标系的原点永远不会移动,它们仅仅与物理设备有关设备空间的范围实际显示设备上的矩形区域,通常有三种范围:窗口的客户区(使用BeginPaint或 GetDC获取)全窗口(使用GetWindowDC获取)全屏幕(使用GetDc (0) / CreateDC获取);还有 一些特殊的设备空间,如内存设备空间(使用CreateCompatibleDC获取),打印机设备空间,元文件设 备空间即(CreateMetaFile) Windows中包括以下3种设备坐标,以满足各种不同需要:1、 客户区域坐标,包括应用程序的客户区域,客户区域的左上角为(0, 0)。
2、 屏幕坐标,包括整个屏幕,屏幕的左上角为0, 0)屏幕坐标用在WM_MOVE消息中(对于非子窗口)以及下面的 Windows 函数中:CreateWindow 和 MoveWindow(都对于非子窗口)、GetMessage、GetCursorPos、GetWindowRect、 WindowFromPoint和SetBrushOrg 中用函数ClientToScreen和ScreenToClient可以将客户区域坐标转换成屏幕区域坐 标,或反之3、 全窗口坐标,包括一个程序的整个窗口,包括标题条、菜单、滚动条和窗口框,窗口的左上角为(0,0)使用GetWindowDC 得到的窗口设备环境,可以将逻辑单位转换成窗口'坐标三) 映射模式映射方式定义了 Windows如何将GDI函数中指定的逻辑坐标映射为设备坐标Windows 为了程序员方便,允许程序员在一个假想的空间上(世界坐标系中)绘制图形,这就是逻辑空间,但是最 终这些图形还是需要显示到真实的屏幕或打印机,这就是设备空间此时就会出现一个问题,即如何将逻 辑空间中的图形通过怎样的关联适当的显示在屏幕上呢? Windows给出了答案一映射模式,Windows内定 了 8种映射模式,其中有常用的6种固定的模式(MM_TEXT、MM_LOMETRIC、MM_HIMETRIC、 MM_LOENGLISH、MM_HIENGLISH、MM_TWIPS)把逻辑单位及数轴的方向都确定好了,还有2种允 许自行定义逻辑单位及数轴方向。
这两种模式的区别在于MM」SOTROPIC要求必须横纵两轴的逻辑单位 必须是相等的,而MM_ANISOTROPIC是绝对的自定义,没有任何限制设备坐标系始终是左手 坐标系且以显示区域的左上角的(0,0)点作为坐标原点,水平向右为x轴的正方 向,垂直向下为y轴的正方向窗口坐标系(就是视口坐标系)是可以自定义的坐 标系,其坐标轴和原点都不固定,de绘图始终是在窗口坐标系中进行在MM TEXT映射模式下,窗口坐标系的x轴向右,y轴向下和设备环境的坐标系 方向相同,在没有移动窗口坐标系的原点时,窗口坐标系的原点也在设备点(0,0) 处在窗口坐标系的第一象限绘图,图像会显示在设备环境中这开始给我一种 错觉:视口就是设备环境的显示区域需要明确在MM_TEXT的映射模式 下,视口坐标系(画笔)的x轴与设备环境坐标系(显示屏)的x轴平行都 是水平向右为正,视口坐标系(画笔)的y轴与设备环境坐标系(显示屏) 的y轴平行都是垂直向下为正此时将de从世界坐标系的原点(0,0)移 动到(X,丫)后,dc绘制的图形会直接显示的设备环境(显示屏)上在 MM_LOMETRIC、MM_HIMETRIC、MM_LOENGLISH、MM_HIENGLISH、MM_TWIPS 的映射模式 下,窗口坐标系的x轴向右,y轴向上。
所以在窗口的第一象限绘图一般图像不会显示在设备环境上(如窗 口的客户区),因为此时视口(窗口)的第一象限与设备环境的第一象限的交集为空映射模式逻辑单位增加值x值y值MM_TEXT像素右下MM_LOMETRIC0.01 cm右上1MM_HIMETRIC0.001 cm右上」MM_LOENGLISH0.01 in.右上MM_HIENGLISH0.001 in.右上MM_TWIPS1/1440 in.右上MM」SOTROPIC任意(x = y)可选可选MM ANISOTROPIC| 任意(x != y)可选可选如果您将显示器的像素尺寸设定为1024x768,下表就是Windows NT 报告的视口和窗口范围的值映像方式视口范围(x,y)窗口范围(x,y)MM LOMETRIC(1024,-768)(3,200, 2,400)MM HIMETRIC(1024,-768)(32,000, 24,000)MM LOENGLISH(1024, -768)(1,260, 945)MM HIENG LISH(1024, -768)(12,598, 9,449)映像方式逻辑单位英寸毫米MM LOENGLISH0.01 in.0.010.254MM LOMETRIC0.1 mm.0.003940.1MM HIENGLISH0.001 in.0.0010.0254MM TWIPS1/1400 in.0.0006940.0176MM HIMETRIC0.01 mm.0.0003940.01MM_TWIPS (1024,-768) (18,142, 13,606)MM TWIPS(1024, -768)(18,142, 13,606)/* 插入 GetDeviceCaps 的使用说明 Begin 〃所有像素数int pagecx=dc.GetDeviceCaps(HORZRES); int pagecy=dc.GetDeviceCaps(VERTRES);〃即每英寸点数short cxInch = dc.GetDeviceCaps(LOGPIXELSX);short cyInch = dc.GetDeviceCaps(LOGPIXELSY);//计算一个设备单位等于多少0.1mmdouble scaleX = 254.0 / (double)GetDeviceCaps(dc.m_hAttribDC, LOGPIXELSX); double scaleY = 254.0 / (double)GetDeviceCaps(dc.m_hAttribDC, LOGPIXELSY);说明:主要用到的参数见例子中的:HORZRES,VERTRES ,L OGPIXELSX, LOGPIXELSY.总的来说是为了方便控 制打印或重画时的控制,如为了定制打印时,一般依据的是物理的长度,而不是像素,而DC 一般是用像素的映 射模式,所以需要一下转换,上面这个函数就为这种转换设计的.以上三者的关系通常满足:HORZSIZE = 25.4 * HORZRES/LOGPIXELSXHORZSIZE为屏幕水平尺寸(定为度量尺寸,以mm计),HORZRES为水平的像素总数(定为像素 大小,平时所说的屏幕分辨率,但在这不这么称呼。
这里,分辨率定为“每英寸的像素数”),LOGPIXELSX 为逻辑像素(假设的每英寸的像素数,并不是刚才所说的实际的“分辨率”)因此HORZSIZE也称为逻辑 宽度当我们选择“显示”属性里的大字体时,LOGPIXELSX(通常分为96dpi与120dpi)变大了,这样假设原 来的字体为10磅,则原来的字体横向所占像素(实际所占的像素数)为10* (1/72) *LOGPIXELSX,现 在LOGPIXELSX变大了,则字体所占像素也大了,因此看起来字体大了如果HORZRES不变的话,则 HORZSIZE应该变小然后这是和Windows有关的,在16位OS中,HORZSIZE值是固定的在XP系统上验证了一下,发现HORZSIZE值与LOGPIXELSX的值也是不变的,如果改变HORZRES 的话,则HORZSIZE会发生相应变化,但LOGPIXELSX不变,一直是96/* 插入 GetDeviceCaps的使用说明 End 这些窗口范围表示包含显示器全部宽度和高度的逻辑单位元数值320毫米宽的屏幕MM_HIMETRIC下屏 幕宽度的逻辑单位为0.01mm,共32000个间隔,故1024像素实际中对应32000*0.01=320mm)也为1260 MM_LOENGLISH单位或12.6英寸(320除以25.4毫米/英寸)。
首先要明确图形只能在设备环境的坐标系中显示其次要注意视口范围中,视口坐标系的y轴前面的负号 表示改变了画笔dc移动时y轴的方向对于这五种映像方式,视口范围相当于显示屏沿着x轴向屏幕上 方折叠后位于实际显示屏上方的矩形区域,想象一下当前显示屏上面放置了一个同样的大小的虚拟显示屏, de的y值随de的上升而增加,de向上移动然后然后绘制图形将显示在虚拟屏幕中,这个事实有一个有趣 的结果此时要想在设备环境的显示区域显示任何东西,必须使用负的y值才能将画笔移动到真实的显示 屏上曲例如下面的程序代码:void CDemoView::OnPaint(){CPaintDC de(this); // device context for paintingdc.SetMapMode(MM_LOMETRIC);〃dc.TextOut(400,400,"Hello"); 〃看不到屏幕上的Hello,此时dc画到显示屏上方的虚拟显示屏上了 dc.TextOut(400,-400,"Hello"); 〃可以看出屏幕上的 Hello}为了使自己保持头脑清醒,您可能想避免这样做1) 一种解决办法是将逻辑的(0,0)点设。