Windows 窗口 在窗口上,弹出一个对话框,覆盖了窗口的一部分。点击确定,对话框消失,显示完整的 窗口。这时,系统就不需要重新绘制整个窗口,只要重新绘制被对话框覆盖的窗口的一部分就可 以了。 如果,你要改变窗口的状态(如大小、位置等) ,就会产生 WM_PANIT 消息,于是就会又弹 出另外一个对话框(见图 1-23) 。 图 1-23 多对话框 Windows 窗口 当然,你关闭这些对话框时,如果改变了窗口的状态,又会产生新的对话框。不过,你可 以关闭整个窗口,这样所有的对话框都会消失。注意,别试图弹出太多的对话框,虽然很有意思, 但是如果弹出上百个对话框的话很可能会因为系统资源枯竭而死机,一些病毒正是这么干的。 3)文本输出 确切的说,文本输出不该归到 GDI 编程中,所以,这里不作详细的介绍,就以一个例子来 讲解。新建一个 TXT 文本文件(命名为 Temp.TXT) ,至于里面要写些什么,那随个人喜好,这里 就写 HELLO WORLD。新建一个空的工程(或者直接在原来的 Win Hello World 上修改) ,加入一 个 C++的源文件, 将原来的 Win Hello World 中的代码拷贝过来。 如果愿意, 可以改改 WinMain 函数的一些参数,这里就不作修改了。然后,将 WndProc 函数修改成如下代码: ………………………………………………………. LRESULT CALLBACK WndProc (HWND hwnd ,UINT message , WPARAM wParam , LPARAM lParam ) { HDC hdc ; PAINTSTRUCT ps ; TCHAR szTemp[256] ; FILE *fp ; static HFONT { //字符缓冲区 //文件指针 tempfont ;//自定义字体存储变量 static LOGFONT lgfont ; //自定义字体 switch(message) Windows 下的 C/C++编程 case WM_CREATE : //自定义字体 lgfont.lfHeight = 20 ; lgfont.lfWidth = 20 ; lgfont.lfEscapement = 900 ; lgfont.lfOrientation = 600 ; lgfont.lfWeight = FW_ULTRABOLD lgfont.lfItalic = 1 ; lgfont.lfUnderline = 1 ; tempfont = CreateFontIndirect(&lgfont) ; return 0 ; case WM_PAINT : hdc=BeginPaint(hwnd,&ps) ; //打开文件 if((fp = fopen("Temp.txt","r")) != NULL) { int I ; int j=0 ; char ch ; //读取字符 while((ch = fgetc(fp)) != '\n' && ch != EOF) if(ch == '\t') for(i=0 else szTemp[j++]=ch ; //基本文本输出 TextOut(hdc,0,0 ,szTemp,j) ; //更改为 OEM_FIXED_FONT 字体显示 SelectObject(hdc,GetStockObject(OEM_FIXED_FONT)) ; TextOut(hdc,0,20,szTemp,j) ; //更改为 ANSI_VAR_FONT 字体显示 SelectObject(hdc,GetStockObject(ANSI_VAR_FONT)) ; TextOut(hdc,0,40,szTemp,j) ; //还原系统字体 SelectObject(hdc,GetStockObject(SYSTEM_FONT)) ; TextOut(hdc,0,60,szTemp,j) ; //更改字体颜色 ; i<4 ; i++) szTemp[j++] = ' ' ; //循环变量 //字符控制变量 //字符临时存放 ; Windows 下的 C/C++编程 SetTextColor(hdc,RGB(255,0,0)) ; TextOut(hdc,0,80,szTemp,j) ; //还原系统字体颜色 SetTextColor(hdc,RGB(0,0,0)) ; //更改文本背景色 SetBkColor(hdc,RGB(255,255,0)) ; TextOut(hdc,0,100,szTemp,j) ; //还原系统文本背景 SetBkColor(hdc,RGB(255,255,255)) ; //自定义字体显示 SelectObject(hdc,tempfont) ; TextOut(hdc,200,350,szTemp,j) ; //还原系统字体 SelectObject(hdc,GetStockObject(SYSTEM_FONT)) ; TextOut(hdc,0,120,szTemp,j) ; } EndPaint(hwnd,&ps) ; return 0 ; case WM_DESTROY : PostQuitMessage(0) ; return 0 ; } return DefWindowProc(hwnd,message,wParam,lParam) ; } 编译运行,将得到如下结果(见图 1-24) : 图 1-24 文本输出 左边有一列 HELLO WORLD。依次为:正常显示,OEM_FIXED_FONT 字体,ANSI_VAR_FONT 字体, 还原的系统字体,更改颜色,更改文本背景色,最后的还原系统字体。中间的垂直粗体代下划线 Windows 下的 C/C++编程 的 HELLO WORLD 是我们的自定义字体,为倒数第二次显示的。 下面,逐一进行分析。 ◆ 正常显示 这里,通过 TextOut 函数来输出文本。这个函数有 5 个参数。第一个参数是显示设 备句柄,这里是指明在那个窗口显示; 第二个参数是输出的 x 轴坐标,窗口左上为 0; 第三个参数是输出的 y 轴坐标,窗口左上为 0; 第四个参数是存放输出文本的数组; 第五个参数是需要输出的字符数; ◆ 更改字体 可以在程序中更改字体。更改的步骤是:先通过 SelectObject 函数设定字体,而 函数中的 GetStockObject 函数是用于获取字体的句柄 ;然后就可以直接输出,如果不 重新设置字体,以后的字体就是最近一次设置的字体;最后,用完后通过 SelectObject 函数还原系统字体,这是一个好习惯。Windows 提供了一些常用的字体,列举如下(见 表 1-8) 。 字体 SYSTEM_FONT OEM_FIXED_FONT ANSI_VAR_FONT ANSI_FIXED_FONT DEFAULT_GUI_FONT DEVICE_DEFAULT_ FONT 系统字体 MS-DOS 中使用的终端字体 变宽字体,常用 MS Sans Serif 字体 固定字宽字体,常用 Courier 字体 图形界面字体,常用 MS Sans Serif 字体 设备字体,设备不同,字体不同 表 1-8 常用的字体 ◆ 更改颜色 和更改字体一样,更改颜色要先设定颜色,然后使用,最后还原成原先的颜色。详 细过程参照程序代码就可以了。两个参数相信大家已经看出来了,就不再多说了。 其中,文本的颜色值用 RGB 宏来定义,下面列出基本的 RGB 纯色色彩(见表 1-9) 。 说明 RGB (0,0,0) (255,0,0) (0,255,0) (0,0,255) (255,255,255) 黑色 红色 绿色 蓝色 白色 表 1-9 基本 RGB 纯色 ◆ 更改文本背景色 色彩 这里的文本背景色是指文本字符周围的底色,不是窗口的背景色。其方法和更改颜 Windows 下的 C/C++编程 色一样。 ◆ 自定义字体 如果需要特殊的输出效果,可以通过自定义字体实现。首先,需要一个 LOGFONT 结 构变量来描述字体的特性。然后通过 CreateFontIndirect 函数创建字体,并取得字体 的句柄,存放于一个 HFONT 变量中,使用的时候,就和使用系统字体一样了。 LOGFONT 结构包括 14 个元素,下面按照 LOGFONT 结构定义的顺序列表说明(见表 1-10) : 元素 lfHeight 类型 LONG 说明 设定字符的高度,取绝对值,0 表示使用 默认值 lfWidth lfEscapement LONG LONG 设定字符的平均宽度, 表示让系统设定 0 连续显示时,后一个字符对前一个字符 的逆时针旋转角度。以 0.1 为单位,900 表示 90 度,即自下而上显示,0 表示从 左向右显示 lfOrientation LONG 单个字符水平方向自身的逆时针旋转角 度。以 0.1 为单位,1800 表示倒置,0 表示正常 lfWeight LONG 字体粗细, 0 到 1000 之间, 取 通常为 400, 粗体为 700,0 表示使用默认值 lfItalic lfUnderline BYTE BYTE 斜体标志,非 0 表示斜体,0 表示正常 下划线标志,非 0 表示带下划线,0 表示 正常 lfStrikeOut BYTE 横线标志,非 0 表示有横线穿过,0 表示 正常 lfCharSet BYTE 定义字符集,Windows 常用字符集见表 1-11 lfOutPrecision lfClipPrecision lfQuality BYTE BYTE BYTE 字体输出精度 指定字体剪裁方式 指定字体与实际字体匹配程度。有三种 选 择 : DEFAULF_QUALITY , PROOF_QUALITY,DARFT_QUALITY lfPitchAndFamily BYTE 指定字符间距和字符族。低 2 位表示字 符间距,0 为缺省,1 为等宽,2 为变宽; 高四位指定字符族 lfFaceName[LF_FACESIZE] TCHAR 字体的名字 Windows 下的 C/C++编程 表 1-10LOGFONT 结构 常量 ANSI_CHARSET DEFAULT_CHARSET SYMBOL_CHARSET SHIFJIS_CHARSET OEM_CHARSET lfCharSet 元素常用值(见表 1-11) 表 1-11 lfCharSet 元素常用值 0 1 2 128 256 数值 试一 试试自己用不同的字体写些东西吧。 好了,对文本的输出,就说到这里。这些对游戏编程已经足够了。如果想要进行 Windows 下 的文本编程,可以查阅其他的资料。下面,看看输入设备的情况。 4)键盘和鼠标输入 由于键盘和鼠标的输入在游戏编程中会专门讲解,所以,这里就不详细说明。我们给出一 个例子,创建窗口,当按下键盘时,发出一个声音,按下 ESC 键时,关闭窗口;同样,按下鼠标 左键时发出一个声音,按下鼠标右键时,关闭窗口,同时在窗口左上角显示鼠标的位置坐标。 新建一个空的工程 InputTest(或者直接在原来的 Win Hello World 上修改) ,加入一个 C ++的源文件,将原来的 Win Hello World 中的代码拷贝过来。 在文件开头加入标准输入输出头文件: #include #include LRESULT CALLBACK WndProc (HWND , UINT , WPARAM , LPARAM ) ; …………………………………………………… 然后,将 WndProc 函数修改成如下代码: …………………………………………………….. LRESULT CALLBACK WndProc (HWND hwnd ,UINT message ,WPARAM wParam ,LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; RECT rect ; char temp[128] ; switch(message) {case WM_CREATE: return 0 ; //获取键盘输入 case WM_KEYDOWN: Windows 下的 C/C++编程 switch(wParam) {//按 Esc 键推出 case VK_ESCAPE: PostQuitMessage(0) ; return 0 ; } //其余按键发声 MessageBeep(MB_OK) ; return 0 ; //按下鼠标左键发声 case WM_LBUTTONDOWN : MessageBeep(MB_OK) ; return 0 ; //按下鼠标右键退出 case WM_RBUTTONDOWN: PostQuitMessage(0) ; return 0 ; //鼠标位置改变,显示坐标 case WM_MOUSEMOVE : hdc = GetDC(hwnd) ; sprintf(temp , "x:%d , y:%d" ,LOWORD(lParam) ,HIWORD(lParam)) ; TextOut(hdc ,10,10,temp,strlen(temp)) ; ReleaseDC(hwnd,hdc) ; return 0 ; case WM_PAINT : hdc=BeginPaint(hwnd,&ps) ; GetClientRect(hwnd,&rect) ; EndPaint(hwnd,&ps) ; return 0 ; case WM_DESTROY: PostQuitMessage(0) ; return 0 ; } return DefWindowProc(hwnd,message,wParam,lParam) ; } 编译运行,将得到如下结果(见图 1-25) 。 Windows 下的 C/C++编程 图 1-25 鼠标位置 下面,来分析一下代码。 ◆按键消息 按下或放开键盘上的任何一个或一组键,都会产生一个消息。在这里,以 case WM_KEYDOWN 语句来判断是否有键被按下(释放按键的消息为 WM_KEYUP) 。然后,通过 switch 语句来判断是否按了 Esc 键,如果有,发送退出消息,否则,发出声音。当 然,键盘上的每一个键都有一个标识,就如 Esc 键为 VK_ESCAPE 一样,这里就不详细 给出了,如果有兴趣可以查阅其他资料。