本文用代码的方式详细说明了Windows编程中WM_MOUSEHOVER和WM_MOUSELEAVE消息的用法,以及按钮的变色问题,实现的功能也很多,主要是示例了这两个消息的用法和具体实现按钮的变色。
代码的注释还算详细,就不多做说明了!看代码!
另外做一下功能的说明:
1: 在客户区点鼠标右键,弹出菜单可以关闭窗口!
2: 客户区中的那个巨大的按钮,鼠标移入和移出时可以变色和改变文字,单击鼠标左键可以更改客户区窗口的背景颜色!
3:在最上面的按钮上按住鼠标左键可以移动窗口!(按钮)
建一个空的win32工程,复制下面的代码就可以运行了,vs2012调试通过!!!
编译使用cpp文件,c++方式编译。
//#undef UNICODE // 加上这行代码,可以编译非UNICODE版本
//如果达不到按钮变色的效果,加上下面这行代码
//#define _WIN32_WINNT 0x0400
//如有问题,请批评指正。
//本程序在vs2012调试通过
#include<Windows.h>
#define ID_MINIMIZE 0
#define ID_MAXIMIZE 1
#define ID_CLOSE 2
#define ID_CAPTION 3
#define ID_CLICK 4
int indicator_color = 0;
COLORREF m_color[6] = {RGB(255,0,0),RGB(0,255,0),RGB(0,0,255),
RGB(0,0,0),RGB(100,100,100),RGB(0,125,0)};
HBRUSH m_hBrush[6]; //画刷句柄
HWND btn_hwnd[5]; //按钮句柄
HINSTANCE m_hInstance; //应用程序实例句柄
BOOL click_entry = FALSE; //FALSE 表示鼠标没有移入button上
BOOL min_entry = FALSE;
BOOL max_entry = FALSE;
BOOL close_entry = FALSE;
// 主窗口过程
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
//ID号为ID_CAPTION的button窗口过程
LRESULT CALLBACK btn_CaptionProc(HWND,UINT,WPARAM,LPARAM);
//ID号为ID_MINIMIZE的button窗口过程
LRESULT CALLBACK btn_MinProc(HWND,UINT,WPARAM,LPARAM);
//ID号为ID_MAXIMIZE的button窗口过程
LRESULT CALLBACK btn_MaxProc(HWND,UINT,WPARAM,LPARAM);
//ID号为ID_CLOSE的button窗口过程
LRESULT CALLBACK btn_CloseProc(HWND,UINT,WPARAM,LPARAM);
//ID号为ID_CLICK的button窗口过程
LRESULT CALLBACK btn_ClickProc(HWND,UINT,WPARAM,LPARAM);
//以下变量为更改button的窗口过程之用
WNDPROC old_btn_CaptionProc;
WNDPROC old_btn_MinProc;
WNDPROC old_btn_MaxProc;
WNDPROC old_btn_CloseProc;
WNDPROC old_btn_ClickProc;
//一个内部使用的函数,主要用于在ID为ID_CAPTION的按钮上输出文字
void MySetWindowText(const TCHAR *str)
{
HDC hdc = GetDC(btn_hwnd[ID_CAPTION]);
SetBkColor(hdc,m_color[5]);
SetTextColor(hdc,RGB(255,255,255)); //白色
RECT rect;
GetClientRect(btn_hwnd[ID_CAPTION],&rect);
InvalidateRect(btn_hwnd[ID_CAPTION],NULL,TRUE);
UpdateWindow(btn_hwnd[ID_CAPTION]);
TextOut(hdc,0,rect.bottom / 3 * 2,str,lstrlen(str));
ReleaseDC(btn_hwnd[ID_CAPTION],hdc);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
//初始化画刷
for(int i = 0; i < 6; ++i)
m_hBrush[i] = CreateSolidBrush(m_color[i]);
m_hInstance = hInstance;
WNDCLASS wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = m_hBrush[3]; // 黑色
wndclass.hCursor = LoadCursor(NULL,IDC_CROSS);
wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = TEXT("sunkang");
wndclass.lpszMenuName = NULL;
wndclass.style = CS_HREDRAW | CS_HREDRAW;
RegisterClass(&wndclass);
HWND hwnd = CreateWindow(TEXT("sunkang"),TEXT(""),WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,
hInstance,NULL);
ShowWindow(hwnd,nShowCmd);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//释放资源
for(int i = 0; i < 6; ++i)
DeleteObject(m_hBrush[i]);
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
//static HINSTANCE hInstance;
static int cxClient,cyClient;
static int click_btn_width,click_btn_height;
switch(message)
{
case WM_CREATE:
{
//m_hInstance = (LPCREATESTRUCT(lParam))->hInstance;
btn_hwnd[ID_CAPTION] = CreateWindow(TEXT("button"),TEXT(""),WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
0,0,0,0,hwnd,HMENU(ID_CAPTION),m_hInstance,NULL);
btn_hwnd[ID_CLICK] = CreateWindow(TEXT("button"),TEXT(""),WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
0,0,0,0,hwnd,HMENU(ID_CLICK),m_hInstance,NULL);
old_btn_CaptionProc = (WNDPROC)SetWindowLong(btn_hwnd[ID_CAPTION],
GWL_WNDPROC,(LONG)btn_CaptionProc);
old_btn_ClickProc = (WNDPROC)SetWindowLong(btn_hwnd[ID_CLICK],
GWL_WNDPROC,LONG(btn_ClickProc));
//以下三个按钮的父窗口为btn_hwnd[ID_CAPTION]
btn_hwnd[ID_MINIMIZE] = CreateWindow(TEXT("button"),TEXT(""),WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
0,0,0,0,btn_hwnd[ID_CAPTION],HMENU(ID_MINIMIZE),m_hInstance,NULL);
btn_hwnd[ID_MAXIMIZE] = CreateWindow(TEXT("button"),TEXT(""),WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
0,0,0,0,btn_hwnd[ID_CAPTION],HMENU(ID_MAXIMIZE),m_hInstance,NULL);
btn_hwnd[ID_CLOSE] = CreateWindow(TEXT("button"),TEXT(""),WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
0,0,0,0,btn_hwnd[ID_CAPTION],HMENU(ID_CLOSE),m_hInstance,NULL);
//分别更改button的窗口过程
old_btn_MinProc = (WNDPROC)SetWindowLong(btn_hwnd[ID_MINIMIZE],
GWL_WNDPROC,(LONG)(btn_MinProc));
old_btn_MaxProc = (WNDPROC)SetWindowLong(btn_hwnd[ID_MAXIMIZE],
GWL_WNDPROC,(LONG)(btn_MaxProc));
old_btn_CloseProc = (WNDPROC)SetWindowLong(btn_hwnd[ID_CLOSE],
GWL_WNDPROC,(LONG)(btn_CloseProc));
break;
}
case WM_SIZE:
{
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
// 模拟标题栏的button
MoveWindow(btn_hwnd[ID_CAPTION],0,0,cxClient,cyClient / 5,TRUE);
click_btn_width = cxClient / 2;
click_btn_height = cyClient / 5 * 2;
//客户区中的button
MoveWindow(btn_hwnd[ID_CLICK],cxClient / 4,cyClient / 5 * 2,click_btn_width,click_btn_height,TRUE);
break;
}
case WM_CTLCOLORBTN:
{
if(HWND(lParam) == btn_hwnd[ID_CAPTION])
return (LRESULT)m_hBrush[5];
else
{
HDC hdc = HDC(wParam);
LOGFONT lf;
lf.lfCharSet = ANSI_CHARSET;
lstrcpy(lf.lfFaceName,TEXT("宋体"));
//lf.lfWidth = click_btn_width / 5;
lf.lfHeight = click_btn_height;
lf.lfItalic = FALSE;
lf.lfClipPrecision = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfOutPrecision = 0;
lf.lfPitchAndFamily = 0;
lf.lfQuality = 0;
lf.lfStrikeOut = FALSE;
lf.lfUnderline = FALSE;
lf.lfWeight = 400;
if(click_entry == FALSE)
{
TCHAR name[] = TEXT("HELLO");
lf.lfWidth = click_btn_width / lstrlen(name);
HFONT hFont = CreateFontIndirect(&lf);
HFONT old_font = (HFONT)SelectObject(hdc,hFont);
SetBkColor(hdc,m_color[0]);
SetTextColor(hdc,m_color[2]);
TextOut(hdc,0,0,name,lstrlen(name));
SelectObject(hdc,old_font);
return (LRESULT)m_hBrush[0];
}
else
{
TCHAR name[] = TEXT("WORLD");
lf.lfWidth = click_btn_width / lstrlen(name);
HFONT hFont = CreateFontIndirect(&lf);
HFONT old_font = (HFONT)SelectObject(hdc,hFont);
SetBkColor(hdc,m_color[5]);
SetTextColor(hdc,m_color[1]);
TextOut(hdc,0,0,name,lstrlen(name));
SelectObject(hdc,old_font);
return (LRESULT)m_hBrush[5];
}
}
break;
}
case WM_RBUTTONDOWN:
{
HMENU hMenu = CreatePopupMenu();
AppendMenu(hMenu,MF_STRING,ID_CLOSE,TEXT("退出!"));
POINT pt = {LOWORD(lParam),HIWORD(lParam)};
ClientToScreen(hwnd,&pt);
TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_TOPALIGN,
pt.x,pt.y,0,hwnd,NULL);
DeleteObject(hMenu);
break;
}
case WM_MOUSEMOVE:
{
TCHAR buf[] = TEXT("右键有惊喜!!!");
MySetWindowText(buf);
break;
}
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case ID_CLOSE:
{
SendMessage(hwnd,WM_CLOSE,0,0);
break;
}
case ID_CLICK:
{
indicator_color = ++indicator_color % 5;
SetClassLong(hwnd,GCL_HBRBACKGROUND,(LONG)(m_hBrush[indicator_color]));
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
break;
}
default:
break;
}
break;
}
case WM_NCCALCSIZE:
{ //完全去掉标题栏和边框
break;
}
case WM_SYSKEYDOWN:
{ //屏蔽Alt + F4关闭窗口的功能
if(wParam == VK_F4)
;
else
return DefWindowProc(hwnd,message,wParam,lParam);
break;
}
case WM_CLOSE:
{
if(IDOK == MessageBox(hwnd,TEXT("确定退出吗?"),TEXT("关闭窗口!"),MB_OKCANCEL | MB_ICONQUESTION))
DestroyWindow(hwnd);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}
LRESULT CALLBACK btn_CaptionProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
//static HINSTANCE hInstace =
switch(message)
{
case WM_SIZE:
{
int cxClient = LOWORD(lParam);
int cyClient = HIWORD(lParam);
int btn_width = cxClient / 15;
int btn_height = cyClient / 4;
MoveWindow(btn_hwnd[ID_MINIMIZE],cxClient - btn_width * 3, 0,
btn_width,btn_height,TRUE);
MoveWindow(btn_hwnd[ID_MAXIMIZE],cxClient - btn_width * 2, 0,
btn_width,btn_height,TRUE);
MoveWindow(btn_hwnd[ID_CLOSE],cxClient - btn_width, 0,
btn_width,btn_height,TRUE);
break;
}
case WM_CTLCOLORBTN:
{
HDC hdc = HDC(wParam);
switch(GetDlgCtrlID(HWND(lParam)))
{
case ID_MINIMIZE:
{
if(min_entry == FALSE)
{
SetBkColor(hdc,m_color[5]);
SetTextColor(hdc,m_color[0]);
RECT rect;
GetClientRect(HWND(lParam),&rect);
DrawText(hdc,TEXT("最小化"),lstrlen(TEXT("最小化")),&rect,DT_BOTTOM | DT_CENTER);
return LRESULT(m_hBrush[5]);
}
else
{
SetBkColor(hdc,m_color[0]);
SetTextColor(hdc,m_color[1]);
RECT rect;
GetClientRect(HWND(lParam),&rect);
DrawText(hdc,TEXT("最小化"),lstrlen(TEXT("最小化")),&rect,DT_BOTTOM | DT_CENTER);
return LRESULT(m_hBrush[0]);
}
break;
}
case ID_MAXIMIZE:
{
if(max_entry == FALSE)
{
SetBkColor(hdc,m_color[5]);
SetTextColor(hdc,m_color[1]);
RECT rect;
GetClientRect(HWND(lParam),&rect);
DrawText(hdc,TEXT("最大化"),lstrlen(TEXT("最大化")),&rect,DT_BOTTOM | DT_CENTER);
return LRESULT(m_hBrush[5]);
}
else
{
SetBkColor(hdc,m_color[1]);
SetTextColor(hdc,m_color[0]);
RECT rect;
GetClientRect(HWND(lParam),&rect);
DrawText(hdc,TEXT("最大化"),lstrlen(TEXT("最大化")),&rect,DT_BOTTOM | DT_CENTER);
return LRESULT(m_hBrush[1]);
}
break;
}
case ID_CLOSE:
{
if(close_entry == FALSE)
{
SetBkColor(hdc,m_color[5]);
SetTextColor(hdc,m_color[3]);
RECT rect;
GetClientRect(HWND(lParam),&rect);
DrawText(hdc,TEXT("关闭"),lstrlen(TEXT("关闭")),&rect,DT_BOTTOM | DT_CENTER);
return LRESULT(m_hBrush[5]);
}
else
{
SetBkColor(hdc,m_color[0]);
SetTextColor(hdc,m_color[2]);
RECT rect;
GetClientRect(HWND(lParam),&rect);
DrawText(hdc,TEXT("关闭"),lstrlen(TEXT("关闭")),&rect,DT_BOTTOM | DT_CENTER);
return LRESULT(m_hBrush[0]);
}
break;
}
default:
break;
}
break;
}
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case ID_MINIMIZE:
{
SendMessage(GetParent(hwnd),WM_SYSCOMMAND,SC_MINIMIZE,lParam);
break;
}
case ID_MAXIMIZE:
{
SendMessage(GetParent(hwnd),WM_SYSCOMMAND,SC_MAXIMIZE,lParam);
break;
}
case ID_CLOSE:
{
SendMessage(GetParent(hwnd),WM_CLOSE,0,0);
break;
}
default:
break;
}
break;
}
case WM_LBUTTONDOWN:
{ //模拟标题栏的鼠标左键双击
SendMessage(GetParent(hwnd),WM_NCLBUTTONDOWN,HTCAPTION,lParam);
break;
}
case WM_LBUTTONDBLCLK:
{
SendMessage(GetParent(hwnd),WM_NCLBUTTONDBLCLK,HTCAPTION,lParam);
break;
}
case WM_MOUSEMOVE:
{
TCHAR buf[] = TEXT("温馨提示:双击鼠标左键可以最大化窗口,\
按住鼠标左键可以拖动窗口!");
MySetWindowText(buf);
break;
}
default:
return CallWindowProc(old_btn_CaptionProc,hwnd,message,wParam,lParam);
// 也可以用下面的方式,一样的。
// return old_btn_CaptionProc(hwnd,message,wParam,lParam);
}
return 0;
}
LRESULT CALLBACK btn_ClickProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_MOUSEMOVE:
{
if(click_entry == FALSE)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = 1; //1ms 立即显示
tme.hwndTrack = hwnd;
//激活WM_MOUSEHOVER消息
TrackMouseEvent(&tme);
}
break;
}
case WM_MOUSEHOVER:
{
click_entry = TRUE;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
TCHAR buf[] = TEXT("点击鼠标左键可以更改窗口颜色!");
MySetWindowText(buf);
break;
}
case WM_MOUSELEAVE:
{
click_entry = FALSE;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
break;
}
default:
return CallWindowProc(old_btn_ClickProc,hwnd,message,wParam,lParam);
//return old_btn_ClickProc(hwnd,message,wParam,lParam);
}
return 0;
}
LRESULT CALLBACK btn_MinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_MOUSEMOVE:
{
if(min_entry == FALSE)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = 1; //1ms 立即显示
tme.hwndTrack = hwnd;
//激活WM_MOUSEHOVER消息
TrackMouseEvent(&tme);
}
break;
}
case WM_MOUSEHOVER:
{
min_entry = TRUE;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
TCHAR buf[] = TEXT("最小化窗口!!!");
MySetWindowText(buf);
break;
}
case WM_MOUSELEAVE:
{
min_entry = FALSE;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
break;
}
default:
return CallWindowProc(old_btn_MinProc,hwnd,message,wParam,lParam);
//return old_btn_ClickProc(hwnd,message,wParam,lParam);
}
return 0;
}
LRESULT CALLBACK btn_MaxProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_MOUSEMOVE:
{
if(max_entry == FALSE)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = 1; //1ms 立即显示
tme.hwndTrack = hwnd;
//激活WM_MOUSEHOVER消息
TrackMouseEvent(&tme);
}
break;
}
case WM_MOUSEHOVER:
{
max_entry = TRUE;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
TCHAR buf[] = TEXT("最大化窗口+++");
MySetWindowText(buf);
break;
}
case WM_MOUSELEAVE:
{
max_entry = FALSE;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
break;
}
default:
return CallWindowProc(old_btn_MaxProc,hwnd,message,wParam,lParam);
//return old_btn_ClickProc(hwnd,message,wParam,lParam);
}
return 0;
}
LRESULT CALLBACK btn_CloseProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_MOUSEMOVE:
{
if(close_entry == FALSE)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = 1; //1ms 立即显示
tme.hwndTrack = hwnd;
//激活WM_MOUSEHOVER消息
TrackMouseEvent(&tme);
}
break;
}
case WM_MOUSEHOVER:
{
close_entry = TRUE;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
TCHAR buf[] = TEXT("关闭窗口XXXXXXX");
MySetWindowText(buf);
break;
}
case WM_MOUSELEAVE:
{
close_entry = FALSE;
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
break;
}
default:
return CallWindowProc(old_btn_CloseProc,hwnd,message,wParam,lParam);
//return old_btn_ClickProc(hwnd,message,wParam,lParam);
}
return 0;
}
下面试程序运行的效果图!