65.9K
CodeProject 正在变化。 阅读更多。
Home

动态重新创建组合框

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (23投票s)

2002 年 7 月 26 日

CPOL

2分钟阅读

viewsIcon

156931

一个在运行时重创建下拉框的函数,以便允许新的样式,同时保留其数据

引言

我经常需要做的事情是切换下拉框的排序状态。 这也是我开发动态可切换控件的原因之一(虽然不是主要原因)。 然而,在创建后更改这些样式是下拉框不支持的功能。 此处提供的函数将重创建下拉框,以便样式更改生效。 该函数将保留所有列表项及其项数据,以及当前选定的或输入的文本。

当下拉框的样式被修改以包含或移除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建议的更改
© . All rights reserved.