书籍:《Visual C++ 2017从入门到精通》的4.2 按钮控件
环境:visual studio 2022
内容:[例 4.4]实现一个三角按钮
说明:以上内容大部分来自腾讯元宝。
CPen
是 MFC(Microsoft Foundation Classes)中封装 Windows GDI(图形设备接口)画笔功能的类,用于绘制线条、边框、轮廓等图形元素。通过 CPen
,开发者可以灵活设置线条的样式、颜色、宽度等属性,实现从简单直线到复杂图形的绘制。
核心功能
- 绘制线条:用于绘制直线、曲线、矩形边框等。
- 自定义样式:支持实线、虚线、点线、双线等多种样式。
- 颜色与宽度控制:可设置 RGB 颜色和画笔宽度。
- 资源管理:自动管理 GDI 对象,避免内存泄漏。
类结构与关键成员
1. 构造函数
- 默认构造函数:创建未初始化的
CPen
对象。CPen myPen;
- 带参数的构造函数:直接指定样式、宽度和颜色。
CPen myPen(PS_SOLID, 2, RGB(255, 0, 0)); // 红色实线,宽度2
2. 创建画笔
-
CreatePen
:动态创建画笔。BOOL CreatePen( int nPenStyle, // 画笔样式(如 PS_SOLID) int nWidth, // 画笔宽度(像素) COLORREF crColor // 颜色(RGB值) );
-
CreatePenIndirect
:通过LOGPEN
结构创建。LOGPEN logPen = { PS_DOT, 1, RGB(0, 0, 255) }; CPen myPen; myPen.CreatePenIndirect(&logPen);
3. 属性设置与获取
方法 | 功能 |
---|---|
SetPenStyle(int nStyle) | 设置画笔样式(如 PS_DASH 虚线)。 |
SetPenWidth(int nWidth) | 设置画笔宽度。 |
SetPenColor(COLORREF) | 设置画笔颜色。 |
GetPenStyle() | 获取当前画笔样式。 |
GetPenWidth() | 获取当前画笔宽度。 |
4. 选入设备上下文
-
SelectObject(CDC* pDC)
:将画笔选入设备上下文(CDC),替换原有画笔。CDC* pDC = GetDC(); CPen oldPen = pDC->SelectObject(&myPen); // 保存原画笔,后续需恢复
- 恢复原画笔:
pDC->SelectObject(oldPen);
常用画笔样式
样式常量 | 描述 |
---|---|
PS_SOLID | 实线(默认)。 |
PS_DASH | 虚线(短划线)。 |
PS_DOT | 点线(小点)。 |
PS_DASHDOT | 点划线(交替虚线和点)。 |
PS_DASHDOTDOT | 双点划线(虚线加点)。 |
PS_NULL | 不可见画笔(用于绘制无边框区域)。 |
PS_INSIDEFRAME | 线条绘制在矩形框内部(常用于填充区域)。 |
代码示例
1. 绘制红色实线矩形
void CMyView::OnDraw(CDC* pDC) {
CPen myPen(PS_SOLID, 2, RGB(255, 0, 0)); // 红色实线,宽度2
CPen* pOldPen = pDC->SelectObject(&myPen);
CRect rect(50, 50, 200, 150);
pDC->Rectangle(rect); // 绘制矩形边框
pDC->SelectObject(pOldPen); // 恢复原画笔
}
2. 动态切换虚实线
void CMyView::OnLButtonDown(UINT nFlags, CPoint point) {
CPen dashedPen(PS_DASH, 1, RGB(0, 0, 255));
m_pDC->SelectObject(&dashedPen);
m_pDC->MoveTo(point);
// ... 其他绘图逻辑 ...
}
高级用法
1. 自定义虚线模式
通过 LOGPEN
结构定义复杂虚线样式:
LOGPEN logPen;
logPen.lopnStyle = PS_USERSTYLE; // 自定义样式
logPen.lopnWidth.x = 1; // 宽度1像素
logPen.lopnColor = RGB(255, 0, 0);
CPen userPen;
userPen.CreatePenIndirect(&logPen);
2. 抗锯齿绘制
结合 CPen
和 SetStretchBltMode
实现平滑线条:
pDC->SetStretchBltMode(HALFTONE);
CPen smoothPen(PS_SOLID, 1, RGB(0, 128, 0));
pDC->SelectObject(&smoothPen);
注意事项
-
资源管理:
- 使用
CPen
时,必须确保选入设备上下文的画笔被正确恢复(通过保存oldPen
)。 - 避免内存泄漏:MFC 的
CPen
在析构时会自动释放 GDI 对象,但显式调用DeleteObject()
更安全。if (myPen.GetSafeHandle() != NULL) { myPen.DeleteObject(); }
- 使用
-
性能优化:
- 频繁创建/销毁画笔可能影响性能,建议复用对象。
- 在
WM_PAINT
消息处理中,优先使用内存 DC 进行双缓冲绘图。
-
坐标系适配:
- 画笔宽度以像素为单位,在高分辨率屏幕(如 4K)下可能需要缩放。
与其他GDI对象对比
类名 | 用途 | 核心属性 |
---|---|---|
CPen | 绘制线条、边框 | 样式、宽度、颜色 |
CBrush | 填充区域(如矩形、圆形) | 填充模式、颜色、图案 |
CFont | 文本绘制 | 字体名称、大小、样式 |
总结
- 核心作用:
CPen
是 MFC 中绘制线条和轮廓的基础工具,支持高度自定义样式。 - 典型应用:
- 自定义控件边框(如圆角按钮、异形窗口)。
- 图表绘制(如折线图、柱状图)。
- 图形界面元素(如菜单高亮、状态指示)。
- 最佳实践:
- 优先使用
CreatePen
或CreatePenIndirect
动态创建画笔。 - 在复杂绘图中复用
CPen
对象以提升性能。 - 结合
CBrush
和CFont
实现完整的图形绘制流程。
- 优先使用