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

CHistogramCtrl,一个类似 Windows 2000 的直方图控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (21投票s)

2001年4月13日

CPOL

5分钟阅读

viewsIcon

223326

downloadIcon

7252

用于在定义范围内(极限)绘制指定值的直方图控件

最初的想法

写这个控件的最初想法是在我心爱的人让我去诊所检查心脏时产生的。你知道,医生们会用一种绘图仪将从心脏获得的信息绘制成直方图。这个想法就是从那时开始的!这个控件是真心献给我的爱人,Cindy。

如何使用

要使用该控件,您需要导入附加到本文的头文件和.cpp文件。然后,您只需打开对话框编辑器,并在您的对话框上放置一个矩形。我们称之为静态控件IDC_STATIC_HISTOGRAM。之后,您需要实例化一个CHistogramCtrl类对象,例如m_ctrlHistogram,作为您dialog类的一个数据成员。

WM_INITDIALOG消息的处理程序中,您获取在dialog框上预先放置的静态矩形的区域,然后像这样创建直方图控件:

// Declaring a local variable
CRect rect;
// Get the rectangular coordinates of the rectangle 
// we already placed on dialog
GetDlgItem(IDC_STATIC_HISTOGRAM)->GetWindowRect(rect);
// Convert to the client coordinates
ScreenToClient(rect);
// Create and place the histogram control on screen
m_ctrlHistogram.Create(WS_VISIBLE | WS_CHILD
      | WS_TABSTOP, rect, this, IDC_STATIC_HISTOGRAM);

完成这些操作后,直方图的窗口就会以类构造函数中指定的默认颜色显示在屏幕上。例如,控件的背景颜色存储在类的m_crBackGround成员变量中,并在CHistogramCtrl的构造函数中被设置为黑色。另一个成员变量m_crGrids存储网格颜色,并在类的构造函数中被设置为RGB(0, 130, 66)

如果我们想将网格颜色改为红色呢?我们是否应该修改构造函数中的上述变量?当然不行!为了做到这一点,我创建了一个名为SetGridsColor的方法,其原型如下:

BOOL CHistogramCtrl::SetGridsColor(COLORREF cr);

其中cr是网格颜色的引用。例如,您可以通过这种方式将网格颜色改为红色:

//Change the color of grids to red
m_ctrlHistogram.SetGridsColor(RGB(255, 0, 0));

以下是该类的其他方法,可用于更改控件的默认行为:

BOOL CHistogramCtrl::SetBkColor(COLORREFcr);
void CHistogramCtrl::SetPen(int nWidth, COLORREF crColor);
void CHistogramCtrl::SetRange(UINT uLower, UINT uUpper);
CHistogramCtrl::SPEED SetSpeed(CHistogramCtrl::SPEED uSpeed);
void CHistogramCtrl::SetPos(UINT uPos);</td>

尽管方法名称清晰地说明了它们的功能,但我们还是快速了解一下每个方法的作用会更有意义。

第一个提到的方法SetBkColor用于设置控件的背景颜色。默认值为黑色,即 RGB(0, 0, 0),在类的构造函数中声明。

第二个方法用于设置控件的画笔,该画笔用于绘制直方图。第一个参数nWidth用于设置线条的宽度。第二个参数crColor是一个COLORREF,用于设置画笔的颜色。如果您不使用此函数,将使用默认值:画笔宽度为1,画笔颜色为RGB(0, 255, 0)

第三个方法SetRange用于设置控件的上限和下限(范围)。这些参数的有效范围如下:

  • uLower > 0
  • uUpper > 0
  • uLower < uUpper

请注意,如果您未指定范围,则范围将设置为 1-100 - 即,您可以绘制 1 到 100 之间的数字。

现在,让我们从SetRange转向下一个方法SetSpeed。此方法用于控制CHistogramCtrl的刷新速度。我这么说吧,窗口内容会在指定的时间间隔内向左移动 3 像素。有 4 个预定义的间隔,声明为一个enum,如下所示:

  1. LOW_SPEED (3000 毫秒)
  2. NORMAL_SPEED (1000 毫秒;默认值)
  3. HIGH_SPEED (500 毫秒)
  4. IDLE (0 毫秒)

要使用此函数,您只需这样做:

// Change the speed of scrolling
m_ctrlHistogram.SetSpeed(CHistogramCtrl::HIGH_SPEED);</td>

这样,控件的内容将在 500 毫秒的间隔内向左移动 3 像素。

现在,是时候将我们的注意力转向该类最后一个public方法SetPos了,其声明如下:

void CHistogramCtrl::SetPos(UINT uPos);

此成员函数执行实际的绘图操作。例如,要将直方图的当前位置设置为26,您可以轻松地编写以下语句:

//Set the current position of the histogram to 26
m_ctrlHistogram.SetPos(26);

现在想象一下,十秒后将直方图的位置设置为 87 会发生什么。您将看到一个如下所示的直方图:

换句话说,如果我们不向控件提供新值,线条将不会发生变化。但是,如果我们提供的数量超过了控件能显示的范围怎么办?例如,假设我们将控件的速度设置为HIGH_SPEED(500 毫秒),并且我们在 500 毫秒内向控件输入 20 次值。在第一个 500 毫秒结束时显示哪个值?

为了解决这个问题,我在CHistogramCtrl中创建了一个CList作为private数据成员。每当您调用SetPos时,我都会将您提供的值附加到上述列表中。每当我想刷新控件时(在我们例子中是每 500 毫秒结束时),我都会处理该列表,并获得列表中当前值的平均值。为了说明我的意思,请想象我们在第一个 500 毫秒内将控件的当前位置设置为以下值:

10, 87, 19, 54, 63, 74

当这些时间过去后,我将处理列表中的当前值,并计算列表成员的平均值:

10 + 87 + 19 + 54 +63 + 74 = 307
307 / 6 = 51.1

我将显示51.1作为当前值……明白了?

这是通过类的private方法之一GetAverage完成的,该方法返回上述列表中数字的平均值。在某些情况下,您可能需要用您期望的机制来更改控件在刷新间隔内计算当前位置的机制。例如,在我的最新项目中,我使用了数字的方差而不是它们的平均值。请注意,为了获得在每个周期结束时显示的值,该函数是在DrawLine方法中调用的。

由于源代码非常直接且易于理解,因此本文到此结束。请随时通过在下方留言来发送您对这个控件的评论、问题和/或建议。 Aloha!

历史

  • 2001 年 4 月 13 日:初始版本
© . All rights reserved.