Определение максимальной ширины раскрывающегося списка для CComboBoxEx с иконками

Я видел эту статью в CodeProject для динамической установки ширины CComboBox.

Однако я использую CComboBoxEx:

Раскрывающийся список

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

Необходимо учитывать тот факт, что слева также есть место для значка. Так что этого будет недостаточно:

BOOL CMyComboBox::OnCbnDropdown()
{ 
    // Reset the dropped width
    CString str;
    CRect rect;
    int nWidth  = 0;
    int nNumEntries = GetCount();;

    CClientDC dc(this);

    int nSave = dc.SaveDC();
    dc.SelectObject(GetFont());

    for (int i = 0; i < nNumEntries; i++)
    {
        GetLBText(i, str); 
        int nLength = dc.GetTextExtent(str).cx;
        if (nLength>nWidth)
            nWidth = nLength;
    }

    nWidth += 2*::GetSystemMetrics(SM_CXEDGE) + 4;

    // check if the current height is large enough for the items in the list
    GetDroppedControlRect(&rect);
    if (rect.Height() <= nNumEntries*GetItemHeight(0))
        nWidth +=::GetSystemMetrics(SM_CXVSCROLL);


    dc.RestoreDC(nSave);
    SetDroppedWidth(nWidth);

    return FALSE;
}

Как мы учитываем значок слева?

Раскрывающийся список со значком


person Andrew Truckle    schedule 10.12.2018    source источник
comment
Вы также должны учитывать COMBOBOXEXITEM::iIndentдокументы. microsoft.com/en-us/windows/desktop/api/commctrl/ — количество отступов, отображаемых для элемента. Каждый отступ равен 10 пикселям.   -  person sergiol    schedule 14.12.2018
comment
@sergiol Это разовый расчет? Я просмотрел ссылку, но я не уверен, как настроить мой окончательный код. Использовать ли вместо этого GetItem для получения отступа и текста? Возможно, вы можете обновить мой ответ добавлением?   -  person Andrew Truckle    schedule 15.12.2018
comment
Я хотел знать то же самое для той же цели: stackoverflow.com/questions/52428007/ . Но iIndent представляет интервал в ЛЕВО значка. Это полезно для иерархической организации элементов в раскрывающемся списке.   -  person sergiol    schedule 15.12.2018
comment
@sergiol Смотрите мой обновленный ответ.   -  person Andrew Truckle    schedule 15.12.2018


Ответы (1)


Это работает:

void CDatesComboBoxEx::OnCbnDropdown()
{
    CString str;
    CRect rect;
    int nWidth = 0, nImageWidth = 0;
    int nNumEntries = GetCount();

    if (nNumEntries > 0)
    {
        // Get the width of an image list entry
        auto pImageList = GetImageList();
        if (pImageList != nullptr && pImageList->GetImageCount() > 0)
        {
            IMAGEINFO sInfo;
            pImageList->GetImageInfo(0, &sInfo);
            nImageWidth = sInfo.rcImage.right - sInfo.rcImage.left;
        }

        CClientDC dc(this);

        int nSave = dc.SaveDC();
        dc.SelectObject(GetFont());

        for (int i = 0; i < nNumEntries; i++)
        {
            COMBOBOXEXITEM sItem;
            TCHAR szBuffer[_MAX_PATH] = _T("");
            sItem.mask = CBEIF_INDENT | CBEIF_TEXT;
            sItem.iItem = i;
            sItem.cchTextMax = _MAX_PATH;
            sItem.pszText = szBuffer;

            if (GetItem(&sItem))
            {
                int nLength = dc.GetTextExtent(szBuffer).cx + nImageWidth + (sItem.iIndent * 10);
                if (nLength > nWidth)
                    nWidth = nLength;
            }
        }

        nWidth += 2 * ::GetSystemMetrics(SM_CXEDGE) + 4;

        // check if the current height is large enough for the items in the list
        GetDroppedControlRect(&rect);
        if (rect.Height() <= nNumEntries * GetItemHeight(0))
            nWidth += ::GetSystemMetrics(SM_CXVSCROLL);

        dc.RestoreDC(nSave);
        SetDroppedWidth(nWidth);
    }
}

Результат:

Раскрывающийся список

person Andrew Truckle    schedule 10.12.2018