David Wincelberg Ответов: 1

Можно ли создать элемент управления списком для надежного отображения подсказок инструментов?


Когда элемент управления списком (CListCtrl) имеет расширенный стиль LVS_EX_INFOTIP, наведение указателя мыши на элемент, который заканчивается эллипсами ( ... ), не всегда приводит к появлению подсказки, показывающей
полный текст. Можно ли что-нибудь с этим сделать?

Следующая веб-страница обсуждает эту проблему, но не дает на нее полного ответа.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/4aae2b02-39af-4cd9-b685-20ebadd14738/tooltip-on-clistctrl-lvsexlabeltip-lvsexinfotip-problem

Что я уже пробовал:

В качестве обходного пути я изменяю размер столбцов в соответствии с содержимым:
m_lc.SetColumnWidth (n, LVSCW_AUTOSIZE_USEHEADER);
Однако это не решает проблему.

1 Ответов

Рейтинг:
2

Jochen Arndt

Решением может быть обработка OnToolHitTest и отображение всплывающей подсказки самостоятельно.

Фрагмент кода из существующего проекта (отредактированный и сокращенный):

INT_PTR CMyListCtrl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
    // Check if clicked inside list area (including header). 
    // Must use client rect to exclude scroll bars.
    CRect rectList;
    GetClientRect(&rectList);
    if (!rectList.PtInRect(point))
        return CListCtrl::OnToolHitTest(point, pTI);

    LVHITTESTINFO tHitTest;
    tHitTest.pt = point;
    // CListCtrl::SubItemHitTest() is not declared as const.
    // However, it is an inline function doing this (see afxcmn2.inl):
    ::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, 0, reinterpret_cast<LPARAM>(&tHitTest));
    // on empty row or dummy column
    if (tHitTest.iItem < 0)
        return -1;

    // Again, CListCtrl::GetSubItemRect() is not declared as const.
    // So send message here (see winctrl2.cpp).
    RECT rect;
    rect.top = tHitTest.iSubItem;
    rect.left = LVIR_BOUNDS;
    if (!::SendMessage(m_hWnd, LVM_GETSUBITEMRECT, tHitTest.iItem, reinterpret_cast<LPARAM>(&rect)))
        return -1;

    CString strTipText;
    	
    // Check if on header.
    // This requires knowing the height of the header.
    // GetHeaderHeight() must be implemented yourself!
    int nHeaderHeight = GetHeaderHeight();
    if (tHitTest.iItem == 0 && point.y < nHeaderHeight)
    {
        HDITEM hdi; 
        // EDIT: Replaced char by TCHAR
        TCHAR buf[255];
        hdi.mask = HDI_TEXT;
        hdi.cchTextMax = sizeof(buf) / sizeof(TCHAR);
        hdi.pszText = buf;
        GetHeaderCtrl()->GetItem(tHitTest.iSubItem, &hdi); 
        strTipText = hdi.pszText;
    }
    else
        strTipText = GetItemText(tHitTest.iItem, tHitTest.iSubItem);
    int nSize = strTipText.GetLength();
    if (0 == nSize)
        return -1;
	
    // Make an ID from row and column number used also as return value.
    // We must add 1 to ensure that ID is not zero.
    // Even when passing the tooltip text here, we must return a unique ID.
    // Tooltips are not displayed when returning the same ID value as for the last call.
    pTI->uId = (UINT)((tHitTest.iItem << 8) + (tHitTest.iSubItem & 0xff) + 1);
    pTI->rect = rect;
    pTI->hwnd = m_hWnd;
    
    // Passing tool tip text using an allocated buffer.
    // By specifying the tooltip text here, we can omit the OnToolTipNotify handler.
    // If text is passed by pointer and pTI->hinst is NULL, the memory must be allocated from the local heap.
    // FilterToolTipMessage() will free the memory (see tooltip.cpp from MFC).
    // Using this allows tooltip text with more than 80 characters.
    pTI->lpszText = new TCHAR [++nSize];
    _tcscpy(pTI->lpszText, strTipText.GetString());
    pTI->hinst = NULL;
    return pTI->uId;
}