在学习了Win32创建窗口的基本流程和消息机制后(见上节),我们可以尝试制作一个简易的打字程序。
资源文件是以.rc为扩展名的脚本文件,由资源编译器编译成为以.rec为扩展名的二进制文件,在链接时链入到可执行文件中去。所以想要使用资源首先得新建一个资源脚本文件。所有的资源都关联了一个字符串或数字,如果要引用某个资源,在程序中包含resource.h头文件使用对应的宏名就行了。
当用户单击菜单的某个选项时,Windows会向程序发送WM_COMMAND消息,其中参数wParam的低字节包含了用户单击菜单的ID号。
在窗口函数中需要添加对应的处理。例如:
case WM_COMMAND:
{
switch(LOWORD(wParam))//其中LOWORD是获取低16位数据
{
case ID_FILE_EXIT:
::SendMessage(hwnd,WM_CLOSE,0,0);
break;
}
return 0;
}
当用户按下或者松开一个键时,Windows都会向程序发送消息。wParam保存了敲击键的虚拟键码,lParam则包含了一些其他信息。
例如:用户敲击一个A键会顺序受到以下3个消息:
WM_KEYDOWN: lParam含义为虚拟键码0X41
WM_CHAR: lParam含义为ANSI码0X61
WM_KEYUP: lParam含义为虚拟键码0X41
可以想到,在输入字符后需要重画客户区,这就要依靠InvalidateRect函数了,它使一块客户区无效从而令系统发送WM_PAINT消息到消息队列。
同理,当鼠标移动到客户机的某个位置时Windows会发送WM_MOUSEMOVE消息,按下左键、中建、右键和弹起它们时也会。发送这些消息时,lParam参数包含了鼠标的位置。
可以这样读出坐标信息:
xPos=LOWORD(lParam);
yPos=HIWORD(wParam);
这些坐标是以客户区的左上角为原点,向右是x轴正方向,向下是y轴正方向。
wParam参数包含了鼠标按钮的状态,都以MK为前缀。
在程序中可以加入以下代码:
case WM_LBUTTONDOWN://当用户单击左键时
{
char szPoint[56];
//保存坐标信息
wsprintf(szPoint," X=%d,Y=%d ",LOWORD(lParam),HIWORD(lParam));
str=str+szPoint;
if(wParam&MK_SHIFT)//同时按下了左键和shift
{
str=str+"Shift Key is down";
}
::InvalidateRect(hwnd,NULL,1);
return 0;
}
设置窗口客户区的背景色的方法:给WNDCLASSEX结构的hbrBackground成员安排一个画刷对象句柄。例如以下代码是将背景色设置为灰色:
wndclass.hbrBackground=(HBRUSH)(COLOR_3DFACE+1)
同时,在TextOut函数输出文本时文本的颜色和背景也要设置的相同。
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc=::BeginPaint(hwnd,&ps);
::SetTextColor(hdc,RGB(255,0,0));
::SetBkColor(hdc,::GetSysColor(COLOR_3DFACE));
::TextOut(hdc,0,0,str.c_str(),str.length());
::EndPaint(hwnd,&ps);
return 0;
}
// win32appdemo.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include"resource.h"
#include
LRESULT CALLBACK MainWndProc(HWND,UINT,WPARAM,LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
char szClassName[]="MainWClass";
WNDCLASSEX wndclass;
wndclass.cbSize=sizeof(wndclass);
wndclass.style=CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc=MainWndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=::LoadIcon(hInstance,(LPSTR)IDI_TYPER);//使用图标IDI_TYPER
wndclass.hCursor=::LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)(COLOR_3DFACE+1);//自定义背景颜色
wndclass.lpszMenuName=(LPSTR)IDR_TYPER;//使用菜单
wndclass.lpszClassName=szClassName;
wndclass.hIconSm=NULL;
::RegisterClassEx(&wndclass);
HWND hwnd=::CreateWindowEx(
0,
szClassName,
"My first Window!",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
if(hwnd==NULL)
{
::MessageBox(NULL,"Create Window Wrong!","error",MB_OK);
return -1;
}
::ShowWindow(hwnd,nCmdShow);
::UpdateWindow(hwnd);
MSG msg;
while(::GetMessage(&msg,NULL,0,0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
static std::string str;
switch(message)
{
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc=::BeginPaint(hwnd,&ps);
::SetTextColor(hdc,RGB(255,0,0));
::SetBkColor(hdc,::GetSysColor(COLOR_3DFACE));
::TextOut(hdc,0,0,str.c_str(),str.length());
::EndPaint(hwnd,&ps);
return 0;
}
case WM_DESTROY:
{
::PostQuitMessage(0);
return 0;
}
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case ID_FILE_EXIT:
::SendMessage(hwnd,WM_CLOSE,0,0);
break;
}
return 0;
}
case WM_CREATE:
{
::SetWindowText(hwnd,"Typing application.");
return 0;
}
case WM_CHAR:
{
str=str+char(wParam);
::InvalidateRect(hwnd,NULL,0);
return 0;
}
case WM_LBUTTONDOWN:
{
char szPoint[56];
//保存坐标信息
wsprintf(szPoint," X=%d,Y=%d ",LOWORD(lParam),HIWORD(lParam));
str=str+szPoint;
if(wParam&MK_SHIFT)
{
str=str+"Shift Key is down";
}
::InvalidateRect(hwnd,NULL,1);
return 0;
}
}
return ::DefWindowProc(hwnd,message,wParam,lParam);
}