浮動小数点数のみを受け入れるようにエディット コントロールをサブクラス化しました。ユーザーが無効な入力をしたときにツールチップをポップしたいと思います。私がターゲットとする動作は、次の 1 つの編集コントロールのようなものですES_NUMBER
。
これまでのところ、追跡ツールチップを実装し、ユーザーが無効な入力を行ったときに表示することができました。
ただし、ツールチップの場所が間違っています。これを使用ScreenToClient
しClientToScreen
て修正しようとしましたが、失敗しました。
SCCEを作成する手順は次のとおりです。
1) Visual Studio でデフォルトの Win32 プロジェクトを作成します。
stdafx.h
2) 次のインクルードを のすぐ下に追加します#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='*'\"")
3) 次のグローバル変数を追加します。
HWND g_hwndTT;
TOOLINFO g_ti;
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);
}
WM_CREATE
5) 次のハンドラーを追加します。
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;
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
SSCCEについては以上です。
私の質問は次のとおりです。
メイン ウィンドウにツールチップを正しく配置するにはどうすればよいですか? キャレット座標を操作するにはどうすればよいですか?
ツールチップ ハンドルとツール情報構造をグローバルにしない方法はありますか?
お時間をいただきありがとうございます。
よろしくお願いします。
編集#1:
ScreenToClient
サブクラス プロシージャの呼び出しを削除することで、かなりの改善を達成することができました。x座標は良好ですが、y座標はわずかに低くなる可能性があります。どうにかしてグローバル変数を削除したいのですが...
編集#2:
メッセージを使用しEM_GETRECT
、y 座標を書式設定用の四角形の下部に設定することで、 y 座標を調整できました。
RECT rcClientRect;
Edit_GetRect( hwnd, &rcClientRect );
pt.y = rcClient.bottom;
これで、最終結果ははるかに良くなりました。あとはグローバル変数を削除するだけです...
編集#3:
割れちゃったみたい!解決策はメッセージに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;