表3-5-1 SetMapMode 函数
用 途 | 设置设备对象的映射方式。 | 原 型 | int SetMapMode( | | HDC hDC, | 设备对象句柄 | int nMapMode | 所欲设置的映射方式,使用表3-4中常量之一 | ) | |
| |
返回值 | 先前的映射方式。 |
表3-5-1 GetMapMode 函数
用 途 | 检索当前的映射方式。 | 原 型 | int GetMapMode( | | HDC hDC, | 设备对象句柄 | ) | |
| |
返回值 | 当前的映射方式。 |
Windows函数中指定的所有坐标值必须在-32768到32767之间的值(这是C语言的int类型的数据的值域)。 在任何映射方式下,逻辑坐标和物理坐标的缺省原点都为(0, 0),即逻辑坐标的点(0, 0)映射到设备坐标的点(0, 0)。
3.4.3 改变视区和窗口的原点 表3-6说明的函数可用于改变视区和窗口的原点,但这两个函数不能同时使用。
表3-6-1 SetViewportOrg 函数
用 途 | 设置视区的坐标原点。 | 原 型 | DWORD SetViewportOrg( | | HDC hDC, | 设备对象句柄 | int x, | 指定视区坐标原点的x坐标值(设备单位)。 | int y, | 指定视区坐标原点的y坐标值(设备单位)。 | ) | |
| |
返回值 | 返回以前视区坐标原点(设备单位),高位字为y坐标,低位字为x坐标。 |
表3-6-2 SetWindowOrg 函数
用 途 | 设置窗口坐标的原点。 | 原 型 | DWORD SetWindowOrg( | | HDC hDC, | 设备对象句柄 | int x, | 指定窗口坐标原点的x坐标值(逻辑单位)。 | int y, | 指定窗口坐标原点的y坐标值(逻辑单位)。 | ) | |
| |
返回值 | 返回以前视区坐标原点(设备单位),高位字为y坐标,低位字为x坐标。 |
无论怎样改变窗口和视区的原点,Windows都将窗口原点变换到视区原点,并按同样的映射算法(即使用当前给出的映射公式)变换其余的点。 我们先介绍MM_TEXT映射方式下这两个函数的工作原理。因为这种映射方式的x坐标和y坐标方向与我们阅读文本时的方向一致。因此,MM_TEXT映射方式又称为“文本”映射方式。
| 图3-4 |
现假定用户区的宽度为xClient个象素,高为yClient给象素,则语句:
SetViewportOrg(hDC, xClient/2, yClient/2);
将逻辑点(0, 0)确定在(映射到)用户区的中心。
| 图3-5 |
这时,若使用语句:
TextOut(hDC, 0, 0, "Hello", 5);
将在用户区中心位置开始显示信息。而语句:
TextOut(hDC, -xClient/2, -yClinent/2, "Hello", 5);
在用户区的左上角(设备点(0, 0))处开始显示文本。 通过使用函数SetWindowOrg可以得到与使用函数SetViewpostOrg相同的结果,例如:
SetWindowOrg(hDC, -xClient/2, -yClient/2);
这使得逻辑点(-xClient/2, -yClient/2)被映射为设备点(0, 0)。 函数GetViewportOrg和GetWindowOrg可分为别用于获取当前视区和窗口的原点,见表3-7。
表3-7-1 GetViewportOrg 函数
用 途 | 获取当前的视区原点。 | 原 型 | DWORD GetViewportOrg( | | HDC hDC, | 设备对象句柄 | ) | |
| |
返回值 | 视区的原点(设备坐标),y坐标在高位字中,x坐标在低位字中。 |
表3-7-2 GetWindowOrg 函数
用 途 | 获取当前的视区原点。 | 原 型 | DWORD GetWindowOrg( | | HDC hDC, | 设备对象句柄 | ) | |
| |
返回值 | 窗口的原点,y坐标在高位字中,x坐标在低位字中。 |
Windows的映射方式中,MM_LOMETRIC、MM_HIMETRIC、MM_LOENGLISH、MM_HIENGLISH和MM_TWIPS是以物理度量单位表示逻辑坐标的映射方式。这五种映射方式被称为公制映射方式,因为它们在X轴和Y轴上的逻辑坐标被映射为等量的物理单位,所以这些映射方式便于绘制圆或正方形。 当初次设置这些映射方式之一时,坐标系为:
| 图3-6 |
因此,在用户区中显示信息必须使用负的Y坐标值。例如:
SetMapMode(hDC, MM_LOENGLISH); TexOut(hDC, 100, -100, "Hello", 5);
将在用户区向右偏移1英寸,向下偏移1英寸的位置显示“Hello”。 下面的语句将逻辑点(0, 0)设置在用户区的左下角:
SetViewportOrg(hDC, 0, yClient);
| 图3-7 |
而下面的语句将逻辑点(0, 0)设置在用户区的中心点。
SetViewportOrg(hDC, xClient/2, yClient/2);
| 图3-8 |
在Windows提供的八种映射方式中,唯有MM_ISOTROPIC和MM_ANISOTROIC允许用户改变窗口和视口的范围(其他六种的范围是固定的,用户不能改变)。表3-7列出了与窗口范围和视区范围有关的函数。
表3-7-3 SetWindowExt 函数
用 途 | 设置窗口的x和y坐标范围。 | 原 型 | DWORD SetWindowExt( | | HDC hDC, | 设备对象句柄 | int x, | 窗口的x坐标范围(逻辑单位) | int y | 窗口的y坐标范围(逻辑单位) | ) | |
| |
返回值 | 以前的坐标范围(逻辑单位),y坐标范围在高位字中,x坐标范围在低位字中。 |
表3-7-4 GetWindowExt 函数
用 途 | 检索窗口的x和y坐标范围。 | 原 型 | DWORD GetWindowExt( | | HDC hDC, | 设备对象句柄 | ) | |
| |
返回值 | y范围在高位字中,x范围在低位字中。 |
表3-7-5 SetViewportExt 函数
用 途 | 设置视区的x和y范围。 | 原 型 | DWORD SetViewportExt( | | HDC hDC, | 设备对象句柄 | int x, | 视区的x坐标范围(设备单位) | int y | 视区的y坐标范围(设备单位) | ) | |
| |
返回值 | 以前的视区的坐标范围(设备单位),y在高位字中,x在低位字中。 |
表3-7-6 GetViewportExt 函数
用 途 | 设置视区的x和y范围。 | 原 型 | DWORD GetViewportExt( | | HDC hDC, | 设备对象句柄 | ) | |
| |
返回值 | 视区的X和Y坐标范围(设备单位),y在高位字中,x在低位字中。 |
窗口和视区的范围不具有任何裁剪区的意义,它们用于确定将逻辑坐标系中的单位放大或缩小多少以适合设备坐标系中的单位。例如,如果窗口的X坐标范围是2,而视区的X坐标范围是4,则GDI将两个逻辑单位(按X轴计算)映射为一个设备单位。 坐标范围也同样决定了两个坐标系(窗口和视区)的X轴和Y轴的相对定向关系。如果相关联的窗口和视区范围符号一致,则坐标轴方向相同,否则方向相反。例如,如果窗口和视区的X坐标范围分别是2和4,则GDI将逻辑坐标系的X轴的正半轴映射到该设备坐标系统的X轴正半轴;如果窗口和视区的Y坐标范围分别为2和-1,则GDI将逻辑坐标系统的Y轴的正半轴映射到设备坐标系的Y轴的负半轴。 对于MM_ISOTROPIC映射方式,词“isotropic”表示在所有的方向都“相等”,即该方式的用途是在两个轴上保持相等的逻辑单位。我们举一例子来说明该方式的设置方法。 我们设置这样一个坐标系,(0, 0)点位于用户区域的左下角,宽度范围从0到32767,高度范围也从0到32767:
| 图3-9 |
并使用下列程序段设置映射方式和范围:
SetMapMode(hDC, MM_ISOTROPIC); SetWindowExt(hDC, 32767, 32767); SetViewportExt(hDC, xClient, yClient); // xClient和yClient是用户区的宽度和高度 SetViewportOrg(hDC, 0, yClient);
这时,Windows将调整范围,使两个轴上的逻辑单位表示相同的物理距离。如果用户区的宽度比高要长,则Windows调整x范围。这时坐标位置如下图:
| 图3-10 |
逻辑窗口将位于用户区左侧,并且由于Windows的坐标值不能大于32767,就无法在用户区的右侧部分显示任何图形。如果用户的高度比宽度要长,则Windows调整y的范围,这时候坐标位置如下图:
| 图3-11 |
同样的原因,在用户的顶部也无法显示任何图形,因为这时需要大于32767逻辑单位的y坐标。 由此可见,对于MM_ISOTROPIC映射方式,程序员可以调用函数SetViewportExt设置范围,Windows通过调整范围,使得两个轴上每一个逻辑单位表示相同的物理距离,这对于绘制圆和正方形等是方便的。 对函数SetViewportExt的调用必须在对函数SetViewportExt的调用之前进行,这可以最有效地使用用户区中的空间。若不是这样的话,当Windows调整范围时,为了使逻辑窗口置于物理视区内,可能导致用户区域的某一部分在逻辑窗口的外面。 窗口和视区的范围不表示裁剪区,我们分析下面的程序片断所建立的坐标系:
SetMapMode(hDC, MM_ISOTROPIC); SetWindowExt(hDC, 1000, 1000); SetViewportExt(hDC, xClient/2, -yClient/2); SetViewportExt(hDC, xClient/2, yClient/2);
我们分析用户区宽度大于高度的情况:
| 图3-12 |
对于上图所示的情况,若点的X坐标小于-1000或大于+1000,则这个点可能落在用户区内,也可能落在用户区之外;但对于Y坐标小于-1000或大于+1000的点,这个点一定落在用户区之外。 最后,我们介绍MM_ANISOTROPIC映射方式,单词“anisotropic”的含义是“在所有的方向上不相等”。对于MM_ANISOTROPIC,Windows对所设置的范围不进行调整,这表明,对于MM_ANISOTROPIC,两个坐标轴上的逻辑单位具有不同的物理尺寸。例如,对于上面的例子,如果设置为MM_ANISOTROPIC映射方式。
SetMapMode(hDC, MM_ANISOTROPIC); SetWindowExt(hDC, 1000, 1000); SetViewportExt(hDC, xClient/2, -yClient/2); SetViewportExt(hDC, xClient/2, yClient/2);
则所建立的坐标系如下图所示:
| 图3-13 |
下面的程序实例是使用MM_ANISOTROPIC映射方式重新设计的2.5节的程序。
// 3-1.c #include <stdio.h> #include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int PASCAL WinMain( HINSTANCE hInstance, // 应用程序的实例句柄 HINSTANCE hPrevInstance, // 该应用程序前一个实例的句柄 LPSTR lpszCmdLine, // 命令行参数串 int nCmdShow ) // 程序在初始化时如何显示窗口 { char szAppName[] = "DispText"; HWND hwnd; MSG msg; WNDCLASS wndclass;
if (!hPrevInstance) { // 该实例是程序的第一个实例,注册窗口类 wndclass.style = CS_VREDRAW | CS_HREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass)) // 如果注册失败 return FALSE; }
// 对每个实例,创建一个窗口对象 hwnd = CreateWindow( szAppName, "Display Text", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd);
while( GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
return msg.wParam; }
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static int xChar, yChar; int line; char szBuffer[256]; HDC hDC; char ch; PAINTSTRUCT ps; TEXTMETRIC tm; FILE *fp;
switch(message) { case WM_CREATE: hDC = GetDC(hwnd); GetTextMetrics(hDC, &tm); xChar = tm.tmAveCharWidth; yChar = tm.tmHeight + tm.tmExternalLeading; ReleaseDC(hwnd, hDC); return 0L;
case WM_PAINT: hDC = BeginPaint(hwnd, &ps); SetMapMode(hdc, MM_ANISOTROPIC); SetWindowExt(hdc, 1, 1); SetViewportExt(hdc, xChar, yChar); line = 0; if((fp = fopen("disptext.cpp", "r")) != NULL) { while(!feof(fp)) { int i = 0; while((ch = fgetc(fp)) != '/n' && ch != EOF) szBuffer[i++] = (char)ch; TextOut(hDC, xChar, line*yChar, szBuffer, i); line++; } fclose(fp); } EndPaint(hwnd, &ps); return 0L;
case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
 
2/2 首页 上一页 1 2 |