Click here to Skip to main content
15,890,512 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
How can I manipulate the drop-down of a "drop list" combo box immediately after the drop-down is displayed? Specifically, I want to make the currently selected item appear not on the top of the visible range, but in the second line (assuming the list contains enough items, and a scroll bar is displayed). I want to user to be able to immediately see the entry above the currently selected one.

What I have tried:

I played with CBN_DROPDOWN (but couldn't get the drop-down's HWND), with CBN_SELCHANGE (isn't fired when the selection is initially set), with WM_CTLCOLOR (is fired on too many occasions), and CB_SHOWDROPDOWN (is fired before the drop-down is created).
Posted
Updated 16-Feb-17 23:42pm
v2

I have no ready to use solution but a common method to get the HWND of the list box. This uses the WM_CTLCOLOR message and checks if nCtlColor is CTLCOLOR_LISTBOX:
HBRUSH CMyComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    if (CTLCOLOR_LISTBOX == nCtlColor && !m_hwndLb)
    {
        // List box has just been created but has not been drawn yet
        m_hwndLb = pWnd->GetSafeHwnd();
    }
    return CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
}

You may also handle the WM_CTLCOLORLISTBOX message (Windows)[^] instead which is send to the parent (the combo box).

Because it is a drop down list box, you must clear m_hwndLb when the drop down is closed.

I also have no solution yet on when and from where to send the scroll command (probably after the list box has been drawn the first time) but hope that this helps as a starting point.
[EDIT]
It should be possible to subclass the list box in the above handler. Then you can handle any list box message from within your subclassed list box class:
m_dropDownList.SubclassWindow(m_hwndLb);

where m_dropDownList is a CListBox derived class as CMyComboBox member.
[/EDIT]
 
Share this answer
 
v2
Thank you Jochen, I gave you 4 of 5 points for leading me into the correct direction. My final solution is this:

Override OnCtrlColor
C++
HBRUSH CMyComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    if (nCtlColor == CTLCOLOR_LISTBOX)
    {
        if (m_hwndListBox == NULL)
        {
            m_hwndListBox = pWnd->GetSafeHwnd();
            CListBox *pLb = (CListBox*)CWnd::FromHandle(m_hwndListBox);

            int nSelIndex = ::SendMessage(m_hwndListBox, LB_GETCURSEL, 0, 0);
            if (nSelIndex >= 1)
            {
                if (nSelIndex == ::SendMessage(m_hwndListBox, LB_GETTOPINDEX, 0, 0))
                    ::SendMessage(m_hwndListBox, LB_SETTOPINDEX, nSelIndex - 1, 0);
            }
        }
    }

    return __super::OnCtlColor(pDC, pWnd, nCtlColor);
}

m_hwndListBox is a member of CMyComboBox and is initialized to NULL. The code inside the if (m_hwndListBox == NULL) scrolls the list box down one line if the current selection is the item displayed on the top row of the drop-down but not the first item in the list. This is the effect I wanted to create.

React to the CBN_CLOSEUP notification
In the message map of CMyComboBox, I added this entry:
ON_CONTROL_REFLECT(CBN_CLOSEUP, &OnReflectCbnCloseup)

The respective handler is short:
C++
void CMyComboBox::OnReflectCbnCloseup()
{
    m_hwndListBox = NULL;
}

It is executed when the drop-down closes.

Thanks again!
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900