Сообщений 2    Оценка 1        Оценить  
Система Orphus

Как создать не исчезающий со временем тултип?

Автор: Александр Шаргин

Версия текста: 1.0.1

Первое, что приходит в голову в связи с этим вопросом - это сообщение TTM_SETDELAYTIME. Оно предназначено для задания различных временных интервалов, связанных с тултипом. В частности интервал, задаваемый флагом TTDT_AUTOPOP, определяет промежуток времени, по истечении которого тултип исчезает автоматически. Проблема с этим сообщением состоит в том, что тултип воспринимает интервалы как двухбайтовые числа, да ещё и в милисекундах. Это значит, что нам не удастся задать интервал больше приблизительно 30 секунд , а такой интервал вряд ли покажется пользователю бесконечным.

Поскольку законного метода решить задачу не существует, придётся прибегнуть к незаконному. Дело в том, что тултип использует для измерения промежутков времени стандартный механизм таймеров системы Windows. В частности, время до исчезновения измеряется таймером с идентификатором 4 (это и есть недокументированный параметр, вычисленный при помощи Spy++). Если уничтожить его (таймер) с помощью функции KillTimer, тултип навсегда останется на экране. Единственная проблема, которая здесь возникает - в каком месте программы лучше всего убивать таймер? Поэкспериментировав с этим подходом, я пришёл к выводу, что таймер проще всего убивать по таймеру. Разумеется, нужно проследить, чтобы период нашего таймера был меньше времени исчезновения тултипа (для этого достаточно использовать уже рассмотренное сообщение TTM_SETDELAYTIME). Вот как может выглядеть функция окна, реализующая эту идею.

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_CREATE:
        ...
        SetTimer(hWnd, 0, 3000, NULL);
        break;

    case WM_TIMER:
        // hTip - дескриптор тултипа
        if(IsWindow(hTip))
            KillTimer(hTip, 4); // Убиваем таймер!
    ...
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

Совершенно аналогично этот способ реализуется в MFC, для этого придётся написать обработчики OnCreate и OnTimer.

int CSomeWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
    
    SetTimer(0, 3000, NULL);
    
    return 0;
}

void CSomeWnd::OnTimer(UINT nIDEvent) 
{
    // pTT - указатель на объект класса CToolTipCtrl
    pTT->KillTimer(4);
    CWnd::OnTimer(nIDEvent);
}

Если вы создаёте тултип вручную, проблем с получением указателя pTT не возникает. Если же вы активизируете его, используя CWnd::EnableToolTips, нужный указатель можно получить из структуры состояния потока, используя выражение AfxGetThreadState()->m_pToolTip.


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
    Сообщений 2    Оценка 1        Оценить