CStatusGraphCtrl - CWnd 的 C++ 包装类,用于以图形方式显示状态





4.00/5 (9投票s)
2004年5月2日
4分钟阅读

105095

4814
C++ 源文件,用于创建一个控件,该控件以图形方式显示应用程序变量的当前状态。
引言
本文档解释了如何将我的图形状态显示控件 (CStatusGraphCtrl
) 集成到您的应用程序中。许多实时应用程序都有一个需求,即向用户更新与该应用程序相关的一些关键参数的当前值;CStatusGraphCtrl
不仅显示值,还可以将参数变化的过程显示为图形。目前,它支持条形图和折线图显示。如果需要,您可以自定义代码以支持您自己的图形显示方式。该控件与您在 Windows 任务管理器中看到的显示 CPU 和内存使用情况的控件完全相同。
使用代码
CStatusGraphCtrl
源文件 (zip) 将包含以下文件
- CGraphData.h
- CGraphData.cpp
- CStatusGraphCtrl.h
- CStatusGraphCtrl.cpp
这四个文件是该控件的核心文件。将这四个文件添加到您的 VC++ 应用程序项目中。
CGraphData
类充当控件视口中当前数据的保存者。数据以线性单向链表的形式存储。
CStatusGraphCtrl
类是核心控件类,它派生自 CWnd
MFC 类。要在对话框中创建 CStatusGraphCtrl
控件,请在对话框的 CDialog::OnCreate
中调用 CStatusGraphCtrl::Create
,如下所示:
m_ctrlStatusGraph.Create("Demo Control",/* Caption - ofcourse not used */ WS_CHILD|WS_VISIBLE, /* Windows styles */ CRect(10,10,350,200), /* Position, size */ static_cast<CWnd*>(this), /* Parent */ GRAPH_CTRL_ID /* ID that u assign for this control */ );
这将根据所需位置创建一个 StatusGraphCtrl
。控件创建后,您需要使用以下方法指定控件的几个属性值:
SetMinValue
SetMaxValue
SetSamplingInterval
调用 SetMinValue
来指定控件视口中最底部的线的值。调用 SetMaxValue
来指定控件视口中最顶部的线的值。调用 SetSamplingInterval
来指定连续绘图点之间的水平距离(以像素为单位)。一切就绪后,调用 CStatusGraphCtrl::StartUpdate
使控件开始运行。调用 StartUpdate
后,任何对 CStatusGraphCtrl::SetCurrentValue
的调用都将反映在控件视口中看到的图形上。
图形从右向左滚动。每次滚动的延迟可以通过调用 CStatusGraphCtrl::SetRefreshDelay
并将所需的延迟(以毫秒为单位)作为参数传入来控制。
以下代码块摘自我的演示应用程序,将提供一个简单的代码来在您的应用程序中使用 CStatusGraphCtrl
控件。
void DataGenerator(LPVOID param) { CStatusGraphCtrl* pCtrl = (CStatusGraphCtrl*)param; while(true) { int nRand = rand(); while(nRand > pCtrl->GetMaxValue()) nRand /= 10; pCtrl->SetCurrentValue(nRand); /* this value will be reflected in the graph in control's viewport */ Sleep(50); } } int CDemoDialog::OnCreate(LPCREATESTRUCT lpCreateStruct) { // m_ctrlStatusGraph is a member of type CStatusGraphCtrl m_ctrlStatusGraph.Create("Demo Control", WS_CHILD|WS_VISIBLE,CRect(10,10,350,200), static_cast<CWnd*>(this),GRAPH_CTRL_ID); m_ctrlStatusGraph.SetMaxValue(100); m_ctrlStatusGraph.SetMinValue(0); m_ctrlStatusGraph.StartUpdate(); AfxBeginThread((AFX_THREADPROC)DataGenerator, (LPVOID)&m_ctrlStatusGraph); return CDialog::OnCreate(lpCreateStruct); }
自定义 CStatusGraphCtrl
CStatusGraphCtrl
的几乎所有方面都可以自定义。以下是您可以根据需要自定义的属性列表:
SamplingInterval
- 调用SetSamplingInterval(short)
- 连续绘图点之间的水平距离(以像素为单位)RefreshDelay
- 调用SetRefreshDelay(int)
- 连续滚动之间的延迟(以毫秒为单位)- 背景颜色 - 访问公共成员
COLORREF m_BackColor
- 前景颜色 - 访问公共成员
COLORREF m_ForeColor
添加自定义 GraphModes
要添加您自己的 GraphMode
,您只需要两个步骤。更新 CStatusGraphCtrl.h 头文件中的 enum StatusGraphType
以添加您新的 GraphType
条目。然后,在 CStatusGraphCtrl.cpp 文件中的 DrawPoint
函数中添加绘制图形的代码。请看这段代码片段:
void DrawPoint(CStatusGraphCtrl* TheCtrl,long int cury,bool Update) { // control specific code will be here... // .. // .. switch(TheCtrl->GetGraphMode()) { case BAR_GRAPH: pdc->MoveTo(rcBounds.right-sSamplingInterval,rcBounds.bottom); pdc->LineTo(rcBounds.right-sSamplingInterval,rcBounds.bottom-cury); break; case LINE_GRAPH: pdc->MoveTo(rcBounds.right-2*sSamplingInterval, rcBounds.bottom-TheCtrl->m_lPreviousY); pdc->LineTo(rcBounds.right-sSamplingInterval,rcBounds.bottom-cury); break; //**************************************************************************// // TODO: // Update the enum type in the header (CStatusGraphCtrl.h) file accordingly // Add additional case blocks to support your own graph modes // cury - represents the current value to plot // TheCtrl->m_lPreviousY - represents the previous point plotted. // rcBounds - represent the bounds of the CStatusGraphCtrl Control. //*************************************************************************// case CUSTOM_GRAPH: // do something with cury,TheCtrl->m_lPreviousY,rcBounds as required. break; } // control specific code will be here... // .. // .. }
事件
CStatusGraphCtrl
的编写方式是在鼠标单击控件时发送 WM_COMMAND
消息。应用程序可以根据需要利用这一点。例如,在我的演示应用程序中,我在控件的 ON_COMMAND
处理程序中添加了更改 CStatusGraphCtrl
的图形模式的功能。请参阅处理程序代码:
BEGIN_MESSAGE_MAP(CDemoDialog, CDialog) // .. other message maps.. // .. ON_COMMAND(GRAPH_CTRL_ID,OnClickGraph) END_MESSAGE_MAP() BOOL CDemoDialog::OnClickGraph() { // toggles the graph mode between BAR_GRAPH (0) and LINE_GRAPH (1) m_ctrlStatusGraph.SetGraphMode((StatusGraphType) !(int)m_ctrlStatusGraph.GetGraphMode()); return TRUE; }
关注点
我将告诉您我是如何编写这段代码的。我当时正在编写一个网络实用程序,用于监控网络流量并控制来自单个源的过多流量,在此过程中我需要一个这样的控件。我从 Button 的 BS_OWNERDRAW
功能开始,并愉快地使用 CDC
来满足需求。此代码使用 CDC::BitBlt
来执行图形滚动,因此速度非常快且无闪烁。我几乎完成了,并检查了控件的各种功能。直到那时,我还没有尝试在我的应用程序运行时切换应用程序。问题就出在我切换回我的应用程序时,整个图形都消失了!!!!糟糕,我的内存中没有必要的信息来重绘图形。那时我添加了一个新类 CGraphData
,它存储与控件当前视口相关的数据。数据结构仅存储点序列,而不存储整个视口像素矩阵。实际上,滚动也发生在数据结构中。每当右侧有新值时,左侧的值就会被删除,从而保持窗口大小。
感谢 CodeProject 的成员:在我提交这篇文章的第一天,我收到了关于我的代码的反馈;从这些反馈中,我感觉到使用 CButton
来实现这个控件根本没有必要;我立即修改了代码,并在那里发布了。现在,该控件不再使用 CButton
。它只是一个窗口。
历史
CStatusGraphCtrl
的第一个版本是从CButton
派生的。- 根据 CodeProject 成员的反馈,我修改了代码,使其派生自
CWnd
。