第一个窗口程序
1. 每个GUI应用程序至少要创建一个窗口,成为主窗口,它作为用户与应用程序间的主界面来提供服务。
2. 程序的入口:
1) 程序实例:
int APIENTRY_tWinMain(HINSTANCE hInstance,//本模块实例句柄
HINSTANCE hPrevInstance,//没用
LPTSTR lpCmdLine,//命令行参数
int nCmdShow)//主窗口显示方式
2) 程序解释:
① GUI应用程序的入口函数WinMain,APIENTRY是_stdcall的宏定义,说明是采用标准的windows调用方式;
② 在win32下,模块的实例句柄和模块句柄是一致的。获得当前模块句柄的方法:
hInstance = (HINSTANCE)GetModuleHandle(NULL); 函数原型:(通过模块名称获得模块句柄)HMODULE WINAPI GetModuleHandle(__in LPCTSTR lpModuleName);
③ lpCmdLine 命令行参数,是CreateProcess的第二个参数指定。
④ nCmdShow主窗口初始化显示方式, 也由CreateProcess的参数决定;
3) MessageBox函数说明:
① 函数原型:
intMessageBox(
HWND hWnd, //窗口句柄,指定哪一个窗口将拥有要创建的消息框
LPCTSTR lpText,//将要显示的消息
LPCTSTR lpCaption,//对话框标题
UINT uType//指定对话框的内容和行为
);
② 第四个参数的取值:
一.为指定消息框中的按钮:MB_OK,MB_OKCANCEL,MB_ABORTRETRYIGNORE,MB_YESNOCANCEL,MB_YESNO,MB_RETRYCANCEL,
二.为在对话框中显示一个图标,MB_ICONHAND,MB_ICONQUESTION,MB_ICONEXCLAMATION,
三.指定默认的选中图标:MB_DEFBUTTON1,2,3,4
③ 函数的返回值:IDYES,IDNO,IDCANCEL,IDABORT,IDRETRY,IDIGNORE,
4) 2
3. Windows消息驱动:
1) 如何能够知道用户在窗口上的动作呢?是OS告诉程序的。Windows不断的向应用程序发送消息。
2) Windows中窗口函数(消息处理函数),是一个自定义的回调函数。 LRESULT CALLBACK WindowProc( HWND hwnd,UINT uMsg,WPARAMwParam,LPARAM lParam);
CALLBACK也是_stdcall,hWnd标识参数到达的窗口;uMsg参数时被命名的常量(消息ID),它指定了所发的消息。
wParam和lParam是消息的两个参数,其值取决于uMsg;
3) 两个函数说明:
HWND hW = ::FindWindow("Notepad",NULL);
//FindWindow通过窗口类名称和窗口类标题名称查找指定的窗口。
::SendMessage(hW,WM_CLOSE,0,0);
//SendMessage 用于向窗口发送消息,直到窗口处理完这个消息才返回。函数的四个参数与WindowPRoc相对应;
4) 每个窗口都关联一个窗口函数,每当这个窗口有输入时,系统调用该函数。窗口函数处理输入然后再将控制权交给OS;
5) 2
创建窗口的过程
主程序的创建流程:
1) 注册窗口类(RegisterClassEx)
2) 创建窗口(CreateWindowEx)
3) 在桌面显示窗口(ShowWIndow)
4) 更新窗口客户区(UpdateWindow)
5) 进入无线的消息获取和消息循环;
1. 注册窗口类:
ATOMMyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXwcex;
= sizeof(WNDCLASSEX);
= CS_HREDRAW | CS_VREDRAW;
//指定窗口类风格,宽度或高度改变,则重画这个窗口
= WndProc;
= 0;
= 0;
= hInstance;
//设定图标和光标,
= LoadIcon(hInstance,MAKEINTRESOURCE(IDI_TYPER));
// =LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32APPLICATION1));
= LoadCursor(NULL, IDC_ARROW);
//指定窗口重画客户区时使用的画刷
= (HBRUSH)(COLOR_WINDOW+1);
// =MAKEINTRESOURCE(IDR_TYPER);//
= MAKEINTRESOURCE(IDC_WIN32APPLICATION1);//
//指定窗口类名
= szWindowClass;
=LoadIcon(, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
结构体说明:
typedef struct {
UINT cbSize;//结构大小
UINT style;//窗口风格
WNDPROC lpfnWndProc;//窗口处理函数名
int cbClsExtra;//窗口类结构后的附加字节数
int cbWndExtra;//窗口事例后的附加字节数
HINSTANCE hInstance;//本模块的实例句柄
HICON hIcon;//左上角图标句柄
HCURSOR hCursor;//光标句柄
HBRUSH hbrBackground;//背景画刷的句柄
LPCTSTR lpszMenuName;//菜单名
LPCTSTR lpszClassName;//该窗口类的类名
HICON hIconSm;//小图标句柄
} WNDCLASSEX, *PWNDCLASSEX;
RegisterClassEx这个函数惟一的参数是这个结构的地址。注册窗口类后将类名和窗口函数,类的风格和其他属性联系起来。
2. 创建窗口:
HWNDCreateWindow(
LPCTSTRlpClassName,//类名
LPCTSTR lpWindowName,//标题
DWORD dwStyle,// 窗口风格
int x,//坐标
int y,
int nWidth,
int nHeight,
HWND hWndParent,// 父窗口句柄
HMENU hMenu,//菜单句柄
HINSTANCE hInstance,//程序实例句柄
LPVOID lpParam
);
hWnd = CreateWindow(szWindowClass,szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
3. 在桌面上显示窗口:
ShowWindow(hWnd,nCmdShow);//第二个参数是系统传递给WinMain函数的参数。
4. 更新窗口客户区: UpdateWindow(hWnd);
5. 进入无限的消息循环:windows为每个线程维护了一个消息队列,windows自动把输入翻译成消息放在消息队列中。
::GetMessage(&msg,NULL,0,0);//从调用线程的消息队列中取出一个消息。阻塞等待;
此函数如果不取得WM_QUIT消息,则返回非零值。
::TranslateMessage(&msg);将键盘翻译为可传递的消息
::DispatchMessage(&msg);//函数分发一个消息到对应窗口的窗口函数;
6. 2
处理消息的代码:
1. 必须把所有不处理的消息交给DefWindowProc函数处理,也要把它的返回值返回给windows,否则windows就失去了与应用程序通信的途径,也就不能控制窗口的行为了。
2. WM_PAINT消息通知应用程序客户区有一块或者全部变成无效,必须刷新。
3. WM_PAINT消息的处理:
hdc = BeginPaint(hWnd, &ps); //使用返回的设备环境句柄不能在客户区之外绘画。
// TODO: 在此添加任意绘图代码...
::TextOut(hdc,0,0,str.c_str(),());//在hdc指定的设备上输出文字;string字符串类型转换为C类型的字符串:.c_str();
EndPaint(hWnd,&ps); //释放环境句柄,使变得不可用。
4. 设置Menu的两种方式:
1) 通过注册窗口类;
2) WM_CREATE响应;
HMENU hMenu =::LoadMenu(::GetModuleHandle(NULL),(LPCTSTR)IDR_TYPER);
::SetMenu(hWnd,hMenu);
::SetWindowText(hWnd,"最简陋的打字程序");//设置标题;
5. 当用户点击菜单中的某一个选项时,Windows即向应用程序发送一个WM_COMMAND的消息,其中参数wParam的低字节包含了用户点击菜单的ID号。
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent= HIWORD(wParam);//取出高字节的信息;
// 分析菜单选择:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
6. SendMessage函数发送的消息并不进入消息队列等待GetMessage函数取出,而是直接交给MainWndProc函数处理,并等待MainWndProc函数返回时再返回。
7. PostMessage函数发送消息后立即返回,不等待消息的运行结果。它是把消息投放到线程所在的消息队列。
8. 用户敲击键盘所发生的消息:
WM_KEYDOWN,WM_CHAR,WM_KEYUP,
case WM_CHAR:
{
str= str + char(wParam);
::InvalidateRect(hWnd,NULL,0);//使客户区无效,触发WM_PAINT消息
return 0;
}
9. 鼠标移动有WM_MOUSEMOVE,消息,还有WM_LBUTTONDOWM,WM_LBUTTONUP,等的消息。发送这些消息时,lParam包含了鼠标的位置坐标。
xPos = LOWORD(lParam);
yPos = HIWORD(lParam);