在Combobox中选择项目时显示格式化文本

时间:2017-09-14 08:53:39

标签: c++ mfc

我有一个组合框,我想在Combo中选择一个项目时显示不同的字符串。

我的组合框是一个下拉组合框。

例如:我的组合框中有以下内容。

亚历克斯 - 经理

雨 - 项目负责人

Shiney - 工程师

Meera - 高级工程师

On在Combobox中选择一个项目我想只是名字,即Alex。

我试过下面的代码

struct details{
    CString name;
    CString des;
};

BOOL CComboTestDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    details d1;
    d1.name = _T("alex");
    d1.des =_T("manager");
    m_vec.push_back(d1);

    details d2;
    d2.name = _T("Rain");
    d2.des =_T("Engineer");
    m_vec.push_back(d2);


    // TODO: Add extra initialization here
    for(int i=0;i<m_vec.size();i++)
    {
        m_ctrlCombo.AddString(m_vec[i].name+m_vec[i].des);
        m_ctrlCombo.SetItemData(i,(DWORD_PTR)&m_vec[i]);
    }
    m_ctrlCombo.SelectString(-1,m_vec[0].name);
    m_ctrlCombo.SetWindowText(m_vec[0].name);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CComboTestDlg::OnCbnSelchangeCombo1()
{
    int nItem = m_ctrlCombo.GetCurSel();
    details* det = (details*)m_ctrlCombo.GetItemData(nItem);
    PostMessage(SETCOMBOTEXT,IDC_COMBO1,(LPARAM)(LPCTSTR)det->name);
}

BOOL CComboTestDlg::PreTranslateMessage(MSG* pMsg) 
{
    MSG msg1=*pMsg;//I am loosing the value after  checking ..so storing temp.
    MSG msg;
    CopyMemory(&msg, pMsg, sizeof(MSG));
    HWND hWndParent = ::GetParent(msg.hwnd);
    while (hWndParent && hWndParent != this->m_hWnd)
    {
        msg.hwnd = hWndParent;
        hWndParent = ::GetParent(hWndParent);
    }

    if (pMsg->message==SETCOMBOTEXT && (pMsg->wParam == IDC_COMBO1))
        SetDlgItemText(IDC_COMBO1, (LPCTSTR)pMsg->lParam);

    if(pMsg->message==WM_KEYDOWN)
    {
        if(pMsg->wParam==VK_RETURN && msg.hwnd ==m_ctrlCombo.m_hWnd )
        {
           OnCbnSelchangeCombo1();
        }
    } 
    return CDialog::PreTranslateMessage(pMsg);
}

我能够实现我的要求OnComboSelChange()和箭头键事件,但在组合框中使用箭头键后按回车键,它没有在组合框中显示格式化文本。

1 个答案:

答案 0 :(得分:5)

我认为最可靠和易于实施的解决方案是subclass组合框的编辑控制。拦截WM_SETTEXT消息并根据需要更改文本,然后将其转发到链的其余部分(最后是原始窗口proc)。

OnInitDialog()中安装子类proc:

COMBOBOXINFO cbi{ sizeof(cbi) };
if( m_ctrlCombo.GetComboBoxInfo( &cbi ) )
{
    SetWindowSubclass( cbi.hwndItem, ComboEditSubClassProc, 0, 0 );
}

ComboEditSubClassProc()可能如下所示:

LRESULT CALLBACK ComboEditSubClassProc( HWND hWnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
    switch( uMsg )
    {
        case WM_SETTEXT:
        {
            CString text = reinterpret_cast<LPCTSTR>( lParam );
            // Extract the name (everything before "-").
            CString name = text.SpanExcluding( _T("-") );
            name.TrimRight();
            // Forward the modified text to any other sub class procs, aswell
            // as the original window proc at the end of the chain.
            return DefSubclassProc( hWnd, uMsg, 0, reinterpret_cast<LPARAM>( name.GetString() ) );
        }
        case WM_NCDESTROY:
        {
            // We must remove our subclass before the subclassed window gets destroyed.
            // This message is our last chance to do that.
            RemoveWindowSubclass( hWnd, ComboEditSubClassProc, uIdSubclass );
            break;
        }
    }

    return DefSubclassProc( hWnd, uMsg, wParam, lParam );
}

备注:

与处理CBN_SELCHANGE的{​​{3}}相反,如果通过按返回关闭组合框下拉列表或被解除,则当前解决方案也能正常工作。

我认为它通常更可靠,因为我们不必依赖通知的顺序。组合框必须最终调用WM_SETTEXT来更改编辑控件的内容,以便始终接收此消息。

原始解决方案中也没有闪烁,其中文本首先由组合框更改,然后仅在事实之后由我们的代码修改。