写这篇东东的目的只在于方便理解列表控件 ListView 中插入进度条的原理, 用的是SDK方式来写, 至于你想找个MFC的类的话自己到网上搜索, 在外国的网站上可能多些.(哪里不清楚的,可以留个言,有时间再帮您解释,谢谢!~~~)偶是个菜鸟而已,所以傲不起.废话少说,下面就列出两个关键点:
1、需要一个绘制进度条的函数。
在查找了老外的源代码后才发现原来列表控件中的进度条是自己用函数绘制的, 而不是直接插入什么进度条控件,下面是这种功能函数的代码:
//
// 函数名: DrawProgress()
// 功能:自定义绘制进度条, 在指定HDC内的RECT内绘制进度条, 适用于列表控件中插入进度条的应用.
// 参数:
// SourceRect --- 列表控件中的SubItem矩形, (自己画的进度条要小于它一个像素)
// hdc --- 列表控件中的hdc
// nProgressPercent -- 进度步值, 从0到100. (自己看看应该懂这是什么意思的,嘻嘻)
//
VOID DrawProgress(HDC hdc, RECT SourceRect, int nProgressPercent)
{
RECT rect; // 整个进度条的矩形, 比来源矩形小一个单位(想要小多少随你定,呵呵)
rect = SourceRect;
rect.left += 1;
rect.top += 1;
rect.right -= 1;
rect.bottom -= 1;
RECT LeftRect, RightRect; // 左右各一个矩形, 用于进度条文字可以在每个矩形内显示不同的颜色
LeftRect = rect;
LeftRect.left += 1;
LeftRect.top += 1;
LeftRect.bottom -= 1;
RightRect = LeftRect;
int w = ((rect.right - rect.left - 2) * nProgressPercent) / 100 ; // nProgressPercent变量,从0-100表示百分比
LeftRect.right = LeftRect.left + w ;
RightRect.left = LeftRect.right;
// 用指定颜色绘制进度条****************************************
// 边框
HBRUSH hBrushRed=CreateSolidBrush(RGB(224, 0, 0)); // 颜色自定
FrameRect (hdc, &rect, hBrushRed);
DeleteObject(hBrushRed);
// 填充
HBRUSH hBrushGreen=CreateSolidBrush(RGB(0, 224, 0)); // 颜色自定
FillRect(hdc, &LeftRect, hBrushGreen);
DeleteObject(hBrushGreen);
// 绘制进度文字**************************************************
TCHAR szFormatStr[10];
_snprintf(szFormatStr, 10, TEXT("%d%%"), nProgressPercent); // 这里可以知道为什么nProgressPercent要取0到100了吧。
// 设置文字背景色透明
SetBkMode(hdc, TRANSPARENT);
RECT TextRect = rect; // 文字绘制区
HRGN hRgnLeft = CreateRectRgnIndirect(&LeftRect);
SelectClipRgn(hdc, hRgnLeft);
SetTextColor(hdc, RGB(0, 0, 255)); // 文字颜色
DrawText(hdc, szFormatStr, -1, &TextRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DeleteObject(hRgnLeft);
HRGN hRgnRight = CreateRectRgnIndirect(&RightRect);
SelectClipRgn(hdc, hRgnRight);
SetTextColor(hdc, RGB(255, 0, 0)); // 文字颜色
DrawText(hdc, szFormatStr, -1, &TextRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DeleteObject(hRgnRight);
SelectClipRgn(hdc, NULL);
}
2、正确的响应NM_CUSTOMDRAW消息。
代码片段如下:
case WM_NOTIFY: // 列表控件发来的通知
// Process notification messages.
switch (((LPNMHDR) lParam)->code)
{
case NM_CUSTOMDRAW: // 自绘列表控件
{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
switch(lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT :
SetWindowLong(hDlg, DWL_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW);
return CDRF_NOTIFYSUBITEMDRAW;
case CDDS_ITEMPREPAINT:
SetWindowLong(hDlg, DWL_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW);
return CDRF_NOTIFYSUBITEMDRAW;
case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
{
int nItemSpec = lplvcd->nmcd.dwItemSpec;
int nSubItem = lplvcd->iSubItem;
// 处理第二个进度子项 (放在哪个列你可以自己定义)
RECT rect;
ListView_GetSubItemRect(hWndListView, nItemSpec, 1, LVIR_BOUNDS, &rect);
// TODO: 在适当的位置处理n, 使其在0到100范围内,然后更新该rect的区域。
DrawProgress(lplvcd->nmcd.hdc, rect, n );
SetWindowLong(hDlg, DWL_MSGRESULT, CDRF_DODEFAULT); // 对话框需要这行才行。
return CDRF_DODEFAULT;
}
}
}
return FALSE; // 其他的不处理,返回给WINDOWS
处理n的示例代码:
// 在某个位置改变n的值后就刷新该区域以使进度条前进,如
n++;
RECT rect;
ListView_GetSubItemRect(hWndListView, Index, 1, LVIR_BOUNDS, &rect); // index就是项目索引
InvalidateRect(hWndListView, &rect, FALSE);
UpdateWindow(hWndListView);
也许写得含糊了点,希望能帮助跟我一样想理解这种原理的您。
源地址:http://hi.baidu.com/senkobqb/blog/item/14d71ddf524e6315622798c1.html