AdvComboBox - 版本 2.1






4.97/5 (45投票s)
用户可以调整下拉窗口大小的组合框。可以是标准样式或平面样式。
最新消息!
本文的源代码和相关 bug 现在可以在 Google Code 找到:http://code.google.com/p/advcombobox/。
我把它放在那里,这样每个人都可以报告 bug 并帮助我开发这个控件。我自己没有时间修复所有问题,所以如果你想帮忙,请发送邮件至 mathias.tunared@gmail.com,我将把你添加到项目中。我将继续在这里的 CodeProject.com 更新此页面,以发布每个新版本。这个控件已经存在很久了,仍然被使用,所以我认为是时候进行更新了。
AdvComboBox 文章索引
引言安装
函数
Notifications
样式
未来升级
技巧与提示
改进和 bug 修复
2.1 版本有什么新内容
我真的很厌倦不得不在 InitDialog 函数中添加所有项目,这在同一页面上有多个 CAdvComboBox
时会非常烦人。现在,此类将在字符串表中查找与 CAdvComboBox
控件在资源编辑器中的 ID 相同的条目。演示项目已升级以显示此功能。更多信息已在 安装 部分添加。如果要添加另一个字符串表条目,只需调用新函数 LoadString(UINT nID)
,其中 nID 指的是字符串表条目。
在此版本中,我添加了代码,以便 CAdvComboBox
可以与宏 RUNTIME_CLASS
一起使用。由 Krishna 请求。
我还添加了缺失的功能,可以通过按 Alt-Down 或 Alt-Up 来打开下拉窗口。这是 Thomas Freudenberg 请求的。
引言
我开始开发一个控件,我将在另一个带有 CListBox
中组合框的程序中使用。我想要的第一项标准是组合框应该是平坦的(没有阴影)。我找了一段时间,找不到合适的,所以只好自己创建一个。当我开始处理平面组合框时,我想到了另一个很酷的功能,会很好用。你曾多少次想要 IE 地址栏的相同功能。当你输入地址,IAutoComplete
COM 对象就开始工作。太棒了!……或者不是。我想要我的组合框具有相同的功能,特别是可调整大小的下拉窗口。所以,回到绘图板。经过许多漫长的夜晚和几种不同的方法,我成功了。
此 ComboBox
并没有继承 MFC 的 CComboBox
,主要是因为我想能够调整下拉窗口的大小。相反,我创建了一个看起来与 MFC 的 CComboBox
几乎相同的 CWnd
对象。棘手的部分是让下拉窗口的反应与 CComboBox
相同。首先,下拉窗口必须是桌面的一个子窗口,然后是鼠标和键盘捕获的棘手问题。那个问题的解决方案是有一个窗口,其中包含一个列表框和一个滚动条。CListBox
类使用的滚动条不能使用,因为存在捕获问题。
在开发过程中添加了更多功能;下拉窗口中的已选中项目和已禁用项目。
下面是类结构的图示。
Picture 1
AdvComboBox
的下拉窗口是自动调整大小的样式,即它会计算显示列表中所有项目所需的大小。
因此,结果是一个组合框,其行为与 MFC 的 CComboBox
几乎相同。除了将资源从标准组合框更改为自定义控件外,您不应更改任何已在使用中的代码。我在 W2K 和 XP 上进行了测试。现在我转向 CodeProject 的会员和其他人来帮助我测试和查找 bug,也许还能添加一些新功能。
安装
安装索引
创建一个新项目
升级您的当前项目
在 MFC DLL 中使用 CAdvComboBox
本文包含三种将 CAdvComboBox
类实现到您的项目中的方法。一种描述了新项目的操作流程,第二种描述了如何升级您当前的项目,最后一种描述了如何在 MFC DLL 中实现 CAdvComboBox
。
创建一个新项目
- 使用 App Wizard 创建一个对话框应用程序。
下面的解释都基于您将应用程序命名为 AdvCBDemo - 将以下文件插入到您的工作区
AdvComboBox.h
AdvComboBox.cpp
DropWnd.h
DropWnd.cpp
DropListBox.h
DropListBox.cpp
DropScrollBar.h
DropScrollBar.cpp
VisualStylesXP.h
VisualStylesXP.h - 在您的 AdvCBDemoDlg.h 文件中包含 AdvComboBox.h 文件
- 在对话框中添加一个自定义控件
在资源编辑器中,使用工具栏中的自定义控件工具在对话框中放置一个新的自定义控件。输入控件的属性,如下图所示。CAdvComboBox
自定义控件类名是AdvComboBoxCtrl
,它在 AdvComboBox.h 中定义。
设置不同样式的说明
Picture 2
组合框样式 属性窗口中的值 CBS_DROPDOWN 0x_____002 CBS_DROPDOWNLIST 0x_____103 CBS_AUTOHSCROLL 0x_____043 CBS_SORT 0x_____103
这意味着,如果您希望您的组合框具有CBS_DROPDOWN
、CBS_AUTOHSCROLL
和CBS_SORT
样式,则样式值应以 142 结尾(如图 2 所示)。您也可以在文本模式下编辑资源文件并在此处添加样式。资源编辑器随后会将您选择的样式转换为此值。以下样式尚未实现
CBS_DISABLENOSCROLL
CBS_HASSTRINGS
CBS_LOWERCASE
CBS_NOINTEGRALHEIGHT
CBS_OEMCONVERT
CBS_OWNERDRAWFIXED
CBS_OWNERDRAWVARIABLE
CBS_SIMPLE
CBS_UPPERCASE - 在 AdvCBDemoDlg.h 头文件中,将以下公共成员变量添加到您的 CAdvCBDemoDlg 类中
CAdvComboBox m_ctlAdvCombo;
- 在 AdvCBDemoDlg.cpp 文件中添加以下 DXX_ 调用
DDX_Control(pDX, IDC_ADV_COMBO, m_ctlAdvCombo);
将其添加到AFX_DATA_MAP
外部,以避免将来出现任何问题。
现在,DoDataExchange(...)
函数应如下所示void CAdvCBDemoDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAdvCBDemoDlg) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP DDX_Control(pDX, IDC_ADV_COMBO, m_ctlAdvCombo); }
- 编译并运行
现在您应该可以测试包含 AdvComboBox 的对话框了。还有一项尚未实现的功能是如何从控件获取和设置数据。这将在下面描述。
- 从 AdvComboBox 设置和获取数据
您可以像使用普通 CComboBox 一样使用相同的方式来获取和设置数据,除了一个小的区别。DDX_CBIndex
和DDX_CBString
应更改为DDX_ACBIndex
和DDX_ACBString
才能工作。这些函数可以在 AdvComboBox.cpp 文件中找到。要添加获取和设置数据的功能,请在您的 AdvCBDemoDlg.h 文件中添加以下一个或两个变量
int m_nAdvCombo; CString m_strAdvCombo;
您还必须在CAdvCBDemoDlg
的构造函数中初始化这些变量的值。将以下代码添加到AFX_DATA_INIT
外部。m_nAdvCombo = -1; m_strAdvCombo = "";
还将 DDX_ 调用添加到 AdvCBDemoDlg.cpp 文件中的DoDataExchange(...)
函数中,位于您在步骤 6 中添加的DDX_Control
之下。DDX_ACBIndex( pDX, IDC_ADV_COMBO, m_nAdvCombo ); DDX_ACBString( pDX, IDC_ADV_COMBO, m_strAdvCombo );
现在您应该可以像使用 MFC 的 CComboBox 一样使用 AdvComboBox 控件了。
以下内容已添加到 2.1 版本中
- 使用字符串表条目填充
CAdvComboBox
列表。
要将字符串表与此组合框一起使用,必须创建一个与控件在资源编辑器中的标识符相同的字符串表条目。在这种情况下,字符串表条目 ID 应为 IDC_ADV_COMBO。下面是您可以添加到项目中的此示例的图片(图 3)。
在字符串表条目中,换行符 ('\n'
) 代表组合框列表中一个项目的结束。请参阅演示项目以获取有关如何实现的更多信息。
图 3
升级您的当前项目
此描述不如上面的详细。希望您有足够的知识来管理以下内容。- 将以下文件插入到您的工作区
AdvComboBox.h
AdvComboBox.cpp
DropWnd.h
DropWnd.cpp
DropListBox.h
DropListBox.cpp
DropScrollBar.h
DropScrollBar.cpp
VisualStylesXP.h
VisualStylesXP.h - 在您的头文件中包含 AdvComboBox.h 文件
- 更改类名
在您的头文件中,将所有CComboBox
变量定义重命名为CAdvComboBox
。 - 替换资源组合框
在资源编辑器中,将您当前的组合框替换为自定义控件,并设置属性,如下图 2 所示。当然,您可以更改自定义控件的样式。提示! 对您的自定义控件使用与组合框相同的 ID。这使得以后更容易,您不必更改所有事件(
ON_CBN_SELCHANGE
等)的 ID,这些 ID 已正确分配给标准组合框。 - 更改 DDX_ 调用
在您的 .cpp 文件中,将所有DDX_CBIndex
和DDX_CBString
更改为DDX_ACBIndex
和DDX_ACBString
。如果您没有为您新的自定义控件设置与旧组合框相同的 ID,请更改这些调用中的 ID。 - 编译并测试
您的项目现在应该可以工作了,除了CAdvComboBox
的限制。
在 MFC DLL 中使用 CAdvComboBox
这只是一个关于如何在具有窗口(对话框)的 DLL 中使用此类以及这些窗口使用CAdvComboBox
的简要描述。要注册该类,您需要更改一些代码。WNDCLASS
结构中的 HINSTANCE
必须是 DLL 的 HINSTANCE
,而不是调用应用程序的 HINSTANCE
。- 声明一个 CAdvComboBox 变量
像这样创建类CAdvComboBox m_ctlAdvCombo( TRUE )
- 全局 HINSTANCE 变量
您还必须为 DLL 项目添加一个全局HINSTANCE
变量。
将以下内容添加到 DLL 项目的 StdAfx.cpp 中,例如HINSTANCE g_hDLLInstance = NULL;
然后,像这样在 StdAfx.h 文件中添加extern
定义extern HINSTANCE g_hDLLInstance;
- 初始化全局 HINSTANCE
在 DllMain 函数中设置hDllInstance
。g_hDLLInstance = hInstance;
- 更改 CAdvComboBox 中的代码
接下来是找到 AdvComboBox.cpp 文件中的RegisterWindowClass()
函数。将函数修改如下BOOL CAdvComboBox::RegisterWindowClass() { WNDCLASS wndcls; HINSTANCE hInst; if( m_bInst ) { hInst = g_hDLLInstance; } else { hInst = AfxGetInstanceHandle(); } ASSERT( hInst != 0 ); ... return TRUE; }
- 导出 CAdvComboBox 类
最后但同样重要的是,如果您想在 DLL 外部使用该类,则必须将其导出。请记住也要导出两个 DDX_ 函数。类定义class __declspec(dllexport) CAdvComboBox : public CWnd
DDX_ 定义_declspec(dllexport) void AFXAPI DDX_ACBIndex( CDataExchange* pDX, int nIDC, int& index ); _declspec(dllexport) void AFXAPI DDX_ACBString( CDataExchange* pDX, int nIDC, CString& value );
AdvComboBox 函数
CAdvComboBox
类中的函数与 MFC 的 CComboBox
中的函数相同。有关更多帮助,请查看 MSDN。还有一些额外的函数可以使用。下面将进行描述
- GetComboRect
描述 使用此函数检索组合框的位置和大小 定义 CRect& GetComboRect()
Returns AdvComboBox 的矩形 - GetDefaultVisibleItems 2.0 版本新增
描述 返回下拉窗口的默认可见项目数。要设置默认数量,请使用 SetDefaultVisibleItems(int)
定义 int GetDefaultVisibleItems()
Returns 项目数。 - GetItemChecked
描述 获取项目的选中状态 定义 BOOL GetItemChecked( int nIndex )
参数 nIndex
列表中项目的索引Returns 如果项目 nIndex
已选中,则返回 TRUE,如果发生错误,则返回CB_ERR
。 - GetItemDisabled
描述 获取项目的禁用状态 定义 BOOL GetItemDisabled( int nIndex )
参数 nIndex
列表中项目的索引Returns 如果项目 nIndex
已禁用,则返回 TRUE,如果发生错误,则返回CB_ERR
。 - GetMinVisibleItems 1.2 版本新增
描述 获取下拉窗口中的最小可见列表框项目数,然后下拉窗口将放置在组合框上方。 定义 int GetMinVisibleItems()
Returns 最小可见列表框项目的数量。 - LoadString 2.1 版本新增
描述 从字符串表中加载一个条目,并将该条目中的项目添加到下拉窗口列表中。 定义 void LoadString( UINT nStringID )
参数 nStringID
要加载的字符串的 ID。Returns void - ModifyACBStyle
描述 修改 CAdvComboBox 的样式。可用样式可以在这里找到。此函数仅处理 ACBS_ 样式。它的工作方式与 MFC 的 ModifyStyle
相同。定义 void ModifyACBStyle(UINT nRemoveStyle, UINT nAddStyle)
参数 nRemoveStyle
ACBS 样式要移除。参数 nAddStyle
ACBS 样式要添加。Returns void
- PointInWindow
描述 CPoint 是否在组合框矩形内? 定义 BOOL PointInWindow( CPoint ptScreenPoint )
参数 ptScreenPoint
这个点是否在组合框内。Returns 如果点在组合框窗口内,则返回 TRUE。 - SetDefaultVisibleItems 2.0 版本新增
描述 设置下拉窗口中默认可见的项目数。 定义 void SetDefaultVisibleItems( int nItems = -1 );
参数 nItems
显示下拉窗口时要可见的项目数。如果样式应为自动大小,请将其设置为 -1。Returns void
- SetItemChecked
描述 将组合框中的项目设置为选中或取消选中。 定义 void SetItemChecked( int nIndex, BOOL bChecked )
参数 nIndex
要设置的项目的零基索引。参数 bChecked
要设置的项目的最新状态。Returns void
- SetItemDisabled
描述 将组合框中的项目设置为禁用或启用。 定义 void SetItemDisabled(int nIndex, BOOL bDisabled)
参数 nIndex
要设置的项目的零基索引。参数 bDisabled
要设置的项目的最新状态。Returns void
- SetMinVisibleItems 1.2 版本新增
描述 设置下拉窗口中的最小可见列表框项目数,然后下拉窗口将放置在组合框上方。默认值为五个项目。 定义 void SetMinVisibleItems(int nMinItems)
参数 nMinItems
最小列表框项目的数量。Returns void
- DDX_ACBIndex
描述 使用此函数通过 MFC 的 UpdateData(...)
获取和设置数据定义 void AFXAPI DDX_ACBIndex( CDataExchange* pDX, int nIDC, int& index )
- DDX_ACBString
描述 使用此函数通过 MFC 的 UpdateData(...)
获取和设置数据定义 void AFXAPI DDX_ACBString( CDataExchange* pDX, int nIDC, CString& value )
下面是 CAdvComboBox
中实现的 CComboBox
函数列表。
AddString
DeleteString
FindString
FindStringExact
GetCount
GetCurSel
GetDroppedControlRect
GetDroppedState
GetEditSel
GetItemData
GetItemDataPtr
GetLBText
GetLBTextLen
GetTopIndex
InsertString
LimitText
1.2 版本新增ResetContent
SelectString
SetCurSel
SetEditSel
SetItemData
SetItemDataPtr
SetTopIndex
ShowDropDown
以下 CComboBox
函数在 CAdvComboBox
中未实现
Clear
CompareItem
复制
剪切
Dir
DrawItem
DeleteItem
GetDroppedWidth
GetExtendedUI
GetHorizontalExtent
GetItemHeight
GetLocale
MeasureItem
粘贴
SetDroppedWidth
SetExtendedUI
SetHorizontalExtent
SetItemHeight
SetLocale
AdvComboBox 通知
CAdvComboBox
向父窗口发送以下通知,就像 MFC 的 CComboBox
一样。CBN_CLOSEUP
CBN_DROPDOWN
CBN_EDITCHANGE
CBN_EDITUPDATE
CBN_KILLFOCUS
CBN_SELCHANGE
CBN_SELENDCANCEL
CBN_SELENDOK
CBN_SETFOCUS
以下通知未发送。
CBN_DBLCLK
此消息仅在组合框样式为CBS_SIMPLE
时发送,而CAdvComboBox
不支持此样式。CBN_ERRSPACE
此控件尚未内置内存管理,我也不确定是否会这样做。太无聊了!
AdvComboBox 样式
CAdvComboBox
具有自己的样式。此处将进行描述。ACBS_FLAT
使组合框变平。使用此样式,组合框将在资源中的自定义控件矩形的边界处绘制。ACBS_STANDARD
使用此样式,组合框将像普通的组合框一样绘制,即 3D 外观。ACBS_CHECKED
要使下拉窗口包含一个可勾选列表,请使用此样式。ACBS_AUTOAPPEND
AdvComboBox 将自动在下拉窗口项目中搜索与 AdvComboBox 的编辑框中输入的文本最匹配的项目。如果找到,它将把剩余的文本附加到编辑框中。ACBS_AUTOSUGGEST
在编辑框中输入文本时,AdvComboBox 将在下拉窗口中显示一个与输入文本匹配的列表。
CAdvComboBox
支持以下 CComboBox
样式
CBS_AUTOHSCROLL
CBS_DROPDOWN
CBS_DROPDOWNLIST
CBS_SORT
以下 CComboBox
样式不受支持
CBS_DISABLENOSCROLL
CBS_HASSTRINGS
CBS_LOWERCASE
CBS_NOINTEGRALHEIGHT
CBS_OEMCONVERT
CBS_OWNERDRAWFIXED
CBS_OWNERDRAWVARIABLE
CBS_SIMPLE
CBS_UPPERCASE
未来升级
- .NET 兼容
技巧与提示
- 使用 ClassWizard
使用 MFC 的CComboBox
创建您的项目,这样 ClassWizard 就可以帮助您实现通知,例如ON_CBN_SELCHANGE
。当您创建了组合框的所有事件后,切换到CAdvComboBox
。这是实现此类的最简单快捷的方法。 - 将样式设置为平面
在OnInitDialog()
中添加对ModifyACBStyle(...)
的调用,如下所示
m_ctlAdvCombo.ModifyACBStyle( 0, ACBS_FLAT );
- Windows 主题兼容
AdvComboBox 与主题兼容,在我测试的范围内。如果您发现任何颜色或其他方面有问题,请告诉我。在告诉我之前,请再与CComboBox
进行比较。
改进和 bug 修复
版本 2.1
- ID 相同的字符串表条目将填充列表。
- 已添加函数
LoadString(UINT)
- 宏
RUNTIME_CLASS
现在可以使用了。
在此版本中,我已将代码添加到CAdvComboBox
可以与宏RUNTIME_CLASS
一起使用。由 Krishna 请求。 - 按 Alt+Up/Down 可以打开下拉窗口。
添加了通过按 Alt-Down 或 Alt-Up 打开下拉窗口的缺失功能。这是 Thomas Freudenberg 的一个请求。
版本 2.0
- 已添加函数
GetDefaultVisibleItems()
- 已添加函数
SetDefaultVisibleItems(int)
- 已添加
CAdvComboBox
样式ACBS_AUTOAPPEND
- 已添加
CAdvComboBox
样式ACBS_AUTOSUGGEST
CAdvComboBox
现在也与 CommCtrl 6.0 manifest 兼容。
我使用了 David Yuheng Zhao 的CVisualStylesXP
类作为基础,但我添加了一些功能,例如从 DLL 获取的函数现在是静态函数,以及一个检查 CommCtrl DLL 版本以查看我们是否能够使用视觉样式的函数。如果未使用 manifest,即使在 WinXP 上运行,此函数也会告知您。- 添加了两个新文件:VisualStylesXP.h 和 VisualStylesXP.cpp
版本 1.21
- 修复了使用 Create(...) 时的 bug
尝试使用Create(...)
函数创建CAdvCombBox
类并且样式为CBS_DROPDOWN
时会出现 bug。感谢您找到这个 bug。
版本 1.2
- 实现了使用鼠标滚轮滚动下拉窗口。
CComboBox
函数LimitText
现在已实现。- 已移除对 Windows 定义
_WIN32_WINNT
的需求。 - 下拉窗口在控件上方
如果到屏幕底部的距离不够,下拉窗口将显示在组合框上方。默认的最小列表框项目数为五个,但可以通过调用CAdvComboBox
类中的SetMinVisibleItems(int)
函数来更改此值。
版本 1.1
- 现在可以禁用该控件。
- 当下拉窗口打开时切换到另一个程序会关闭下拉窗口。
- 修正了 Win2K 下的一个小绘图错误。