Win32(视口和窗口、坐标映射、自定义映射)

本文介绍了Win32编程中的视口和窗口概念,以及它们的坐标映射。通过SetMapMode()函数可以改变映射模式,以适应不同场景需求。SetViewportOrgEx()和SetWindowOrgEx()用于定义视口原点,SetWindowExtEx()和SetViewportExtEx()则用于自定义坐标刻度和方向。文章还探讨了MM_ISOTROPIC和MM_ANISOTROPIC两种映射模式的区别,前者确保在坐标变换后形状保持不变,后者不作此保证。

什么是视口和窗口

首先需要明白的什么是视口和窗口,其实很简单,窗口自己有一个坐标体系,我们称为逻辑坐标,我们在编程输入坐标的时候,对应的都是逻辑坐标,而视口对应的是设备坐标,单位是屏幕的像素。
显示器显示内容时会把我们输入的逻辑坐标转换为设备坐标,为什么要这么麻烦呢?答:为了自己定义一个合适的坐标轴,具体往下看。
那就要提到映射模式了,在Win32中我们可以使用SetMapMode()函数来修改二者的映射模式,具体可以看以下链接:
https://fishc.com.cn/forum.php?mod=viewthread&tid=64573&extra=page%3D4%26filter%3Dtypeid%26typeid%3D420

映射模式是用来干嘛的

映射模式是用来干嘛的呢,我们知道,win32中的设备坐标默认情况下,无论那种坐标,原点都是在左上角,x轴向右为正,y轴向下为正,这在很多时候是不方便的,我们需要可以自己定义一个坐标,想想我们在纸上作图的时候,会借助于坐标轴,而为了方便,我们常常会在特定的地方画一个坐标轴,并且,我们可以自己标刻度大小,而在win32里面,整个客户区,可以将其看作一张白纸(客户区坐标称为窗口坐标,这个坐标一直不会改变,且原点一直在左上角),我们想要在这张纸的某一个点绘制一个坐标轴的时候,只需要使用SetViewportOrgEx()函数,指定要显示的视口坐标原点在客户区中的位置即可,需要注意的是视口原点和窗口原点是重合的,所以我们同样可以使用SetWindowOrgEx()函数来修改显示的坐标来达到同样的效果。

以上,我们知道了怎么在客户区的任意位置画一个坐标轴,但是我们只确定了原点的位置,这个坐标轴的横纵坐标的方向以及刻度(每一单位对应多少像素)我们还没有进行设定呢,win32本身以及给了我们一些固定的设定,也就是我们刚提到的映射模式,在映射模式中,我们规定了横纵坐标的方向,(比如MM_LOMETRIC模式,表示了每个逻辑单位映射为 0.1 毫米,x 轴向右,y 轴向上,简单来说,我们编程设计坐标时,设定在10,10位置上显示一个点,根据这个映射模式来说,会在我们设定的原点的右上方横向和纵向距离位0.1*10mm位置处出现一个点),定义好映射模式之后,我们编程输入的坐标就会是我们想要的刻度大小了,这样,我们在这张纸上就完成了一个合理的坐标轴的设定了,接下来设计的时候都会根据我们设定的这个坐标轴显示内容了。

如何自定义映射?

在自定义映射之前首先需要将映射模式修正为MM_ISOTROPIC或者MM_ANISOTROPIC,二者区别是使用MM_ISOTROPIC时每个 x 轴的逻辑单位与 y 轴相等,而MM_ANISOTROPIC时不要求。
我们为了自己定义刻度大小,可以使用 SetWindowExtEx 和SetViewportExtEx两个函数来指定横纵坐标的刻度和方向,注意需要先使用SetWindowExtEx 再使用SetViewportExtEx。
具体使用看以下代码:

//修改原点坐标为中心位置
	SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);

	newPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
	oldPen = (HPEN)SelectObject(hdc, newPen);
//在中心位置画两条辅助线
	MoveToEx(hdc, -cxClient / 2, 0, NULL);
	LineTo(hdc, cxClient / 2, 0);
	MoveToEx(hdc, 0, -cyClient / 2, NULL);
	LineTo(hdc, 0, cyClient / 2);
	SelectObject(hdc, oldPen);

//自定义映射模式
	SetMapMode(hdc, MM_ISOTROPIC);
//当两个函数对应的值相同时,坐标方向仍然为默认的方向,即x向右,y向下
//当一个为正一个为负数,则映射后的坐标方向和之前的相反
//以下代码对应的映射后的坐标应该是x向右,y向上(和之前相反)
//而数值大小对应的刻度,这里意思是我们将逻辑坐标分成100份,并对应整个客户区的大小
	SetWindowExtEx(hdc, 100, 100, NULL);
	SetViewportExtEx(hdc, cxClient, -cyClient, NULL);

MM_ISOTROPIC和MM_ANISOTROPIC区别

具体区别就是,例如以上代码我们映射的是整个客户区,我们在Ellipse(hdc,-40,-40,40,40)定义一个圆当客户区大小改变时,会出现客户区是一个长方形的情况,但我们设置圆形的时候使用的时逻辑坐标呀,按理说,不管你客户区怎么变,我在我设定的逻辑做表里面都应该是一个圆形,显然,在MM_ISOTROPIC映射模式下是这样的,因为win32为了保证这种情况,会以客户区的高度先进行映射,再把纵坐标映射的部分根据我们设定窗口的比例在横坐标上映射,例如上文我们横纵坐标刻度比例是100:100,根据以上规则,横坐标的映射应该就是把cyClient分成100份映射到横坐标,如果是100:200呢,那就是2cyClient分成100份映射过去(注意这是当y方向是短边的时候,如果x方向是短边,就是把cxClient和2cxClient映射到y方向了)。

但是对于MM_ANISOTROPIC来说,他不会这么做,这种模式下,它总会把cyClient的映射到纵坐标上,而把cxClient映射到x轴上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值