动态重新创建组合框






4.70/5 (23投票s)
一个在运行时重创建下拉框的函数,以便允许新的样式,同时保留其数据
引言
我经常需要做的事情是切换下拉框的排序状态。 这也是我开发动态可切换控件的原因之一(虽然不是主要原因)。 然而,在创建后更改这些样式是下拉框不支持的功能。 此处提供的函数将重创建下拉框,以便样式更改生效。 该函数将保留所有列表项及其项数据,以及当前选定的或输入的文本。
当下拉框的样式被修改以包含或移除CBS_SORT
时,例如,可以通过使用GetStyle()
或使用Spy++之类的工具来观察到控件确实具有新的样式,但控件的行为并未改变。 此处的函数只是从控件获取当前信息,例如样式、字体等,并使用这些值重创建控件。
如何使用
我最初有一个基于CComboBox
的类,其中一个成员函数用于重创建控件,但后来认为这比它值得的麻烦更多,因为我大多数下拉框都派生自其他东西。 因此,我将其呈现为一个单独的函数,该函数应包含在全局库文件中,以便您可以随时在任何下拉框上调用它。
为了更改下拉框的样式,您应该执行通常设置新样式的过程,例如:
combo.ModifyStyle(0, CBS_SORT);
然后在该调用之后,您应该调用
RecreateComboBox(&combo)
该函数接受一个可选的void指针lpParam
,该指针在重创建控件时传递给CreateEx
。 如果您在创建控件时有特殊要求,并且通常会传递一些用于创建参数的数据,那么您应该在此处传递相同的信息。 大多数开发人员可以简单地忽略此参数。
函数
重创建下拉框的函数如下
// recreate the combo box by copying styles etc, and list items // and applying them to a newly created control BOOL RecreateComboBox(CComboBox* pCombo, LPVOID lpParam/*=0*/) { if (pCombo == NULL) return FALSE; if (pCombo->GetSafeHwnd() == NULL) return FALSE; CWnd* pParent = pCombo->GetParent(); if (pParent == NULL) return FALSE; // get current attributes DWORD dwStyle = pCombo->GetStyle(); DWORD dwStyleEx = pCombo->GetExStyle(); CRect rc; pCombo->GetDroppedControlRect(&rc); pParent->ScreenToClient(&rc); // map to client co-ords UINT nID = pCombo->GetDlgCtrlID(); CFont* pFont = pCombo->GetFont(); CWnd* pWndAfter = pCombo->GetNextWindow(GW_HWNDPREV); // get the currently selected text (and whether it is a valid list selection) CString sCurText; int nCurSel = pCombo->GetCurSel(); BOOL bItemSelValid = nCurSel != -1; if (bItemSelValid) pCombo->GetLBText(nCurSel, sCurText); else pCombo->GetWindowText(sCurText); // copy the combo box items into a temp combobox (not sorted) // along with each item's data CComboBox comboNew; if (! comboNew.CreateEx(dwStyleEx, _T("COMBOBOX"), _T(""), dwStyle, rc, pParent, nID, lpParam)) return FALSE; comboNew.SetFont(pFont); int nNumItems = pCombo->GetCount(); for (int n = 0; n < nNumItems; n++) { CString sText; pCombo->GetLBText(n, sText); int nNewIndex = comboNew.AddString(sText); comboNew.SetItemData(nNewIndex, pCombo->GetItemData(n)); } // re-set selected text if (bItemSelValid) comboNew.SetCurSel(comboNew.FindStringExact(-1, sCurText)); else comboNew.SetWindowText(sCurText); // destroy the existing window, then attach the new one pCombo->DestroyWindow(); HWND hwnd = comboNew.Detach(); pCombo->Attach(hwnd); // position correctly in z-order pCombo->SetWindowPos(pWndAfter == NULL ? &CWnd::wndBottom : pWndAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); return TRUE; }
另请参阅
- 动态重创建列表框:一个在运行时重创建列表框的函数,以便允许新的样式,同时保留其数据和选择。
- 动态可切换多用途控件:允许在多种控件类型之间运行时切换的控件,例如下拉框、编辑框等。
历史
- 版本 1 - 2002年7月26日 - 首次版本
- 版本 2 - 2002年7月30日 - 修改以包含Jean-Michel LE FOL和Davide Zaccanti建议的更改