mfcccombobox

Working out the maximum drop-down width for a CComboBoxEx with icons


I have seen this article on CodeProject for setting the width of a CComboBox dynamically.

However, I am using a CComboBoxEx:

DropDown

As you can see with the last entry it is cropped. So I would like to automatically widen the drop-down list.

It needs to take into account the fact that their is a space for an icon on the left too. So this won't be good enough:

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;
}

How do we factor in for the icon on the left?

Drop-down with icon


Solution

  • This is working:

    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);
        }
    }
    

    Result:

    Drop-down List