我们用VC,基于对话框来创建对象,项目名为TextProgress,在MFC的基类中有个CProgressCtrl类,CProgressCtrl是“进度条控件”是一个窗口,应用程序可以使用这个窗口来表明一个冗长操作的进度。它由一个从左到右,用系统高亮色逐渐填充的矩形组成。我们基于它派生一个新类CTextProgress,这个就是我们实现代码的地方。然后我们在对话框中添加进度条控件,将其属性设为Smooth,并为它关联一个控件变量m_Progress,基于CTextProgress。当你关联变量成功时,会跳出个对话框,提示你在CTextProgressDlg的头文件中加上TextProgress的头文件,这是因为,我们的这个控件是基于对话框类(CTextProgressDlg)的尽管我们为进度条关联的是别的类型,但还是声明在CTextProgressDlg类的头文件中。因此我们需要告诉编译器,m_Progress变量是CTextProgress中。
我们需要为新类添加WM_PAINT消息,在这里面添加我们的实现代码,当我们添加消息成功后,添加如下代码,不过在头文件中先声明三个变量:
class CTextProgress : public CProgressCtrl
{
// Construction
public:
CTextProgress();
COLORREF m_crText; //文本颜色
COLORREF m_crProgress; //进度颜色
COLORREF m_crBlank; //空白区域颜色
// Attributes
public:
........
}
接着我们在构造函数中,实例化变量:
CTextProgress::CTextProgress()
{
m_crText = RGB(0, 255, 0);
m_crBlank = RGB(255, 255, 255);
m_crProgress = RGB(0, 255, 0);
}
最后就是代码了:
void CTextProgress::OnPaint()
{
PAINTSTRUCT ps;
CDC* pDC = BeginPaint(&ps); //开始绘制
int nPos = GetPos(); //获取当前进度条的位置
CString csPos;
csPos.Format("%d%%", nPos); //格式化字符串
CRect clientRC;
GetClientRect(clientRC); //获取客户区域
CSize sztext = pDC->GetTextExtent(csPos); //获取字符串的高度和宽度
int nX = (clientRC.Width() - sztext.cx) / 2; //计算中心位置
int nY = (clientRC.Height() - sztext.cy) / 2;
int nMin, nMax;
GetRange(nMin, nMax); //获取进度条的显示范围
//获取单位刻度
double dFraction = (double)clientRC.Width() / (nMax-nMin);
int nLeft = nPos * dFraction; //计算左边距
CRect leftRC = clientRC;
leftRC.right = nLeft;
CRect rightRC = clientRC;
rightRC.left = nLeft;
pDC->FillRect(leftRC, &CBrush(m_crProgress)); //使用蓝色标识当前的进度
pDC->FillRect(rightRC, &CBrush(m_crBlank)); //使用白色标识剩余的部分
pDC->SetTextColor(m_crText); //设置文本颜色
pDC->TextOut(nX, nY, csPos); //输出当前的进度
ReleaseDC(pDC); //释放设备上下文
EndPaint(&ps); //结束窗口绘制
}
第一句代码是一个结构体:
PAINTSTRUCT定义
typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT;
PAINTSTRUCT 结构体包含了用于绘制窗口客户区的信息。例如要更新的客户区的矩形区域的大小等等,MFC里的CPaintDC与之对应;BeginPaint可以得到客户区设备描述表的句柄,GetDC也可以得到,MFC里的CClientDC与之对应。
hdc是用于绘制的句柄,
fErase如果为非零值则擦除背景,否则不擦除背景,
rcPaint 通过制定左上角和右下角的坐标确定一个要绘制的矩形范围,该矩形单位相对于客户区左上角,
后面三个参数都是系统预留的,编程一般用不到。
这是我们第二句代码Begin函数里的参数:
HDC BeginPaint(
HWND hwnd, // 窗口的句柄
LPPAINTSTRUCT lpPaint // 绘制信息
);
下面的代码我就不句句解释了,我在代码后面做了注释。我们的进度条有了这个还不够哦!我们需要设置一个定时器,使得进度条移动。我们在CTextProgressDlg类中,设置个定时器,首先在InitInstance函数中设置定时器:
BOOL CTextProgressDlg::OnInitDialog()
{
CDialog::OnInitDialog();
......
SetTimer(1, 100, NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
接着就是定时器消息了:
void CTextProgressDlg::OnTimer(UINT nIDEvent)
{
int nCurPos = m_Progress.GetPos();
m_Progress.SetPos(nCurPos+1);
CDialog::OnTimer(nIDEvent);
}
其中的代码就是设置进度条中的进度一格一格的增加。效果图: