Не позволяйте всплывающей подсказке на CMFCRibbonBar - PullRequest
3 голосов
/ 26 марта 2020

У меня есть CMFCRibbonBar контроль. Мне нужно создать мою собственную подсказку. Моя подсказка происходит от CMFCToolTipCtrl и работает довольно хорошо. Но ...

При наведении курсора на кнопку ленты появляется всплывающая подсказка. Замечательно. Но когда я перемещаю мышь из кнопки, всплывающая подсказка закрывается. Это не то, что я хочу. Мне просто нужно иметь возможность перемещать мышь по всплывающей подсказке и щелкать ссылку, которая находится во всплывающей подсказке. Представьте, что это какая-то интерактивная подсказка. Что я могу сделать, чтобы достичь этого?

1 Ответ

0 голосов
/ 31 марта 2020

ОК, я сделал кое-что полезное, но результат не удовлетворяет 100%.

Итак, прежде всего, создайте собственную подсказку, наследующую от CMfcToolTipCtrl. Идея в том, что: - пользователь может захотеть взаимодействовать с вашей подсказкой или нет. Таким образом, мы должны создать какой-то умный способ из закрытия и показа всплывающей подсказки. - Мы можем предположить, что когда пользователь наводит всплывающую подсказку с помощью мыши, он хочет взаимодействовать.

К сожалению, всякий раз, когда пользователь перемещает мышь от кнопки ленты, всплывающая подсказка исчезает. Но иногда мы можем поймать MouseMove внутри него. Но это довольно редко. Итак, мы должны получить момент, когда всплывающая подсказка закрывается системой.

Существует такое сообщение, которое мы можем добавить к карте сообщений:

ON_NOTIFY_REFLECT(TTN_POP, &CAsInteractiveToolTip::OnPop)

Теперь наш OnPop будет выглядит так (я использую идиому pImpl):

void CAsInteractiveToolTip::OnPop(NMHDR* pNMHDR, LRESULT* pResult)
{
    if (m_pImpl->m_forceClose)
    {
        CMFCToolTipCtrl::OnPop(pNMHDR, pResult);

        m_pImpl->m_forceOpened = false;
        m_pImpl->m_forceClose = false;
        m_pImpl->StopForceOpenTimer();
    } 
    else
    {
        m_pImpl->StartForceOpenTimer();
    }

    *pResult = 0;
}

Теперь, что здесь происходит: - когда подсказка закрывается, проверьте, не закрыта ли она принудительно нашим кодом. Если нет, значит, он закрыт системой. В таком случае мы должны дать пользователю возможность навести указатель мыши на нашу подсказку. Итак, мы должны снова показать подсказку (заставить ее показать). Это делается методом таймера. StartForceOpenTimer - это простой метод, который запускает таймер:

void StartForceOpenTimer()
{
    if (!m_forceOpenTimerActive)
    {
        m_self.SetTimer(IDT_FORCE_OPEN_TIMER, 100, (TIMERPROC)NULL);
        m_forceOpenTimerActive = true;
    }
}

Теперь волхвы c запускаются в методе таймера:

void CAsInteractiveToolTip::OnForceTimer()
{
    static DWORD waitForUserStartTime = 0;
    static bool waitingForUserReaction = false;     

    if (!waitingForUserReaction)
    {
        //open and give the user chance to mouse move over it within 0.5 seconds
        SetWindowPos(&wndTopMost, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
        waitForUserStartTime = GetTickCount();
        waitingForUserReaction = true;
        return;
    }

    if (GetTickCount() - waitForUserStartTime > 500)
    {
        m_pImpl->StopForceOpenTimer();
        m_pImpl->m_forceClose = true;
        waitingForUserReaction = false;
        m_pImpl->PopToolTip();      
        return;
    }

    if (m_pImpl->m_doForceOpen)
    {
        m_pImpl->StopForceOpenTimer();
        waitingForUserReaction = false;
        m_pImpl->m_forceOpened = true;
    }   
}

Общая идея: - заставить показывать всплывающую подсказку - подождите около 0,5 секунды, пока пользователь наведет курсор мыши - если пользователь наводит указатель мыши на окно всплывающей подсказки, мы можем предположить, что он хочет взаимодействовать. Таким образом, мы можем оставить окно открытым. - если пользователь не взаимодействует с окном в течение 0,5 секунды, просто закройте всплывающую подсказку.

Теперь метод PopToolTip просто запускает другой таймер с интервалом в 100 мс. А вот другая часть волхвов c:

void CAsInteractiveToolTip::OnPopTimer()
{
    m_pImpl->StopForceOpenTimer();
    KillTimer(IDT_POP_TIMER);
    //Pop();

    m_pImpl->m_forceClose = true;
    m_pImpl->m_hdr.idFrom = 2;
    m_pImpl->m_hdr.hwndFrom = GetSafeHwnd();
    m_pImpl->m_hdr.code = (int)TTN_POP; //4294966774
    GetParent()->SendMessage(WM_NOTIFY, 1, (LPARAM)&m_pImpl->m_hdr);
    //GetParent()->SendMessage(WM_NOTIFY, 2, (LPARAM)&m_pImpl->m_hdr);

    ShowWindow(SW_HIDE);
}

Теперь этот метод должен просто выскочить (скрыть) подсказку. Но по какой-то причине в моем случае вызов метода Pop () ничего не делает. Поэтому мне нужно отправить сообщение WM_NOTIFY с соответствующими параметрами (они взяты из моих отладочных наблюдений). Теперь OnPop снова запустится, но на этот раз для m_forceClose задано значение true, поэтому всплывающая подсказка больше не будет отображаться (первый таймер не запустится).

Теперь третья часть волхвов c - Мышь Шаг. Просто добавьте его в карту сообщений:

ON_WM_MOUSEMOVE()

И метод:

void CAsInteractiveToolTip::OnMouseMove(UINT nFlags, CPoint point)
{
    m_pImpl->m_doForceOpen = true; //let the first timer know, that user wants to interact

    CMFCToolTipCtrl::OnMouseMove(nFlags, point);
}

И вы можете просто скрыть подсказку, когда пользователь нажимает на нее. Просто:

void CAsInteractiveToolTip::OnLButtonDown(UINT nFlags, CPoint point)
{
    m_pImpl->m_forceClose = true;
    m_pImpl->PopToolTip();
}

Это не идеальное решение, но оно как-то работает. Если у кого-нибудь есть предложения, буду рад их услышать:)

...