作为 MFC 的新手,我经常看到设备上下文 (DC)。我隐约明白这与绘画有关,但我能找到的任何地方都没有很好地解释具体细节。创建“兼容的设备上下文”意味着什么,为什么它很重要? SelectObject 有什么作用?我必须首先如何使 DC 兼容?
设备上下文只是进行绘制的地方,因此如果您有两个不同的 DC,则您将在两个不同的位置进行绘制。有点像文件句柄。
设备上下文可以指屏幕上的实际空间,也可以指仅驻留在内存中的位图,也可能是其他地方,这些只是我目前能想到的两个。
兼容上下文是具有相同底层像素组织的上下文,这意味着每个像素的位数、每个像素的字节数、颜色组织等等。内存位图设备上下文可以具有您想要的任何组织,但您的屏幕上下文将(最终)与显卡上的缓冲区相关,这将(取决于模式等)具有非常特定的像素组织。
拥有兼容的上下文意味着在它们之间传输图像数据是高效的,因为几乎不需要或不需要数据转换。在另一个极端,如果您有 256 色调色板、8 位图,并且尝试将其传输到每个像素具有 8 位 RGBA 的屏幕,则每个最后一个像素在复制时都需要大量调整,因此复制不兼容位图要慢得多。根据Win32 SDK文档,至少BitBlt()和StretchBlt()“转换源颜色格式以匹配目标格式”,所以可以做到。
研究 CreateCompatibleDC() 和 CreateCompatibleBitmap() 作为如何创建与现有绘图上下文兼容的绘图上下文的起点。
SelectObject() 控制设备上下文中当前处于活动状态的资源。上下文具有当前笔、画笔、字体和位图。这些允许您指定更少的参数,从而使许多其他 GDI 调用变得更简单。例如,使用 TextOut() 时不必指定字体,但如果您想更改字体,则需要使用 SelectObject()。如果向 SelectObject() 提供字体句柄,则返回value 是有效字体的句柄,后续操作将使用新字体。其他类型的资源、钢笔、画笔等的行为是相同的。
(老问题,但在谷歌搜索时会显示...)
恐怕对于初学者来说,所选的答案可能会有点误导。
请记住,MFC 封装了 Win32 API,因此我们需要从 Win32 层面来看,才能更好地理解发生了什么。
要了解为什么有设备上下文,我们应该了解GDI(图形设备接口)。
那么,为什么会有GDI呢? - 为了设备独立性。为了实现这一目标,微软制作了图形对象(画笔、笔……),每个对象都包装并抽象了所有设备依赖性问题。
现在我们不必关心不同的设备,这就是 GDI 的全部意义。
所以我们需要在某种数据结构中保存图形对象(画笔、笔、位图……),这就是设备上下文。
那么什么是SelectObject函数?
从字面上看,它使 DC 能够“选择”图形对象。即,我们使用 SelectObject 将存储在 DC 中的图形对象句柄更改为我们想要使用的另一个图形对象句柄。
那么什么是兼容设备上下文?
兼容设备上下文(=内存设备上下文)使用内存,而不是设备。
来自MSDN(强调我的):
一次使应用程序能够将输出放入内存而不是发送 它到实际设备,使用位图的特殊设备上下文 称为“内存设备上下文”的操作。内存 DC 使 系统将一部分内存视为虚拟设备。它是一个 应用程序可以临时使用的内存中的位数组 存储在普通绘图表面上创建的位图的颜色数据。 由于位图与设备兼容,因此内存 DC 也是 有时称为兼容设备上下文。 内存 DC 存储特定设备的位图图像。一个 应用程序可以通过调用CreateCompatibleDC来创建内存DC 功能。
可以使用兼容DC(内存DC),例如,减少“闪烁”(一次又一次地部分绘制),因为我们可以在内存中的位图上绘制所有内容并在显示器上显示
,而不是显示所有内容显示器刷新的时间(例如 60Hz)。这种方法称为“双缓冲”。 遵循 MSDN 文档对新手(包括我)会有帮助。
设备上下文,从 MFC 的角度来看。
设备上下文,从 Win32 的角度来看
,以及 以下部分。