推测的处理过程:

要在标题栏上增加一个问号按钮,得参考一些系统菜单操作API;

点这个问号按钮会产生一个系统消息,我在处理这个消息的时候把对话框的鼠标光标改为带问号的指针,用这个带问号的指针点击对话框的某个元素,就产生一个“WM_LBUTTONDOWN”的消息,处理这个消息,根据鼠标光标的位置判定鼠标点击的是对话框上的那个元素,获取这个元素的帮助字符串,创建一个没有Title的很小的窗口,把这个小窗口在鼠标光标位置处Pop出来,然后在上面Draw一些帮助字符串,当这个小窗口失去焦点,或被用户用鼠标点击了一下,或按了一下键盘什么的,就会Hide起来,当用户又执行了上述的“问号点击操作”之后,这个小窗口才会再次Show出,最后在对话框关闭的时候Destroy这个小窗口。

 

首先在对话框的标题栏上增加一个问号按钮就不容易,有没有简单些的方法?当然有,看下图:
 

 


其实只需要在对话框属性上选中Context Help这个选项就OK了;

 

WM_HELP,MSDN上能找到,我大致说明一下:

 

lphi = (LPHELPINFO) lParam;

 

typedef  struct  tagHELPINFO

{

    UINT     cbSize;

    int      iContextType

    int      iCtrlId;

    HANDLE   hItemHandle;

    DWORD    dwContextId;

    POINT    MousePos;

} HELPINFO, FAR *LPHELPINFO;

 

WM_HELP的lParam参数是指向HELPINFO这个结构的指针,我们需要用到这个结构的几个成员,一是iContextType==HELPINFO_WINDOW的时候,iCtrlId的值,这个值就是点击的对话框上元素的ID,具体看resource.h中的定义;另一个就是MousePos,光标位置;至于其它,就自己看看MSDN,在别处会用到的,但这里就简单些,暂时不用,此文只是起个抛砖引玉的作用。

 

 

现在只剩下一个问题了,那就是如何实现那个pop出来的小窗口?我马上想到了tooltip control,什么是tooltip control?我想你天天见,天天用,只是不知道它就是tooltip control而已,看看下面这截图:

 

 


当鼠标光标停留在工具栏上片刻(通常是你最长的双击间隔时间),光标下面就会出现一个小提示窗口,你把鼠标移动到别处后,这个小提示就消失或者换成别的了;

 

最后我是自己手动实现了这么一个窗口的,下面我将给出代码:

 

在对话框的WM_INITDIALOG消息处理中:

{

    WNDCLASS wndclass;

    wndclass.style         = CS_HREDRAW | CS_VREDRAW;

    wndclass.lpfnWndProc   = MyToolTipProc;

    wndclass.cbClsExtra    = 0;

    wndclass.cbWndExtra    = 0;

    wndclass.hInstance     = g_hInstance;

    wndclass.hIcon         = LoadIcon(g_hInstance, (LPCTSTR)IDI_ICONAPP);

    wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);

    wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);

    wndclass.lpszMenuName  = NULL;

    wndclass.lpszClassName = TEXT("MyToolTipWindow");

    RegisterClass (&wndclass);

    hwndToolTip = CreateWindow(TEXT("MyToolTipWindow"), TEXT(""),

       WS_POPUP|WS_BORDER, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

       CW_USEDEFAULT, hDlg, (HMENU)NULL, g_hInstance, NULL);

}

 

其中"MyToolTipWindow"是我要注册的窗口类名,你可以起别的名字,注意这个窗口是没有标题栏的,hDlg是这个小小窗口的父窗口,也就是对话框的句柄,g_hInstance是进程实例句柄,我是把它存在一个全局变量中的,所以有个“g_”前缀,还要注意一下,把hwndToolTip作为全局变量或者static变量,以保存它的值,因为之后我们还需要用。

 

在对话框的WM_DESTROY消息中:

 

{

    DestroyWindow(hwndToolTip);

}

 

把这个tooltip control删除。

 

好,现在我们看看"MyToolTipWindow"这个窗口的消息处理函数MyToolTipProc:

 

#define WM_USER_SETTEXT (WM_USER+10) //wParam : Pointer to the TCHAR string; lParam : NULL

#define WM_USER_SHOWWINDOW (WM_USER+11) //wParam: mouse.x; lParam : mouse.y

 

// Message handler for MyToolTipWindow.

LRESULT CALLBACK MyToolTipProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

    static TCHAR szToDisp[1024];

    switch (message)

    {

    case WM_CREATE:

       return TRUE;

      

    case WM_LBUTTONDOWN:

    case WM_RBUTTONDOWN:

    case WM_KEYDOWN:

    case WM_KILLFOCUS:

       ShowWindow(hwnd, FALSE);

       break;

 

    case WM_PAINT:

       {

           RECT rect;

           PAINTSTRUCT ps;

           HDC hdc = BeginPaint (hwnd, &ps);

           GetWindowRect(hwnd, &rect);

           rect.right = rect.right-rect.left;

           rect.bottom = rect.bottom-rect.top;

           rect.top = 0;

           rect.left = 0;

           DrawText(hdc, szToDisp, lstrlen(szToDisp), &rect, DT_LEFT|DT_WORDBREAK);

           EndPaint (hwnd, &ps);

       }

       break;

    case WM_USER_SETTEXT:

       lstrcpy(szToDisp, (TCHAR *)wParam);

       return TRUE;

    case WM_USER_SHOWWINDOW:

       {

           PAINTSTRUCT ps;

           HDC hdc = BeginPaint (hwnd, &ps);

           DWORD dwRtn = GetTabbedTextExtent(hdc, szToDisp, lstrlen(szToDisp), 0, NULL);

           EndPaint (hwnd, &ps);

 

           UINT iScreenWidth = GetSystemMetrics(SM_CXFULLSCREEN);

           UINT iXPos = wParam+LOWORD(dwRtn)+4>iScreenWidth?iScreenWidth-LOWORD(dwRtn)-4:wParam;

           MoveWindow(hwnd, iXPos, lParam+21, LOWORD(dwRtn)+4, HIWORD(dwRtn)+3, FALSE);

           ShowWindow(hwnd, TRUE);

       }

       return TRUE;

    }

    return DefWindowProc(hwnd, message, wParam, lParam);

}

 

接到WM_LBUTTONDOWN,WM_RBUTTONDOWN,WM_KEYDOWN,WM_KILLFOCUS这几个消息之后,就把窗口隐藏起来,用WM_USER_SETTEXT这个消息设置要在mytooltip中显示的文本,然后用WM_USER_SHOWWINDOW把mytooltip show出来,WM_USER_SHOWWINDOW里面那些处理是为了根据要显示的文本和鼠标的位置调整mytooltip的窗口大小和位置,其它倒是很简单,没什么好解释的。

 

最后就是在对话框处理函数中加入对WM_HELP消息的响应:

 

{

    LPHELPINFO lphi = (LPHELPINFO) lParam;

    if (lphi->iContextType==HELPINFO_WINDOW)

    {

       TCHAR szDisp[256];

       memset(szDisp, 0, sizeof(szDisp));

       LoadString(g_hInstance, lphi->iCtrlId, szDisp, 255);

       SendMessage(hwndToolTip, WM_USER_SETTEXT, (WPARAM)(szDisp), NULL);

       if (0==lstrlen(szDisp))

           break;

       SendMessage(hwndToolTip, WM_USER_SHOWWINDOW, lphi->MousePos.x, lphi->MousePos.y);

    }

}

 

LoadString函数能在程序资源中Load出相应对话框元素ID的string,这个需要自己编辑一下string资源。大功告成;

 

 

 
如果文本太长了,不会自动换行,很难看,而且没有“阴影效果”,这两个功能就交给读者你了;(#add 可设置CToolTipCtrl的宽度,)

 

posted on 2010-12-19 19:13  maxweii  阅读(1690)  评论(1编辑  收藏  举报