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

动态重新创建列表框

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (18投票s)

2002 年 7 月 26 日

CPOL

2分钟阅读

viewsIcon

131426

一个在运行时重创建列表框的函数,允许使用新的样式,同时保留其数据和选择项。

引言

本文是我的文章动态重创建组合框的配套文章。与组合框类似,我经常需要将列表框在排序或多选状态之间切换。与组合框一样,在创建后更改这些样式是列表框不支持的操作。这里提供的函数将重创建列表框,以便使样式更改生效。该函数将保留所有列表项,包括项数据和当前选定的项。

当列表框的样式被修改以包含或移除例如LBS_SORT时,可以通过使用GetStyle()或使用诸如Spy++之类的工具来观察到控件确实具有了新的样式,但控件的行为并未改变。这里的函数只是从控件获取当前信息,例如样式、字体等,并使用这些值重创建控件。

如何使用

我最初有一个基于CListBox的类,其中包含一个成员函数来重创建控件,但后来认为这比它值得的要麻烦,因为我通常使用从其他基类派生的控件。因此,我将此呈现为一个单独的函数,该函数应包含在全局库文件中,以便您可以随时在任何列表框上调用它。

为了更改列表框的样式,您应该执行通常设置新样式的操作,例如:

list.ModifyStyle(0, LBS_SORT);

然后之后调用您的应该调用

RecreateListBox(&list)

该函数接受一个可选的void指针lpParam,该指针在重创建控件时传递给CreateEx。如果您在创建控件时有特殊要求,并且通常会传递一些用于创建参数的数据,那么您应该在此处传递相同的信息。大多数开发人员可以简单地忽略此参数。

函数

重创建列表框的函数如下

// recreate the list box by copying styles etc, and list items
// and applying them to a newly created control
BOOL RecreateListBox(CListBox* pList, LPVOID lpParam/*=NULL*/)
{
	if (pList == NULL)
		return FALSE;
	if (pList->GetSafeHwnd() == NULL)
		return FALSE;

	CWnd* pParent = pList->GetParent();
	if (pParent == NULL)
		return FALSE;

	// get current attributes
	DWORD dwStyle = pList->GetStyle();
	DWORD dwStyleEx = pList->GetExStyle();
	CRect rc;
	pList->GetWindowRect(&rc);
	pParent->ScreenToClient(&rc);	// map to client co-ords
	UINT nID = pList->GetDlgCtrlID();
	CFont* pFont = pList->GetFont();
	CWnd* pWndAfter = pList->GetNextWindow(GW_HWNDPREV);

	// create the new list box and copy the old list box items 
	// into a new listbox along with each item's data, and selection state
	CListBox listNew;
	if (! listNew.CreateEx(dwStyleEx, _T("LISTBOX"), _T(""), dwStyle, 
                                rc, pParent, nID, lpParam))
	  return FALSE;
	listNew.SetFont(pFont);
	int nNumItems = pList->GetCount();
	BOOL bMultiSel = (dwStyle & LBS_MULTIPLESEL || dwStyle & LBS_EXTENDEDSEL);
	for (int n = 0; n < nNumItems; n++)
	{
		CString sText;
		pList->GetText(n, sText);
		int nNewIndex = listNew.AddString(sText);
		listNew.SetItemData(nNewIndex, pList->GetItemData(n));
		if (bMultiSel && pList->GetSel(n))
			listNew.SetSel(nNewIndex);
	}
	if (! bMultiSel)
	{
		int nCurSel = pList->GetCurSel();
		if (nCurSel != -1)
		{
			CString sSelText;
			// get the selection in the old list
			pList->GetText(nCurSel, sSelText);
			// now find and select it in the new list
			listNew.SetCurSel(listNew.FindStringExact(-1, sSelText));
		}
	}
	// destroy the existing window, then attach the new one
	pList->DestroyWindow();
	HWND hwnd = listNew.Detach();
	pList->Attach(hwnd);

	// position correctly in z-order
	pList->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.