Windows 编程/GDI 和绘图
此页面为Windows 编程书籍中的一个存根。您可以通过扩展它来提供帮助。
本页将讨论使用 Windows GDI 库进行图形和绘图。
GDI 是 Windows 的原始图形 API。但是,DirectX 图形基础架构 现在推荐用于其改进的 GPU 函数使用、alpha 混合 和 抗锯齿[1]。
里面有什么?以及它们的默认值
| GDI 对象(每种类型一个) | Windows 版本 | 设置函数 | 获取函数 | |
| 画笔 | 零宽度黑色画笔(表示在任何缩放比例下 1 像素宽度) | 2 | SelectObject(SelectPen、SelectBrush、SelectFont) | GetCurrentObject |
| 画刷 | 白色实心画刷 | 2 | ||
| 字体 | 系统默认字体 | 2 | ||
| 调色板 | 系统默认调色板(见下文) | 3 | SelectPalette | |
| 颜色空间 | ? | 4 | SetColorSpace | |
| 目标位图(不适用于元文件上下文) | 取决于创建 DC 的函数 | 2 | SelectObject(SelectBrush) | |
| 裁剪区域 | 取决于创建 DC 的函数 | 2 | GetClipRgn(GetClipBox) | |
| 数字 | ||||
| 映射模式、缩放和偏移量 | 1 单位 = 1 像素,原点 = 左/上 | 2 | Get/Set MapMode、WindowOrgEx、WindowExtEx、ViewportOrgEx、ViewportExtEx | |
| 变换矩阵(旋转、剪切、缩放、偏移量) | 平等 | 4 | SetWorldTransform、ModifyTransform | GetWorldTransform |
| 文本颜色,也用于涉及 blt 操作的黑白 | 黑色 | 2 | SetTextColor | GetTextColor |
| 背景颜色,用于文本 / 网格画刷 / 虚线背景和一些 blt 操作 | 白色 | 2 | SetBkColor | GetBkColor |
| 斜接限制(锐利多边形角的裁剪) | 10.0F(线宽的十倍) | 4 | SetMiterLimit | GetMiterLimit |
| 画刷原点(用于对齐图案画刷) | 0/0 | 2 | SetBrushOrgEx | GetBrushOrgEx |
| 枚举和布尔开关 | ||||
| 启用高级 GDI 函数 | 否 | 4 | SetGraphicsMode | GetGraphicsMode |
| 复杂多边形内或外(PolyFillMode) | 交替规则 | 2 | SetPolyFillMode | GetPolyFillMode |
| 文本对齐 | 顶部/左侧 | 2 | SetTextAlign | GetTextAlign |
| 文本 / 网格画刷 / 虚线输出是否具有不透明背景颜色 | 有背景 | 2 | SetBkMode | GetBkMode |
| 位图在 blt 操作中如何拉伸 | ? | 3 | SetStretchBltMode | GetStretchBltMode |
| 画笔 / 画刷和表面如何组合(布尔运算) | 复制画笔 | 2 | SetROP2 | GetROP2 |
| 其他 | ||||
| 路径(准备好的线) | 空路径 | 4 | BeginPath、EndPath ... | - |
| 上下文堆栈 | 空 | 2 | SaveDC | RestoreDC |
待续...
Windows 使用画刷来绘制颜色并使用预定义的图案填充区域。画刷的最小尺寸为 8X8 像素,并且与画笔类似,具有三个基本特征:大小、图案和颜色。由于其 8X8 像素的最小尺寸,画刷被认为具有图案,而不是像画笔那样的样式。图案可以是实色、网格、对角线或任何其他用户定义的组合,甚至是位图图案。
case WM_PAINT:
{
/* This will paint a red rectangle */
HDC holdBrush;
HDC hdc = BeginPaint(hwnd, &ps);
HBRUSH hBrush = CreateSolidBrush(RGB(255,0,0));
holdBrush = SelectObject(hdc, hBrush);
Rectangle(hdc, 10, 10, 100, 100);
DeleteObject(hBrush);
/* Memory management has been omitted for brevity */
EndPaint(hwnd, &ps);
break;
}
画刷对象背后是什么?
| 在创建时,请参见 LOGBRUSH 结构 | 修改 |
|---|---|
| 颜色(RGB 颜色,可以在实现时进行抖动) | SetDCBrushColor |
| 样式(实心、网格或位图) | - |
| 位图(对于位图样式) | - |
| 实现时的隐藏字段 | |
| 引用设备上下文(跟踪实现是否仍然有效) | UnrealizeObject |
| 设备相关,可能是抖动的位图,通常为 8x8 尺寸 | - |
请注意,位图图案画刷的行为与网格画刷不同,即使位图看起来像网格。网格画刷是透明的,而位图画刷是不透明的。如果使用黑白位图,黑色将被替换为设备上下文的文本颜色,白色将被替换为背景颜色。(这正是 BitBlt() 的行为。)SetBkMode() 不会起作用。但是,DC 的 ROP2 会起作用。
画笔用于创建绘制的形状周围的边框。
| 可见字段,请参见 LOGPEN 结构 | Windows 版本 | 修改 |
|---|---|---|
| 宽度,以水平(!) 逻辑单位表示,0 = 1 像素 | 2 | - |
| 样式(实心或某种点线) | 2 | - |
| 用户点线样式(对于用户选择的样式) | 4 | - |
| 颜色 | 2 | SetDCPenColor |
| 画刷(内容:见上文) | 4 | - |
| 几何/装饰标志 | 4 | - |
| 提示如何绘制线端 | 4 | - |
| 提示如何绘制线连接 | 4 | - |
| 隐藏字段 | ||
| 引用设备上下文(跟踪其他隐藏字段的有效性) | 2 | UnrealizeObject? |
| 以设备像素表示的宽度 | 2 | - |
| 给定颜色的调色板索引 | 2 | - |
| 用于填充宽线的设备相关位图 | 2 | - |
导致宽度大于 1 设备像素(而不是逻辑单位)的线将作为具有绕线规则的多边形绘制。线颜色永远不会进行抖动,除非使用具有实心画刷的 ExtCreatePen。
字体用于以各种样式和尺寸显示文本和符号。Windows 2(非常基本)、3.1(引入 TrueType)和 4+(Unicode;世界变换旋转和镜像;倾斜度可能与旋转不同)之间的字体管理存在内部较大差异。
请参见 LOGFONT 结构以了解可见字段。
隐藏字段包括
- 引用设备上下文
- 设备相关位图字体表示
因此,将字体选择到设备上下文(SelectObject)可能很耗时,尤其是对于大型亚洲字体和大型字体尺寸,需要从 TrueType 模板中“绘制”所有字形到位图中。此外,与所有 GDI 对象一样,最好不要在一个上下文之间选择一个对象,因为使隐藏文件失效可能是一个耗时的过程。请注意,任何 GDI 对象都不能选择到多个 DC 中。
在 Windows 中,绘图通常由 WM_PAINT 消息处理。以下是绘制红色正方形的示例
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
// RECT defines the upper-left and lower-right corners of a rectangle
RECT rectangle = {50, 50, 250, 250};
HBRUSH hbr = CreateSolidBrush(RGB(125, 0, 0));
FillRect(ps.hdc, &rectangle, hbr);
DeleteObject(hbr);
EndPaint(hwnd, &ps);
}
break;
首先,我们创建 PAINTSTRUCT 变量 ps。这是一个包含有关绘画操作的信息的数据结构。下一行调用 BeginPaint。这将初始化 ps,然后用相关信息填充它。对于此示例,我们只需要 ps 的 hdc 成员。这是一个指向我们窗口设备上下文的句柄。接下来,我们创建一个矩形。这包含我们要绘制此矩形的左上角和右下角坐标。坐标相对于窗口客户区的左上角。我们还必须创建一个画刷,否则 Windows 将不知道要使用什么颜色来绘制矩形。最后,我们调用 FillRect,并传递参数 ps.hdc、指向 rectangle 的指针和 hbr(我们的画刷)。这会将矩形直接绘制到我们窗口的设备上下文,然后从那里绘制到屏幕上。在每次绘画操作后,都需要清理我们使用的任何 GDI 对象,在本例中为 hbr 和 ps。
由于 Windows 应该响应 WM_PAINT 和 WM_PRINTCLIENT,因此编写 WM_PAINT 处理程序的一般规则如下
case WM_PRINTCLIENT: OnPaint((HDC)wParam, NULL); break;
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
OnPaint(ps.hdc, &ps.rcPaint); // It's a good idea to manage the update area. Other PAINTSTRUCT fields are of less usefulness.
EndPaint(hwnd, &ps);
}break;
// Somewhere else
void OnPaint(HDC dc, RECT* rcUpdate) {
...
}
- ↑ QuinnRadich. "Windows 图形架构概述 - Win32 应用". learn.microsoft.com. 检索于 2023-04-11.