1、在前一篇文章中:一个窗口的诞生中详细介绍了面向对象的方式创建Windows应用程序窗口的过程。
2、一个Windows应用程序应该有交互的功能,也就是说,我们得为其添加消息响应,添加对话框,添加控件等详细的功能,这样才能初具规模的形成一个Windows应用程序。
3、windows应用程序是由消息驱动(Message)的,没有了Message,windows便没有了生机和活力。现在为之前的窗口添加消息响应,让其拥有基本的消息响应功能。
windows消息是由系统定义的形如WM_PAINT和WM_CLOSE这样的值,当然用户也可以自定义消息及其响应函数。我们为Windows添加消息便是为相应的消息添加响应函数。在添加消息之前,我们需要对Windows消息有一定的了解。
4、Windows消息介绍:
在Windows中消息有三种类型,分为标准消息,命令消息,通告消息。他们的区别如下:
1)、标准消息:
1、除WM_COMMAND之外,所有以WM_开头的消息,对应得消息宏通常为ON_WM_''''。
2)、命令消息:
1、来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。
3)、通告消息:
1、由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现,对应得宏类如ON_BN_CLICKED,区别于ON_WM类。
不管是哪一类消息,都得有其相应的消息响应函数来处理消息,既然这样我们可以定义一个宏来表明消息映射:
#define MY_MESSAGE_MAP \
tagMessage MessageMap[] = { \
WM_CHAR, CMyWnd::OnChar, \
WM_LBUTTONDOWN, CMyWnd::OnLButtonDown, \
WM_PAINT, CMyWnd::OnPaint, \
WM_DESTROY, CMyWnd::OnDestroy, \
WM_TIMER, CMyWnd::OnTimer, \
WM_CLOSE, CMyWnd::OnClose, \
WM_CREATE, CMyWnd::OnCreate, \
}; \
#define MY_MESSAGE_DECLARE \
static LRESULT OnChar(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnLButtonDown(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnPaint(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnDestroy(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnTimer(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnClose(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnCreate(HWND, UINT, WPARAM, LPARAM); \
stdafx.h头文件
#ifndef _STDAFX_H
#define _STDAFX_H
#define MY_MESSAGE_DECLARE \
static LRESULT OnChar(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnLButtonDown(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnPaint(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnDestroy(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnTimer(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnClose(HWND, UINT, WPARAM, LPARAM); \
static LRESULT OnCreate(HWND, UINT, WPARAM, LPARAM); \
#define MY_MESSAGE_MAP \
tagMessage MessageMap[] = { \
WM_CHAR, CMyWnd::OnChar, \
WM_LBUTTONDOWN, CMyWnd::OnLButtonDown, \
WM_PAINT, CMyWnd::OnPaint, \
WM_DESTROY, CMyWnd::OnDestroy, \
WM_TIMER, CMyWnd::OnTimer, \
WM_CLOSE, CMyWnd::OnClose, \
WM_CREATE, CMyWnd::OnCreate, \
}; \
#define dim(X)(sizeof(X)/sizeof(X[0]))
#endif
CWinApp头文件
#ifndef _CWIN_APP_H
#define _CWIN_APP_H
#include "MainWnd.h"
class CWinApp{
private:
public:
CMyWnd *m_pWnd;
bool InitInstance();
bool Run();
CWinApp();
virtual ~CWinApp();
protected:
};
#endif
MainWind头文件
#ifndef AFX_WIN32LIB_H__510E6511_F3DB_4E80_B512__INCLUDED_
#define AFX_WIN32LIB_H__510E6511_F3DB_4E80_B512__INCLUDED_
#pragma once
#if _MSC_VER >1000
#pragma once
#endif //_MSC_VER>1000
#include <windows.h>
#include "stdafx.h"
typedef LRESULT (*FXN)(HWND, UINT, WPARAM, LPARAM);
struct tagMessage
{
UINT code;
FXN Fxn;
};
class CMyWnd
{
private:
HINSTANCE m_hInstance;
HWND m_hWnd;
protected:
public:
virtual void PreCreateWindow(WNDCLASS &cs);
bool Create();
bool ShowWindow();
bool UpdateWindow();
CMyWnd();
virtual ~CMyWnd();
static LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
//消息响应函数
MY_MESSAGE_DECLARE
};
#endif // !AFX_WIN32LIB_H__510E6511_F3DB_4E80_B512__INCLUDED_
CWinApp实现文件:
#include "CWinApp.h"
CWinApp::CWinApp()
{
m_pWnd = NULL;
if (InitInstance())
Run();
}
CWinApp::~CWinApp()
{
}
bool CWinApp::InitInstance()
{
m_pWnd = new CMyWnd;
m_pWnd->Create();
m_pWnd->UpdateWindow();
m_pWnd->ShowWindow();
return true;
}
bool CWinApp::Run()
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return true;
}
MainWind实现文件
#include "MainWnd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string"
MY_MESSAGE_MAP
CMyWnd::CMyWnd()
{
}
CMyWnd::~CMyWnd()
{
if (NULL != this)
delete this;
}
bool CMyWnd::Create()
{
WNDCLASS cs;
cs.cbClsExtra = 0;
cs.cbWndExtra = 0;
cs.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
cs.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW);
cs.hIcon = (HICON)LoadIcon(NULL, IDI_ERROR);
cs.hInstance = m_hInstance;
cs.lpfnWndProc = WinProc;
cs.lpszClassName = LPCWSTR("Beautiful");
cs.lpszMenuName = NULL;
cs.style = CS_HREDRAW | CS_VREDRAW;
PreCreateWindow(cs);
RegisterClass(&cs);
m_hWnd = ::CreateWindow(cs.lpszClassName,
TEXT("Beautiful"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, m_hInstance, NULL);
if (NULL == m_hWnd)
return false;
else
return true;
}
void CMyWnd::PreCreateWindow(WNDCLASS &cs)
{
cs.hbrBackground = ::CreateSolidBrush(RGB(255, 0, 0));
cs.hIcon = ::LoadIcon(NULL, IDI_INFORMATION);
}
bool CMyWnd::UpdateWindow()
{
if (::UpdateWindow(m_hWnd))
return true;
else
return false;
}
bool CMyWnd::ShowWindow()
{
if (::ShowWindow(m_hWnd, SW_SHOWNORMAL))
return true;
else
return false;
}
LRESULT CALLBACK CMyWnd::WinProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
/*switch (nMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
}*/
for (int i = 0; i < dim(MessageMap); i++)
{
if (nMsg == MessageMap[i].code)
{
FXN iFxn = MessageMap[i].Fxn;
LRESULT lResult = iFxn(hWnd, nMsg, wParam, lParam);
if (lResult == 0)
return 0;
}
}
return DefWindowProc(hWnd, nMsg, wParam, lParam);
}
LRESULT CMyWnd::OnChar(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
char szChar[20];
sprintf_s(szChar, "char is %c", (char)wParam);
MessageBox(hWnd,reinterpret_cast<LPCWSTR>(szChar), TEXT("OnChar"), 0);
return 0;
}
LRESULT CMyWnd::OnClose(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
if (::MessageBox(hWnd, TEXT("真的要关闭窗口吗?"), TEXT("OnClose"), MB_YESNO) == IDYES)
{
::DestroyWindow(hWnd);
}
return 0;
}
//消息响应函数: 鼠标左键按下
LRESULT CMyWnd::OnLButtonDown(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
wchar_t *szTitle =L"一个美好的世界";
hdc = GetDC(hWnd);
TextOut(hdc, 0, 50, TEXT("一个美好的世界"), wcslen(szTitle));
ReleaseDC(hWnd, hdc);
return 0;
}
//消息响应函数:重绘窗口
LRESULT CMyWnd::OnPaint(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
//画一个圆
RECT rc;
GetClientRect(hWnd, &rc);
int iR = min(rc.right - rc.left, rc.bottom - rc.top) / 2;
iR = iR * 4 / 5;
POINT pt;
pt.x = (rc.right + rc.left) / 2;
pt.y = (rc.bottom + rc.top) / 2;
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
::Ellipse(hdc, pt.x - iR, pt.y - iR, pt.x + iR, pt.y + iR);
MoveToEx(hdc, pt.x, pt.y, (LPPOINT)NULL);
LineTo(hdc, pt.x + iR, pt.y);
//显示时间
static wchar_t stime[16] = TEXT("23:59:59");
SYSTEMTIME tm;
::GetLocalTime(&tm);
swprintf_s(stime,16, TEXT("%2d:%2d:%2d"), tm.wHour, tm.wMinute, tm.wSecond);
::TextOut(hdc, 10, 10, reinterpret_cast<LPCWSTR>(stime), wcslen(stime)+1);
EndPaint(hWnd, &ps);
return 0;
}
//消息响应函数: 销毁窗口
LRESULT CMyWnd::OnDestroy(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
PostQuitMessage(0);
return 0;
}
//消息响应函数: 定时器
LRESULT CMyWnd::OnTimer(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
RECT rc;
::GetClientRect(hWnd, &rc);
::InvalidateRect(hWnd, &rc, TRUE);
return 0;
}
//消息响应函数: 创建窗口
LRESULT CMyWnd::OnCreate(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
::SetWindowText(hWnd, TEXT("消息循环"));
::SetTimer(hWnd, 10,1000, NULL);
return 0;
}
Window文件:
#include "CWinApp.h"
CWinApp theApp;
int WINAPI WinMain(_In_ HINSTANCE hInstance, \
_In_opt_ HINSTANCE hPrevInstance, \
_In_ LPSTR lpCmdLine, \
_In_ int nShowCmd)
{
return 0;
}
6、可以看到该程序的结构相对于之前的没有太大的改变,只是添加了一些消息响应函数。在这里需要注意的有以下几点:
1)、要把Declare宏放到类的声明内部:
static LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
//消息响应函数
MY_MESSAGE_DECLARE
};
2)、把消息映射放到类的实现中去:
MY_MESSAGE_MAP
CMyWnd::CMyWnd()
{
}
CMyWnd::~CMyWnd()
{
if (NULL != this)
delete this;
}
这样的话系统才能知道函数和消息之间的关系。
7、程序运行的结果如下所示: