Как переопределить поведение всплывающей подсказки по умолчанию? - PullRequest
0 голосов
/ 21 октября 2019

Я создал образец для проверки tooltip элемента управления. Вот немного запутанная программа, которая создает окно, кнопку и регистры для всплывающей подсказки кнопки с сообщением qwerty. Незначительные журналы были добавлены к каждому window / button / tooltip окнам.

#include <windows.h>
#include <Windowsx.h>
#include <CommCtrl.h>
#include <string>
#include <map>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static HWND hwndTip = 0;
static HWND tool = 0;
WNDPROC old_tooltip_proc = 0;
WNDPROC old_button_proc = 0;

std::string GetLastErrorAsString()
{
    //Get the error message, if any.
    DWORD errorMessageID = ::GetLastError();
    if (errorMessageID == 0)
        return std::string(); //No error message has been recorded

    LPSTR messageBuffer = nullptr;
    size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);

    std::string message(messageBuffer, size);

    //Free the buffer.
    LocalFree(messageBuffer);

    return message;
}

void log_msg(std::string prefix, UINT msg)
{
    std::map<UINT, std::string> table
    {
        {WM_NCHITTEST, "WM_NCHITTEST"},
        {TTM_WINDOWFROMPOINT, "TTM_WINDOWFROMPOINT"},
        {WM_SETCURSOR, "WM_SETCURSOR"},
        {WM_PAINT, "WM_PAINT"},
        {WM_NCPAINT, "WM_NCPAINT"},
        {WM_ERASEBKGND, "WM_ERASEBKGND"},
        {WM_SHOWWINDOW, "WM_SHOWWINDOW"},
        {WM_ACTIVATEAPP, "WM_ACTIVATEAPP"},
        {WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING"},
        {WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED"},
        {WM_GETTEXT, "WM_GETTEXT"},
        {WM_MOUSELEAVE , "WM_MOUSELEAVE"},
        {WM_GETTEXTLENGTH, "WM_GETTEXTLENGTH"},
        {WM_NCCALCSIZE, "WM_NCCALCSIZE"},
        {WM_TIMER, "WM_TIMER"},
        {WM_MOVE, "WM_MOVE"},
        {WM_MOUSEMOVE, "WM_MOUSEMOVE"},
        {WM_LBUTTONDOWN, "WM_LBUTTONDOWN"},
        {TTM_RELAYEVENT, "TTM_RELAYEVENT"},
        {SB_SETTEXTA, "SB_SETTEXTA"}
    };
    if (table.find(msg) == table.end())
    {
        OutputDebugString((prefix + " " + std::to_string(msg) + "\n").c_str());
        return;
    }
    OutputDebugString((prefix + " " + table.at(msg) + "\n").c_str());
}

LRESULT CALLBACK tooltip_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    log_msg("TOOLTIP", message);
    return CallWindowProc(old_tooltip_proc, hwnd, message, wParam, lParam);
}

LRESULT CALLBACK button_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    log_msg("BUTTON", message);
    return CallWindowProc(old_button_proc, hwnd, message, wParam, lParam);
}


void createToolTip(HINSTANCE hInstance, HWND parent_window)
{
    hwndTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
        WS_POPUP | TTS_ALWAYSTIP,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        parent_window, NULL, hInstance,
        NULL);
    old_tooltip_proc = (WNDPROC)SetWindowLongPtr(hwndTip, GWLP_WNDPROC, (LONG_PTR)tooltip_proc);
    if (!hwndTip)
    {
        MessageBox(parent_window, "CreateWindowEx TOOLTIPS_CLASS failed", "ERROR", MB_OK);
        return;
    }   
}

TOOLINFO get_tool_info(HWND tool)
{
    TOOLINFO g_toolItem = { 0 };
    g_toolItem.cbSize = sizeof(g_toolItem);
    g_toolItem.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
    g_toolItem.hwnd = GetParent(tool);
    g_toolItem.uId = (UINT_PTR)tool;
    g_toolItem.hinst = NULL;
    g_toolItem.lpszText = LPSTR_TEXTCALLBACK;
    return g_toolItem;
}

void register_tool(HWND _tool)
{
    std::string f("qwerty");
    TOOLINFO toolinfo = get_tool_info(_tool);
    toolinfo.lpszText = const_cast<char*>(f.c_str());
    if (SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolinfo) == FALSE)
    {
        MessageBox(toolinfo.hwnd, "TTM_ADDTOOL failed", "ERROR", MB_OK);
        return;
    }
    tool = _tool;
}

void unregister_tool(HWND tool)
{
    TOOLINFO toolinfo = get_tool_info(tool);
    SendMessage(hwndTip, TTM_DELTOOL, 0, (LPARAM)&toolinfo);
}

HWND createButton(HWND parent_window)
{
    auto handle =  CreateWindow(TEXT("button"), TEXT("Hellooooooooooooooooooooooooooooo"),
        WS_VISIBLE | WS_CHILD,
        10, 10, 800, 250,
        parent_window, NULL, NULL, NULL);
    old_button_proc = (WNDPROC)SetWindowLongPtr(handle, GWLP_WNDPROC, (LONG_PTR)button_proc);
    return handle;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PSTR szCmdLine, int iCmdShow)
{
    INITCOMMONCONTROLSEX ic;
    ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
    ic.dwICC = ICC_TAB_CLASSES;
    InitCommonControlsEx(&ic);
    static TCHAR szAppName[] = TEXT("ToolTipApplication");
    HWND         hwnd;
    MSG          msg;
    WNDCLASS     wndclass;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
            szAppName, MB_ICONERROR);
        return 0;
    }
    hwnd = CreateWindow(szAppName,                  // window class name
        TEXT("The Hello Program"), // window caption
        WS_OVERLAPPEDWINDOW,        // window style
        CW_USEDEFAULT,              // initial x position
        CW_USEDEFAULT,              // initial y position
        CW_USEDEFAULT,              // initial x size
        CW_USEDEFAULT,              // initial y size
        NULL,                       // parent window handle
        NULL,                       // window menu handle
        hInstance,                  // program instance handle
        NULL);                     // creation parameters
    HWND button = createButton(hwnd);
    createToolTip(hInstance, ::GetDesktopWindow());
    register_tool(button);
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    log_msg("window", message);
    return DefWindowProc(hwnd, message, wParam, lParam);
}

Подсказка работает нормально, но я хочу заменить поведение по умолчанию. Если вы наведите курсор мыши на кнопку, появится всплывающая подсказка. Но когда я быстро наведу курсор на всплывающую подсказку, подсказка исчезнет. Я хочу отключить такое исчезновение. Всплывающие подсказки из системного трея напоминают это поведение. Если вы наводите курсор на всплывающую подсказку, она не исчезнет одновременно. Примерно так:

enter image description here

PS Я пытался переопределить обработку сообщения TTM_RELAYEVENT, но оно не дало никаких результатов.

1 Ответ

1 голос
/ 22 октября 2019

Добавить TTF_TRANSPARENT

TTF_TRANSPARENT: заставляет элемент управления всплывающей подсказки пересылать сообщения о событиях мыши в родительское окно. Это ограничено событиями мыши, которые происходят в границах окна всплывающей подсказки.

код:

TOOLINFO get_tool_info(HWND tool)
{
    TOOLINFO g_toolItem = { 0 };
    g_toolItem.cbSize = sizeof(g_toolItem);
    g_toolItem.uFlags = TTF_IDISHWND | TTF_SUBCLASS | TTF_TRANSPARENT;
    g_toolItem.hwnd = GetParent(tool);
    g_toolItem.uId = (UINT_PTR)tool;
    g_toolItem.hinst = NULL;
    g_toolItem.lpszText = LPSTR_TEXTCALLBACK;
    return g_toolItem;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...