Tooltip bei ungültiger Eingabe im Bearbeitungssteuerelement anzeigen

Ich habe die Bearbeitungssteuerung untergeordnet, um nur gleitende Zahlen zu akzeptieren. Ich möchte einen Tooltip anzeigen, wenn der Benutzer eine ungültige Eingabe vornimmt. Das Verhalten, das ich anvisiere, entspricht dem eines BearbeitungssteuerelementsES_NUMBER hat :

Bisher konnte ich den Tracking-Tooltip implementieren und anzeigen, wenn der Benutzer ungültige Eingaben vornimmt.

Der Tooltipp ist jedoch falsch platziert. Ich habe versucht zu verwendenScreenToClient undClientToScreen um dies zu beheben, sind aber gescheitert.

Hier sind die Anweisungen zum ErstellenSCCE :

1) Erstellen Sie ein Standard-Win32-Projekt in Visual Studio.

2) Fügen Sie die folgenden Includes in Ihrestdafx.h, knapp unter#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) Fügen Sie diese globalen Variablen hinzu:

HWND g_hwndTT;
TOOLINFO g_ti;

4) Hier ist eine einfache Unterklassenprozedur für Bearbeitungssteuerelemente (nur zu Testzwecken):

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);
} 

5) Fügen Sie Folgendes hinzuWM_CREATE Handler:

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) Initialisieren Sie die allgemeinen Steuerelemente inMyRegisterClass ( Vorreturn Aussage ) :

// 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 

Das war's auch schonSSCCE.

Meine Fragen sind folgende:

Wie kann ich den Tooltip in meinem Hauptfenster richtig positionieren? Wie soll ich mit Caret-Koordinaten manipulieren?

Gibt es eine Möglichkeit, dass das Tooltip-Handle und die Toolinfo-Struktur nicht global sind?

Vielen Dank für Ihre Zeit.

Freundliche Grüße.

EDIT # 1:

Durch das Löschen habe ich eine ziemliche Verbesserung erreichtScreenToClient in der Unterklasse Prozedur aufrufen. Die x-Koordinate ist gut, die y-Koordinate könnte etwas niedriger sein. Ich würde trotzdem gerne globale Variablen irgendwie entfernen ...

EDIT # 2:

Ich konnte die y-Koordinate mit anpassenEM_GETRECT Nachricht und Festlegen der y-Koordinate am unteren Rand des Formatierungsrechtecks:

RECT rcClientRect;
Edit_GetRect( hwnd, &rcClientRect );
pt.y = rcClient.bottom;

Jetzt ist das Endergebnis viel besser. Jetzt müssen nur noch globale Variablen entfernt werden ...

EDIT # 3:

Es scheint, dass ich es geknackt habe! Die Lösung liegt inEM_SHOWBALLOONTIP undEM_HIDEBALLOONTIP Mitteilungen! Der Tooltip befindet sich an der Position "Einfügemarke". Die Ballonform entspricht der auf dem Bild und wird automatisch ausgeblendet. Und das Beste ist dasIch brauche keine globalen Variablen!

Hier ist mein Unterklassen-Prozedur-Snippet:

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;

Antworten auf die Frage(3)

Ihre Antwort auf die Frage