Alw*_*uff 11 c++ winapi tooltip editcontrol
我有子类编辑控件只接受浮动数字.我想在用户输入无效时弹出工具提示.我的目标行为就像一个带有的编辑控件ES_NUMBER
:
到目前为止,我能够实现跟踪工具提示并在用户进行无效输入时显示它.
但是,工具提示是错误的.我试图使用ScreenToClient
并ClientToScreen
修复此问题但失败了.
以下是创建SCCE的说明:
1)在Visual Studio中创建默认的Win32项目.
2)在您的stdafx.h
下方添加以下内容#include <windows.h>
:
#include <windowsx.h>
#include <commctrl.h>
#pragma comment( lib, "comctl32.lib")
#pragma comment(linker, \
"\"/manifestdependency:type='Win32' "\
"name='Microsoft.Windows.Common-Controls' "\
"version='6.0.0.0' "\
"processorArchitecture='*' "\
"publicKeyToken='6595b64144ccf1df' "\
"language='*'\"")
Run Code Online (Sandbox Code Playgroud)
3)添加这些全局变量:
HWND g_hwndTT;
TOOLINFO g_ti;
Run Code Online (Sandbox Code Playgroud)
4)这是编辑控件的简单子类过程(仅用于测试目的):
LRESULT CALLBACK EditSubProc ( HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
switch (message)
{
case WM_CHAR:
{
POINT pt;
if( ! isdigit( wParam ) ) // if not a number pop a tooltip!
{
if (GetCaretPos(&pt)) // here comes the problem
{
// coordinates are not good, so tooltip is misplaced
ClientToScreen( hwnd, &pt );
/************************** EDIT #1 ****************************/
/******* If I delete this line x-coordinate is OK *************/
/*** y-coordinate should be little lower, but it is still OK **/
/**************************************************************/
ScreenToClient( GetParent(hwnd), &pt );
/************************* Edit #2 ****************************/
// this adjusts the y-coordinate, see the second edit
RECT rcClientRect;
Edit_GetRect( hwnd, &rcClientRect );
pt.y = rcClientRect.bottom;
/**************************************************************/
SendMessage(g_hwndTT, TTM_TRACKACTIVATE,
TRUE, (LPARAM)&g_ti);
SendMessage(g_hwndTT, TTM_TRACKPOSITION,
0, MAKELPARAM(pt.x, pt.y));
}
return FALSE;
}
else
{
SendMessage(g_hwndTT, TTM_TRACKACTIVATE,
FALSE, (LPARAM)&g_ti);
return ::DefSubclassProc( hwnd, message, wParam, lParam );
}
}
break;
case WM_NCDESTROY:
::RemoveWindowSubclass( hwnd, EditSubProc, 0 );
return DefSubclassProc( hwnd, message, wParam, lParam);
break;
}
return DefSubclassProc( hwnd, message, wParam, lParam);
}
Run Code Online (Sandbox Code Playgroud)
5)添加以下WM_CREATE
处理程序:
case WM_CREATE:
{
HWND hEdit = CreateWindowEx( 0, L"EDIT", L"edit", WS_CHILD | WS_VISIBLE |
WS_BORDER | ES_CENTER, 150, 150, 100, 30, hWnd, (HMENU)1000, hInst, 0 );
// try with tooltip
g_hwndTT = CreateWindow(TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON,
0, 0, 0, 0, hWnd, NULL, hInst, NULL);
if( !g_hwndTT )
MessageBeep(0); // just to signal error somehow
g_ti.cbSize = sizeof(TOOLINFO);
g_ti.uFlags = TTF_TRACK | TTF_ABSOLUTE;
g_ti.hwnd = hWnd;
g_ti.hinst = hInst;
g_ti.lpszText = TEXT("Hi there");
if( ! SendMessage(g_hwndTT, TTM_ADDTOOL, 0, (LPARAM)&g_ti) )
MessageBeep(0); // just to have some error signal
// subclass edit control
SetWindowSubclass( hEdit, EditSubProc, 0, 0 );
}
return 0L;
Run Code Online (Sandbox Code Playgroud)
6)初始化MyRegisterClass
(return
声明前)的常用控件:
// initialize common controls
INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES |
ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_STANDARD_CLASSES ;
if( !InitCommonControlsEx(&iccex) )
MessageBeep(0); // signal error
Run Code Online (Sandbox Code Playgroud)
对于SSCCE来说就是这样.
我的问题如下:
如何在主窗口中正确定位工具提示?我应该如何操纵插入符号坐标?
工具提示句柄和toolinfo结构是否有办法不是全局的?
感谢您的时间.
最好的祝福.
通过删除ScreenToClient
子类过程中的调用,我设法实现了相当大的改进.x坐标很好,y坐标可能略低.我还是想以某种方式删除全局变量......
我可以通过使用EM_GETRECT
消息并将y坐标设置到格式化矩形的底部来调整y坐标:
RECT rcClientRect;
Edit_GetRect( hwnd, &rcClientRect );
pt.y = rcClient.bottom;
Run Code Online (Sandbox Code Playgroud)
现在最终结果要好得多.剩下的就是删除全局变量......
好像我已经破解了!解决方案是EM_SHOWBALLOONTIP
和EM_HIDEBALLOONTIP
消息!工具提示位于插入符号位置,气球形状与图片上的气球形状相同,并且它会自动自动解散.最好的是我不需要全局变量!
这是我的子类过程片段:
case WM_CHAR:
{
// whatever... This condition is for testing purpose only
if( ! IsCharAlpha( wParam ) && IsCharAlphaNumeric( wParam ) )
{
SendMessage(hwnd, EM_HIDEBALLOONTIP, 0, 0);
return ::DefSubclassProc( hwnd, message, wParam, lParam );
}
else
{
EDITBALLOONTIP ebt;
ebt.cbStruct = sizeof( EDITBALLOONTIP );
ebt.pszText = L" Tooltip text! ";
ebt.pszTitle = L" Tooltip title!!! ";
ebt.ttiIcon = TTI_ERROR_LARGE; // tooltip icon
SendMessage(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt);
return FALSE;
}
}
break;
Run Code Online (Sandbox Code Playgroud)
经过进一步测试,我决定将其作为答案,以便其他人可以清楚地发现它。
解决方案是使用EM_SHOWBALLOONTIP
和EM_HIDEBALLOONTIP
消息。您无需创建工具提示并将其关联到编辑控件!因此,我现在要做的只是子类编辑控件,一切正常:
LRESULT CALLBACK EditSubProc ( HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
switch (message)
{
case WM_CHAR:
{
if( ! isdigit( wParam ) ) // if not a number pop a tooltip!
{
EDITBALLOONTIP ebt;
ebt.cbStruct = sizeof( EDITBALLOONTIP );
ebt.pszText = L" Tooltip text! ";
ebt.pszTitle = L" Tooltip title!!! ";
ebt.ttiIcon = TTI_ERROR_LARGE; // tooltip icon
SendMessage(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt);
return FALSE;
}
else
{
SendMessage(hwnd, EM_HIDEBALLOONTIP, 0, 0);
return ::DefSubclassProc( hwnd, message, wParam, lParam );
}
}
break;
case WM_NCDESTROY:
::RemoveWindowSubclass( hwnd, EditSubProc, 0 );
return DefSubclassProc( hwnd, message, wParam, lParam);
break;
}
return DefSubclassProc( hwnd, message, wParam, lParam);
}
Run Code Online (Sandbox Code Playgroud)
而已!
希望这个答案也能对某人有所帮助!
我将评论作为答案(我应该早点这样做),以便清楚地表明问题已得到解答:
TTM_TRACKPOSITION 的 MSDN 文档表示 x/y 值是“在屏幕坐标中”。
我不完全确定,但 y 坐标可能对应于插入符的顶部,如果您想将工具提示放置在编辑框的中间,您可以添加编辑框高度的一半。
编辑
全局变量,您可以将所有全局变量捆绑到一个结构中,为该结构分配内存,并使用编辑窗口的SetWindowLongPtr API 调用传递该结构的指针,然后窗口过程可以使用GetWindowLongPtrGWLP_USERDATA
检索值...