高级校验器控件
一个高性能的类似“磁盘优化程序”的状态显示类
![]() |
图1:使用普通对话框模板的示例 |
引言
在开发一个电信服务器监控应用程序期间,我遇到了需要显示大量线路和资源状态的需求。一种能让用户了解整体状态,同时又可以获取更详细状态信息的有趣方法是,使用一个通过彩色小方块来显示状态的控件。一些磁盘优化程序也使用这种技术,以便向用户显示操作的进度和状态。
在评估了一些格子控件之后,我决定开发自己的版本,因为我有一系列在评估过的实现中未能满足的需求。这些需求是:
- 动态调整大小能力
- 动态滚动条
- 静态和动态工具提示
- 实时工具提示更新
- 支持 Unicode
- 低内存占用
- 低内存碎片
- 对系统性能影响小
最终的成果是 CCheckersCtrl
,一个派生自 CWnd
的类,既可以用作对话框、属性页和表单视图中的控件,也可以用作子窗口。
![]() |
图2:带滚动条的控件 |
用法
如果您在对话框模板中使用格子控件,只需向对话框模板添加一个用户绘制按钮,并在类向导中将其与一个控件变量关联。您应该为该按钮激活以下样式:Visible、Tab Stop、Owner Draw、Client Edge
。在类向导中,为该按钮分配一个控件变量。之后,您应该在对话框类中将该控件变量的类型从 CButton
更改为 CCheckersCtrl
。这样就可以了。现在您可以开始使用它了。
在开始之前,让我解释一些基本概念:每个方块都被当作一个 项(Item) 来处理,就像 CListView
中的项一样。每个项通过一个从0(零)开始的索引号来标识,并保存三种信息:
- 项状态。这是一个
BYTE
。状态以颜色显示。 - 一个可选的
DWORD
类型的项数据。 - 一个可选的工具提示文本,可以为项静态设置,也可以在需要显示时通过一个可重写的方法动态获取。
该控件存储一些关于项可视化的全局信息:
- 方块的最大和最小尺寸
- 一个用于表示每种可能状态的颜色数组
为了使用该控件,您不必指定所有这些东西,因为控件已经用合理的默认值进行了初始化:项的大小被设置为6到24像素的范围,颜色数组包含16种标准的Windows颜色。顺便说一下:如果您为一个项设置的状态值大于颜色数组中的最大元素索引,控件不会崩溃:颜色将通过以下公式确定:
COLORREF crUsedColor = m_crColorArray[bItemState % m_iNumColors];
如果您不希望方块自动调整大小,只需将项大小范围的最小值和最大值设置为相同的值即可。
在 CCheckersCtrl
的生命周期内,您可以按任意顺序重新配置、调整大小、添加项、删除项、设置值和属性。该控件能够处理所有这些操作。此版本的唯一限制是该控件不是线程安全的,所以请 不要 从多个线程中使用它。在将来的版本中,我将使其线程安全。
参考
这些方法的风格类似于标准的面向项的 MFC 控件,如 CListView
,因此应该没有太多需要解释的地方。
BOOL CCheckersCtrl::SetSizeLimits (int iMinSize, int iMaxSize, BOOL bRedraw = TRUE);
使用此函数可以定义方块可以自动调整大小的范围。如果您不希望方块自动调整大小,请为 iMinSize
和 iMaxSize
指定相同的值。
int CCheckersCtrl::GetMinSize () const; int CCheckersCtrl::GetMaxSize () const; BOOL CCheckersCtrl::IsAutoResize () const;
使用这些函数可以检索方块的大小范围。
int CCheckersCtrl::GetItemCount () const;
检索格子控件中的项数。
BOOL CCheckersCtrl::SetItemCount ( int iCheckers, BYTE bInitialState = 0, DWORD dwData = 0, LPCTSTR pszTip = LPSTR_TEXTCALLBACK, BOOL bRedraw = TRUE );
设置格子控件中的项数。如果项数大于现有项数,将使用指定的状态、项数据和工具提示文本创建新项。如果使用 LPSTR_TEXTCALLBACK
,工具提示文本将在需要时通过调用可重写的方法 CCheckersCtrl::OnGetToolTipText
来请求。
BOOL CCheckersCtrl::SetColorsArray (COLORREF *pColors,
int iNumColors, BOOL bRedraw = TRUE)
指定用于表示每种状态的颜色数组。由于状态是一个 BYTE
,数组的最大大小不应超过256。
void CCheckersCtrl::SetDefaultColors (BOOL bRedraw = TRUE)
将用于表示每种状态的颜色数组重置为16种标准的Windows颜色。
BOOL CCheckersCtrl::SetItemData (int nItem, DWORD dwData); DWORD CCheckersCtrl::GetItemData (int nItem) const;
这些函数允许您将应用程序定义的值与每个项关联并进行检索。
BOOL CCheckersCtrl::SetItemState (int nItem, BYTE bState, BOOL bRedraw = TRUE); BYTE CCheckersCtrl::GetItemState (int nItem) const;
这些函数允许您获取或修改单个项的状态。更改会立即反映出来。
BOOL CCheckersCtrl::SetItemStateArray (BYTE *baState, int cbSize = -1, BOOL bRedraw = TRUE); BOOL CCheckersCtrl::GetItemStateArray (BYTE *baState, int cbSize) const;
这些函数允许您获取或修改所有项的状态。更改会立即反映出来。
BOOL CCheckersCtrl::SetItemToolTip (int nItem, LPCTSTR pszTip = LPSTR_TEXTCALLBACK); BOOL CCheckersCtrl::GetItemToolTip (int nItem, CString& str) const
这些函数允许您获取或修改项的工具提示文本。更改会立即反映出来。
BOOL CCheckersCtrl::Create (DWORD dwStyle, const RECT& rect,
CWnd* pParentWnd, UINT nID);
使用此函数将格子控件创建为子窗口。该函数的用法与任何其他通用控件一样。格子控件没有特定的样式。
BOOL CCheckersCtrl::ResetState (BYTE bState = 0, BOOL bRedraw = TRUE);
将所有项的状态重置为指定的状态。
BOOL CCheckersCtrl::InsertItem ( int nItem, BYTE bInitialState = 0, DWORD dwData = 0, LPCTSTR pszTip = LPSTR_TEXTCALLBACK, BOOL bRedraw = TRUE ); BOOL CCheckersCtrl::InsertItems ( int nItem, int nCount = 1, BYTE bInitialState = 0, DWORD dwData = 0, LPCTSTR pszTip = LPSTR_TEXTCALLBACK, BOOL bRedraw = TRUE );
在指定位置插入新项。与 CCheckersCtrl::SetItemCount
中一样,可以指定初始状态、项数据和工具提示文本。
BOOL CCheckersCtrl::DeleteItem (int nItem, BOOL bRedraw = TRUE); BOOL CCheckersCtrl::DeleteItems (int nItem, int nCount = 1, BOOL bRedraw = TRUE);
从指定位置删除项。
BOOL CCheckersCtrl::DeleteAllItems ();
删除所有项。
int CCheckersCtrl::FindItem (DWORD dwData) const;
允许根据关联的应用程序定义值查找项。此方法返回找到的项的索引。如果未找到匹配的项,则返回-1。
int CCheckersCtrl::HitTest (CPoint pt) const;
返回与指定客户区坐标对应的项索引。如果未找到匹配的项,则返回-1。
BOOL CCheckersCtrl::EnsureVisible (int nItem, BOOL bPartialOK);
确保指定的项是可见的。如果需要,该项将被滚动到视图中。
BOOL CCheckersCtrl::EnableToolTips (BOOL bEnable);
允许启用或禁用工具提示功能。如果禁用该功能,所有静态工具提示将被移除。当启用工具提示时,所有项将获得动态工具提示。
高级函数
CToolTipCtrl & CCheckersCtrl::GetToolTipCtrl (); const CToolTipCtrl & CCheckersCtrl::GetToolTipCtrl () const;
检索内部的工具提示控件
可重写函数
您可以从 CCheckersCtrl
派生自己的类,以实现工具提示和鼠标点击的自定义行为。为此,CCheckersCtrl
提供了4个可重写的方法。
virtual BOOL CCheckersCtrl::OnGetToolTipText ( int nItem, BYTE bState, DWORD dwParam, TOOLTIPTEXT * pTTT );
如果您为项指定了动态工具提示(LPSTR_TEXTCALLBACK
),则在请求工具提示文本时会调用此方法。您将获得项索引 nItem
、其状态 bState
、关联的应用程序值 dwData
以及一个指向 TOOLTIPTEXT
结构的指针,您可以在其中返回工具提示文本。请查看演示程序中的实现:
BOOL CMyChecker::OnGetToolTipText (int nItem, BYTE bState, DWORD dwParam, TOOLTIPTEXT *pTTT) { m_csBuffer.Format ( _T("Tooltip for Item %i\n\nStatus: %u\nParameter: %lu (0x%08x)"), nItem, (UINT) bState, dwParam, dwParam ); pTTT->lpszText = (LPTSTR) (LPCTSTR) m_csBuffer; return TRUE; }
virtual BOOL CCheckersCtrl::OnLeftClick ( BOOL bDoubleClick, UINT nFlags, CPoint point, int nItem, BYTE bState, DWORD dwParam ); virtual BOOL CCheckersCtrl::OnMiddleClick ( BOOL bDoubleClick, UINT nFlags, CPoint point, int nItem, BYTE bState, DWORD dwParam ); virtual BOOL CCheckersCtrl::OnRightClick ( BOOL bDoubleClick, UINT nFlags, CPoint point, int nItem, BYTE bState, DWORD dwParam );
这三个可重写的方法允许您处理控件上的鼠标点击事件。nFlags
参数指示各种虚拟键是否被按下。此参数可以是以下值的任意组合:
MK_CONTROL
:如果CTRL键被按下,则设置。MK_LBUTTON
:如果鼠标左键被按下,则设置。MK_MBUTTON
:如果鼠标中键被按下,则设置。MK_SHIFT
:如果SHIFT键被按下,则设置。
point
参数包含发生鼠标点击时相对于控件的客户区坐标。请查看演示应用程序中上下文菜单的实现:
BOOL CMyChecker::OnRightClick (BOOL bDoubleClick, UINT nFlags, CPoint point, int nItem, BYTE bState, DWORD dwParam) { if ( bDoubleClick ) { return TRUE; } CMenu menu; if ( menu.LoadMenu (IDR_CONTEXT_MENU) ) { CMenu *pPopUp = menu.GetSubMenu (0); if ( pPopUp ) { ClientToScreen (&point); m_iLastClick = nItem; pPopUp->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, GetParent ()); } } return TRUE; }
版本历史
版本 1.3
- 修正了类向导注释
- 修正了初始化问题
- 修复了鼠标点击行为
版本 1.2
- 修正了
SetDefaultColors
中的刷新错误 - 添加了延迟重绘功能
- 调整了演示应用程序
版本 1.1
- 改进了文档
- 为演示应用程序添加了上下文菜单
版本 1.0
初始修订版