当前位置:C++技术网 > 资讯 > win32实现鼠标经过控件时的实时提示功能

win32实现鼠标经过控件时的实时提示功能

更新时间:2016-02-05 11:49:54浏览次数:1+次

    在文章《窗口子类化如何实现切换多个子窗口控件的焦点》中,我们详细解释了在窗口和多个子窗口控件中切换焦点的技术点。我们利用到了窗口子类化的技术。而我们这里实现鼠标经过控件时的实时提示,同样也是基于窗口子类化实现的。所以,窗口子类化相关的讲解,看焦点切换的讲解文章即可,就不在此重复了。

    我们先看看效果图:

鼠标放在按钮控件上,标签static控件出现了提示文字

【鼠标放在按钮控件上,标签static控件出现了提示文字】

鼠标离开按钮控件,标签static控件的提示文字消失

【鼠标离开按钮控件,标签static控件的提示文字消失】
    我们的实现效果就是,当鼠标移动到按钮上,窗口就设置标签的文字,当鼠标离开按钮,窗口就清除标签上的文字。
    我们需要创建一个按钮控件和一个静态标签控件。静态标签控件用于显示提示文字。我们在窗口创建消息WM_CREATE中创建好按钮和标签控件,然后将按钮子类化,修改好窗口过程。
    当鼠标移动到按钮控件上时,设置标签控件的提示文字。但是你知道,当鼠标移动到控件上之后,鼠标消息就流入了控件窗口。此时的鼠标移动消息并不会被窗口处理,而是被按钮控件的默认窗口过程处理,即忽略鼠标移动消息。
    为了让窗口来处理鼠标移动消息,那么就让按钮控件将接收到的鼠标移动消息发给父窗口。这也就要在子类化的窗口过程中实现。实现过程很简单,就是用SendMessage给父窗口发送一个WM_MOUSEMOVE消息。

    不过不管是鼠标在窗口客户区,还是在按钮控件上,窗口都会受到鼠标移动消息,这样窗口就无法分辨鼠标是不是在按钮上。所以,我们增加了一个全局的布尔变量,在子类化窗口过程中接收到鼠标移动的消息后,就设置这个变量。在窗口设置了标签的文字之后,就重置布尔变量。如果窗口检测到布尔变量为false,则表示鼠标是在窗口客户区上移动的,就清除标签上的文字。

    我们可以看到,按钮控件实际上是将控件上的消息原样发回给了窗口,这个就就做消息反射,在MFC中已经被封装起来了。

    下面是完整代码:
#include "windows.h"
#include <tchar.h>
// - 项目是Unicode字符集
HWND hwndPa;//父窗口句柄,便于子窗口发送消息,设置为全局变量
WNDPROC wndProc;//窗口过程类型变量,用于存储窗口之前的窗口过程
static bool bIsOnBtn=false;
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK BtnProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    //按钮控件子类化的窗口过程,对按钮的一些事件进行处理
    switch(message)
    {
    case WM_MOUSEMOVE:
        SendMessage(hwndPa,message,wParam,lParam);
        bIsOnBtn=true;
        break;
    default:
        break;//跳出到默认处理
    }
    return CallWindowProc(wndProc,hwnd, message, wParam, lParam);//调用按钮控件的窗口过程,这样就支持按钮的各种特性
}
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    static HWND hChild1,hTip;
    switch (message)
    {
        case WM_CREATE:
            hTip =  CreateWindow(_T("static"),_T(""),WS_CHILD|WS_VISIBLE,0,100,200,20,hwnd,(HMENU)2,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
            hChild1 = CreateWindow(_T("button"),_T("1"),WS_CHILD|WS_VISIBLE,0,0,100,50,hwnd,(HMENU)1,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
            wndProc = (WNDPROC)SetWindowLong(hChild1,GWL_WNDPROC,(LONG)BtnProc);//子类化按钮1,得到按钮的原先系统的按钮窗口过程
            break;
        case WM_MOUSEMOVE:
            if(bIsOnBtn)
            {
                SetWindowText(hTip,_T("鼠标移动到了按钮上了"));
                bIsOnBtn=false;
            }
            else
            {
                SetWindowText(hTip,_T(""));
            }
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
        break;//跳出到默认处理
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;

    if(!RegisterClass(&wndClass))return 0;
    hwndPa = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,10,100,600,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwndPa,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}