hans.sch Ответов: 2

Как прокрутить выпадающий список combobox после его открытия?


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

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

Я играл с CBN_DROPDOWN (но не смог получить hwnd выпадающего списка), с CBN_SELCHANGE (не срабатывает, когда выбор изначально установлен), с WM_CTLCOLOR (слишком часто увольняется), и CB_SHOWDROPDOWN (запускается до создания раскрывающегося списка).

2 Ответов

Рейтинг:
9

hans.sch

Спасибо, Йохен, я дал тебе 4 из 5 баллов за то, что ты привел меня в правильное русло. Мое окончательное решение таково:

Переопределить OnCtrlColor

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 является членом CMyComboBox и инициализируется значением NULL. Код внутри if (m_hwndListBox == NULL) прокрутите список вниз на одну строку, если текущий выбор - это элемент, отображаемый в верхней строке раскрывающегося списка, но не первый элемент в списке. Именно такой эффект я и хотел создать.

Реагируйте на уведомление CBN_CLOSEUP
В карте сообщений CMyComboBox я добавил эту запись:
ON_CONTROL_REFLECT(CBN_CLOSEUP, &OnReflectCbnCloseup)

Соответствующий обработчик короткий:
void CMyComboBox::OnReflectCbnCloseup()
{
    m_hwndListBox = NULL;
}

Он выполняется, когда раскрывающийся список закрывается.

Еще раз спасибо!


Рейтинг:
12

Jochen Arndt

У меня нет готового к использованию решения, но есть общий метод получения HWND из списка. При этом используется WM_CTLCOLOR сообщение и проверяет, если nCtlColor является 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);
}

Вы также можете справиться с Сообщение WM_CTLCOLORLISTBOX (Windows)[^] вместо этого, который отправляется родителю (поле со списком).

Поскольку это выпадающий список, вы должны очистить его m_hwndLb когда выпадающий список будет закрыт.

У меня также пока нет решения о том, когда и откуда отправить команду прокрутки (вероятно, после того, как список был нарисован в первый раз), но я надеюсь, что это поможет в качестве отправной точки.
[РЕДАКТИРОВАТЬ]
Должно быть возможно подклассировать список в приведенном выше обработчике. Затем вы можете обработать любое сообщение списка из своего подкласса класса списка:
m_dropDownList.SubclassWindow(m_hwndLb);

где m_dropDownList это CListBox производный класс как CMyComboBox член.
[/РЕДАКТИРОВАТЬ]