程序的入口为WinMain函数,其主要功能是注册窗口类、创建窗口、消息循环。要把握窗口程序的流程,重点应该放在窗口函数(消息处理)上,同时,对窗口的绘制也是需要掌握的重点。
常用窗口消息如下:
| 消息名称 | 值 | 说 明 |
| WM_NULL | 0x0000 | 空消息,此消息将被接收窗口忽略 |
| WM_CREATE | 0x0001 | 应用程序创建一个窗口 |
| WM_DESTROY | 0x0002 | 一个窗口被销毁 |
| WM_MOVE | 0x0003 | 移动一个窗口 |
| WM_SIZE | 0x0005 | 改变一个窗口的大小 |
| WM_ACTIVATE | 0x0006 | 一个窗口被激活或失去激活状态 |
| WM_SETFOCUS | 0x0007 | 获得焦点后 |
| WM_KILLFOCUS | 0x0008 | 失去焦点 |
| WM_ENABLE | 0x000A | 应用程序Enable状态改变时产生 |
| WM_PAINT | 0x000F | 要求一个窗口重绘自己 |
| WM_CLOSE | 0x0010 | 当一个窗口或应用程序要关闭时发送一个信号 |
| WM_QUIT | 0x0012 | 用来结束程序运行或应用程序调用Postquitmessage()函数来产生此消息 |
| WM_SHOWWINDOW | 0x0018 | 当隐藏或显示窗口是发送此消息给这个窗口 |
| WM_DRAWITEM | 0x002B | 当Button,ComboBox,Listbox,Menu控件的外观改变时,发送此消息给这些控件的所有者 |
| WM_WINDOWPOSCHANGING | 0x0046 | 当调用SetWindowPos()函数改变窗口的大小和位置后,发送此消息给该窗口 |
| WM_NOTIFY | 0x004E | 当某个控件的某个事件已经发生或这个控件需要得到一些信息时,发送此消息给它的父窗口 |
| WM_HELP | 0x0053 | 当用户按下了F1,如果某个菜单是激活的,就发送此消息给此窗口关联的菜单,否则就发送给有焦点的窗口,如果当前都没有焦点,就把此消息发送给当前激活的窗口 |
| WM_CONTEXTMENU | 0x007B | 当用户在某个窗口中点击右键,则发送此消息给该窗口 |
| WM_KEYDOWN | 0x0100 | 按下一个非系统键(按下键时未按下“ALT”键) |
| WM_KEYUP | 0x0101 | 释放一个非系统键 |
| WM_CHAR | 0x0102 | 按下某键,当TranslateMessage()转发WM_KEYDOWN后发送本消息 |
| WM_COMMAND | 0x0111 | 选择窗口菜单项或某个控件发送一条消息给它的父窗口或按下一个快捷键时产生此消息 |
| WM_TIMER | 0x0113 | 发生了定时器事件 |
| WM_MOUSEMOVE | 0x0200 | 鼠标移动 |
| WM_LBUTTONDOWN | 0x0201 | 按下鼠标左键 |
| WM_LBUTTONUP | 0x0202 | 释放鼠标左键 |
| WM_LBUTTONDBLCLK | 0x0203 | 双击鼠标左键 |
| WM_RBUTTONDOWN | 0x0204 | 按下鼠标右键 |
| WM_RBUTTONUP | 0x0205 | 释放鼠标右键 |
| WM_RBUTTONDBLCLK | 0x0206 | 双击鼠标右键 |
| WM_MBUTTONDOWN | 0x0207 | 按下鼠标中键 |
| WM_MBUTTONUP | 0x0208 | 释放鼠标中键 |
| WM_MBUTTONDBLCLK | 0x0209 | 双击鼠标中键 |
| WM_MOUSEWHEEL | 0x020A | 当鼠标滚轮转动时发送此消息给当前获得焦点的窗口 |
| WM_USER | 0x0400 | 帮助用户自定义消息,自定义消息可以为WM_USER+X,X为正整数 |
还有子窗口消息,如对话框中的控件消息。
窗口绘制是通过GID + DC 一起来完成的。
GDI 简单而言就是绘制的工具:画笔、画刷、字体、图片等等
HFONT font = ::CreateFont(20,0,0,0,0,0,0,0,0,0,0,0,0,"楷体");
HPEN pen = ::CreatePen(PS_SOLID,5,RGB(0,0,255));
DC 可以理解为绘制的场景(设备上下文):
1、场景有两种:内存DC 和 显示DC,内存DC是没用直接完成显示的,显示DC则所有动作都会同步显示在窗口里。
2、两种DC可以通过 “拷贝” 来完成场景的复制(内存拷贝到显示,即显示内存DC中的内容)
3、有时候需要通过内存DC来消除窗口绘制过程中的 ”闪烁“ 问题,闪烁是因为多次直接在显示DC中绘制引起的。把所有需要绘制的动作(画线、输出文本、贴图等等)全部 ”暂存“ 在内存DC中完成,最后一次拷贝到显示DC。
4、显示DC 的获取方法有两种:
HDC dc = ::GetDC(hWnd); //从窗口句柄获取
在响应WM_PAINT消息中:
PAINTSTRUCT ps;//开始绘制
HDC hdc = ::BeginPaint(hWnd,&ps);
......
::EndPaint(hWnd,&ps); //结束绘制,并回收资源
5、内存DC与显示DC需要兼容:
HDC hMenDC = ::CreateCompatibleDC(hdc);
6、记得释放DC资源:
显示DC :::ReleaseDC(hdc)
内存DC:::DeleteDC(hMenDC);
在第一个窗口程序上完成自动切换指定的5张图片,再进行简单的文本、画线操作。
分析:初始化GDI工具(字体、画笔、图片)放在WM_CREATE消息响应(创建窗口);
开启定时器,这样每隔一段时间会收到系统的WM_TIMER 消息,响应WM_TIMER 随机选择一张图片,更新窗口即产生WM_PAINT消息
WM_PAINT消息响应中绘制窗口。
修改第一个窗口程序(整理版)Wndproc.h 头文件,添加三个函数
- #ifndef WNDPROC_H
- #define WNDPROC_H
- #include "main.h"
-
- LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
- WPARAM wParam, LPARAM lParam);
-
- void Render(HWND hWnd);
- void InitGdiObject(HWND hwnd);
- void DestroyGdiObjcet();
- #endif
Wndproc.cpp进行相应的修改:
- #include "wndproc.h"
- #include "stdlib.h"
- #include "Mmsystem.h"
- #pragma comment(lib,"Winmm.lib")
- #include <stdio.h>
- HBITMAP bitmap[5];
- HFONT font;
- HPEN pen;
- int index = 0;
- LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
- WPARAM wParam, LPARAM lParam)
- {
- switch (message)
- {
- case WM_CREATE:
- InitGdiObject(hWnd);
- break;
- case WM_CLOSE:
- {
- ::DestroyWindow(hWnd);
- }
- break;
- case WM_DESTROY: //如果按下关闭按钮
- {
- PostQuitMessage(0); //发出关闭程序的消息
- DestroyGdiObjcet();
- break;
- }
- case WM_PAINT:
- {
- Render( hWnd);
- break;
- }
- case WM_TIMER:
- {
- RECT rect;
- ::srand(::timeGetTime());
- index=rand()%5;
- ::GetClientRect(hWnd,&rect);
- ::InvalidateRect(hWnd,&rect,TRUE);
- break;
- }
- default: //其他消息发给windows默认窗口处理函数
- return (DefWindowProc(hWnd,message,wParam,lParam));
- }
- return 0;
- }
- void Render(HWND hWnd)
- {
- PAINTSTRUCT ps;
- HDC hdc = ::BeginPaint(hWnd,&ps);
- HDC hMenDC = ::CreateCompatibleDC(hdc);
- ::SelectObject(hMenDC,bitmap[index]);
- ::SetStretchBltMode(hdc,COLORONCOLOR);
- ::StretchBlt(hdc,0,0,ps.rcPaint.right,ps.rcPaint.bottom,hMenDC,0,0,ps.rcPaint.right,ps.rcPaint.bottom,SRCCOPY);
-
- ::SelectObject(hdc,font);
-
- ::SetBkMode(hdc,TRANSPARENT);
- ::SetTextColor(hdc,RGB(255,0,0));
- ::TextOut(hdc,ps.rcPaint.right / 2 - 20,20,"My Second Appliaction",21);
-
- ::SelectObject(hdc,pen);
- ::MoveToEx(hdc,200,50,NULL);
- ::LineTo(hdc,ps.rcPaint.right-200,50);
- ::DeleteDC(hMenDC);
-
- ::EndPaint(hWnd,&ps);
- }
- void InitGdiObject(HWND hwnd)
- {
- char filename[256];
- RECT rect;
- ::GetClientRect(hwnd,&rect);
- for(int i=0;i<5;i++)
- {
- ::sprintf(filename,"%d.bmp",i+1);
- bitmap[i]=(HBITMAP)::LoadImage(NULL,filename,IMAGE_BITMAP,rect.right,rect.bottom,LR_LOADFROMFILE);
- }
- font = ::CreateFont(20,0,0,0,0,0,0,0,0,0,0,0,0,"楷体");
- pen = ::CreatePen(PS_SOLID,5,RGB(0,0,255));
- }
- void DestroyGdiObjcet()
- {
- for(int i=0;i<5;i++)
- ::DeleteObject(bitmap[i]);
- }
其他消息的处理,建议多做测试,尤其是键盘、菜单、鼠标消息的处理。