打开后如何滚动组合框下拉列表? [英] How to scroll a combobox dropdown after it opens?

查看:144
本文介绍了打开后如何滚动组合框下拉列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在显示下拉列表后立即操作下拉列表组合框的下拉列表?具体来说,我想让当前选中的项目不在可见范围的顶部,而是在第二行(假设列表包含足够的项目,并显示滚动条)。我希望用户能够立即看到当前所选条目之上的条目。



我尝试了什么:



我玩 CBN_DROPDOWN (但无法获得下拉列表的HWND), CBN_SELCHANGE (最初设置选择时不会触发), WM_CTLCOLOR (在很多情况下被触发),以及 CB_SHOWDROPDOWN (在创建下拉列表之前触发)。

解决方案

我还没有准备好使用解决方案但是常用方法获取列表框的 HWND 。这使用 WM_CTLCOLOR 消息并检查 nCtlColor 是否 CTLCOLOR_LISTBOX

 HBRUSH CMyComboBox :: OnCtlColor(CDC * pDC,CWnd * pWnd,UINT nCtlColor)
{
if(CTLCOLOR_LISTBOX == nCtlColor&& ;!m_hwndLb)
{
//列表框刚刚创建但尚未绘制
m_hwndLb = pWnd-> GetSafeHwnd();
}
返回CComboBox :: OnCtlColor(pDC,pWnd,nCtlColor);
}



你也可以处理 WM_CTLCOLORLISTBOX消息(Windows) [ ^ ]而不是发送给父母(组合框)。



因为它是一个下拉列表框,所以当下拉菜单关闭时你必须清除 m_hwndLb



我还没有关于何时以及从何处发送滚动命令的解决方案(可能是在第一次绘制列表框之后)但希望这有助于作为起点。



应该可以在上面的处理程序中对列表框进行子类化。然后,您可以处理子类列表框类中的任何列表框消息:

 m_dropDownList.SubclassWindow(m_hwndLb); 



其中 m_dropDownList 是一个 CListBox 派生类,为 CMyComboBox 会员。

[/编辑]


谢谢Jochen,我给了你4分中的4分,引导我进入正确的方向。我的最终解决方案是:



覆盖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 ,< span class =code-digit> 0 );
if (nSelIndex> = 1
{
< span class =code-keyword> if (nSelIndex == :: SendMessage(m_hwndListBox,LB_GETTOPINDEX, 0 0 ))
:: SendMessage(m_hwndListBox,LB_SETTOPINDEX,nSelIndex - 1 0 );
}
}
}

返回 __ 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;
}



当下拉菜单关闭时执行。



再次感谢!


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).

解决方案

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]


Thank you Jochen, I gave you 4 of 5 points for leading me into the correct direction. My final solution is this:

Override 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 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:

void CMyComboBox::OnReflectCbnCloseup()
{
    m_hwndListBox = NULL;
}


It is executed when the drop-down closes.

Thanks again!


这篇关于打开后如何滚动组合框下拉列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆