📄 chap11_1.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>11.1调色板</title>
<link rel="stylesheet" href="../../../cpcw.css"></head>
<body link="#3973DE" alink="#3973DE" background="../../bg.gif">
<div align="center"><center>
<table width="85%" border="0">
<tr bgcolor="#FFFFFF">
<td>
<div align="center">
<center>
</center>
</div>
<p align="CENTER"><b><font face="Times New Roman" color="red">11.1</font><font color="red">调色板</font></b></p>
<p align="CENTER"> <font face="Times New Roman" size="4"></font><b> </b></p>
<p align="JUSTIFY"> <b></b><font color="#3973DE" face="Times New Roman" size="3">11.1.1
</font><font size="3" color="#3973DE">调色板的原理</font></p>
<p align="JUSTIFY"> PC机上显示的图象是由一个个像素组成的,每个像素都有自己的颜色属性。在PC的显示系统中,像素的颜色是基于RGB模型的,每一个像素的颜色由红(B)、绿(G)、蓝(B)三原色组合而成。每种原色用8位表示,这样一个的颜色就是24位的。以此推算,PC的SVGA适配器可以同时显示2<sup>24</sup>约一千六百多万种颜色。24位的颜色通常被称作真彩色,用真彩色显示的图象可达到十分逼真的效果。</p>
<p align="JUSTIFY"> 但是,真彩色的显示需要大量的视频内存,一幅640×480的真彩色图象需要约1MB的视频内存。由于数据量大增,显示真彩色会使系统的整体性能迅速下降。为了解决这个问题,计算机使用调色板来限制颜色的数目。调色板实际上是一个有256个表项的RGB颜色表,颜色表的每项是一个24位的RGB颜色值。使用调色板时,在视频内存中存储的不是的24位颜色值,而是调色板的4位或8位的索引。这样一来,显示器可同时显示的颜色被限制在256色以内,对系统资源的耗费大大降低了。</p>
<p align="JUSTIFY"> 显示器可以被设置成16、256、64K、真彩色等显示模式,前两种模式需要调色板。在16或256色模式下,程序必须将想要显示的颜色正确地设置到调色板中,这样才能显示出预期的颜色。图11.1显示了调色板的工作原理。使用调色板的一个好处是不必改变视频内存中的值,只需改变调色板的颜色项就可快速地改变一幅图象的颜色或灰度。</p>
<p align="JUSTIFY"> 在DOS中,调色板的使用不会有什么问题。由于DOS是一个单任务操作系统,一次只能运行一个程序,因此程序可以独占调色板。在Windows环境下,情况就不那么简单了。Windows是一个多任务操作系统,可以同时运行多个程序。如果有几个程序都要设置调色板,就有可能产生冲突。为了避免这种冲突,Windows使用逻辑调色板来作为使用颜色的应用程序和系统调色板(物理调色板)之间的缓冲。</p>
<p align="center"><img src="T11_1.gif" alt="T11_1.tif (194188 bytes)" width="520" height="282"></p>
<p align="center">图11.1 调色板工作原理</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY"> 在Windows中,应用程序是通过一个或多个逻辑调色板来使用系统调色板(物理调色板)。在256色系统调色板中,Windows保留了20种颜色作为静态颜色,这些颜色用作显示Windows界面,应用程序一般不能改变。缺省的系统调色板只包含这20种静态颜色,调色板的其它项为空。应用程序要想使用新的颜色,必须将包含有所需颜色的逻辑调色板实现到系统调色板中。在实现过程中,Windows首先将逻辑调色板中的项与系统调色板中的项作完全匹配,对于逻辑调色板中不能完全匹配的项,Windows将其加入到系统调色板的空白项中,系统调色板总共有236个空白项可供使用,若系统调色板已满,则Windows将逻辑调色板的剩余项匹配到系统调色板中尽可能接近的颜色上。</p>
<p align="JUSTIFY"> 每个设备上下文都拥有一个逻辑调色板,缺省的逻辑调色板只有20种保留颜色,如果要使用新的颜色,则应该创建一个新的逻辑调色板并将其选入到设备上下文中。但光这样还不能使用新颜色,程序只有把设备上下文中的逻辑调色板实现到系统调色板中,新的颜色才能实现。在逻辑调色板被实现到系统调色板时,Windows会建立一个调色板映射表。当设备上下文用逻辑调色板中的颜色绘图时,GDI绘图函数会查询调色板映射表以把像素值从逻辑调色板的索引转换成系统调色板的索引,这样当像素被输出到视频内存中时就具有了正确的颜色值。图11.2说明了这种映射关系,从图中读者可以体会到逻辑调色板的缓冲作用。在该图中,GDI绘图函数使用逻辑调色板的索引1中的颜色来绘图,通过查询调色板映射表,得知系统调色板中的第23号索引与其完全匹配,这样实际输出到视频内存中的像素值是23。注意图中还演示了颜色的不完全匹配,即逻辑调色板中的索引15和系统调色板中的索引46。</p>
<p align="JUSTIFY"> 每个要使用额外颜色的窗口都会实现自己的逻辑调色板,逻辑调色板中的每种颜色在系统调色板中都有相同或相近的匹配。调色板的实现优先权越高,匹配的精度也就越高。Windows规定,活动窗口的逻辑调色板(如果有的话)具有最高的实现优先权。这是因为活动窗口是当前与用户交互的窗口,应该保证其有最佳的颜色显示。非活动窗口的优先权是按Z顺序自上到下确定的(Z顺序就是重叠窗口的重叠顺序)。活动窗口有权将其逻辑调色板作为前景调色板实现,非活动窗口则只能实现背景调色板。</p>
<div align="center">
<center>
<table border="2" cellpadding="2" cellspacing="0" width="100%" bgcolor="#55C8FF">
<tr>
<td width="100%"> <b></b>提示:术语活动窗口(Active window)或前台窗口(Foreground
window)是指当前与用户交互的窗口,活动窗口的顶端的标题条呈高亮显示,而非活动窗口的标题条则是灰色的。活动窗口肯定是一个顶层窗口(Top-level
window),顶层窗口是指没有父窗口或父窗口是桌面窗口的窗口,这种窗口一般都有标题和边框,主要包括框架窗口和对话框。术语重叠窗口是指作为应用程序主窗口的窗口,我们可以把对话框看成是一种特殊的重叠式窗口。</td>
</tr>
</table>
</center>
</div>
<p align="JUSTIFY"><b> </b></p>
<p align="center"> <b></b><img src="T11_2.gif" alt="T11_2.tif (192888 bytes)" width="520" height="303"></p>
<p align="center">图11.2 调色板的映射关系</p>
<b>
<p align="JUSTIFY"> </p>
</b>
<p align="JUSTIFY"><b></b><font color="#3973DE" face="Times New Roman" size="3">11.1.2
</font><font size="3" color="#3973DE">调色板的创建和实现</font></p>
<p align="JUSTIFY">MFC的CPalette类对逻辑调色板进行了封装。该类的成员函数CreatePalette负责创建逻辑调色板,该函数的声明为:</p>
<blockquote>
<blockquote>
<blockquote>
<p align="JUSTIFY">BOOL CreatePalette( LPLOGPALETTE lpLogPalette
); //成功则返回TRUE。</p>
</blockquote>
</blockquote>
</blockquote>
<p align="JUSTIFY">参数lpLogPalette是一个指向LPLOGPALETTE结构的指针,LPLOGPALETTE结构描述了逻辑调色板的内容,该结构的定义为:</p>
<blockquote>
<p align="JUSTIFY">typedef struct tagLOGPALETTE { </p>
<p align="JUSTIFY">WORD palVersion; //Windows版本号,一般是0x300</p>
<p align="JUSTIFY">WORD palNumEntries; //调色板中颜色表项的数目</p>
<p align="JUSTIFY">PALETTEENTRY palPalEntry[1]; //每个表项的颜色和使用方法</p>
<p align="JUSTIFY">} LOGPALETTE;</p>
</blockquote>
<p align="JUSTIFY"> 结构中最重要的成员是PALETTEENTRY数组,数组项的数目由palNumEntries成员指定。PALETTEENTRY结构对调色板的某一个颜色表项进行了描述,该结构的定义为:</p>
<blockquote>
<p align="JUSTIFY">typedef struct tagPALETTEENTRY {</p>
<p align="JUSTIFY">BYTE peRed; //红色的强度(0~255,下同)</p>
<p align="JUSTIFY">BYTE peGreen; //绿色的强度</p>
<p align="JUSTIFY">BYTE peBlue; //蓝色的强度</p>
<p align="JUSTIFY">BYTE peFlags; </p>
<p align="JUSTIFY">} PALETTEENTRY;</p>
</blockquote>
<p align="JUSTIFY"> 成员peFlags说明了颜色表项的使用方法,在一般应用时为NULL,若读者对peFlags的详细说明感兴趣,可以查看Visual
C++的联机帮助。</p>
<p align="JUSTIFY"> 可以看出,创建调色板的关键是在PALETTEENTRY数组中指定要使用的颜色。这些颜色可以是程序自己指定的特殊颜色,也可以从DIB位图中载入。逻辑调色板的大小可根据用户使用的颜色数来定,一般不能超过256个颜色表项。</p>
<p align="JUSTIFY"> CreatePalette只是创建了逻辑调色板,此时调色板只是一张孤立的颜色表,还不能对系统产生影响。程序必需调用CDC::SelectPalette把逻辑调色板选入到要使用它的设备上下文中,然后调用CDC::RealizePalette把逻辑调色板实现到系统调色板中。函数的声明为:</p>
<blockquote>
<blockquote>
<p align="JUSTIFY">CPalette* SelectPalette( CPalette* pPalette,
BOOL bForceBackground );<br>
该函数把指定的调色板选择到设备上下文中。参数pPalette指向一个CPalette对象。参数bForceBackground如果是TRUE,那么被选择的调色板总是作为背景调色板使用,如果bForceBackground是FALSE并且设备上下文是附属于某个窗口的,那么当窗口是活动窗口或活动窗口的子窗口时,被选择的调色板将作为前景调色板实现,否则作为背景调色板实现。如果使用调色板的是一个内存设备上下文,则该参数被忽略。函数返回设备上下文原来使用的调色板,若出错则返回NULL。</p>
<p align="JUSTIFY">UINT RealizePalette( );<br>
该函数把设备上下文中的逻辑调色板实现到系统调色板中。函数的返回值表明调色板映射表中有多少项被改变了。</p>
</blockquote>
</blockquote>
<p> </p>
<p align="JUSTIFY"> 如果某一个窗口要显示特殊的颜色,那么一般应该在处理WM_PAINT消息时实现自己的逻辑调色板。也就是说,在OnPaint或OnDraw函数中重绘以前,要调用SelectPalette和RealizePalette。如果窗口显示的颜色比较重要,则在调用SelectPalette时应该指定bForceBackground参数为FALSE。</p>
<p align="JUSTIFY"> 前景调色板具有使用颜色的最高优先级,它有无条件占用系统调色板(20种保留颜色除外)的权力,也就是说,如果需要,前景调色板将覆盖系统调色板的236个表项,而不管这些表项是否正被别的窗口使用。背景调色板则无权破坏系统调色板中的已使用项。</p>
<p align="JUSTIFY"> 请读者注意,前景调色板应该是唯一。如果一个活动窗口同时要实现几个逻辑调色板,那么只能有一个调色板作为前景调色板实现,也即在调用CDC::SelectPalette时只能有一个bForceBackground被指定为FALSE,其它的bForceBackground必需为TRUE。通常是把具有输入焦点的窗口的调色板作为前景调色板实现,其它窗口只能使用背景调色板。如果活动窗口的子窗口全都使用前景调色板,则会导致程序的死循环。</p>
<div align="center">
<center>
<table border="2" cellpadding="2" cellspacing="0" width="100%" bgcolor="#71D0FF">
<tr>
<td width="100%"> <b></b>提示:请读者注意区分活动窗口和有输入焦点的窗口。有输入焦点的窗口要么是活动窗口本身,要么是活动窗口的子窗口。也就是说,活动窗口不一定具有输入焦点,当活动窗口的子窗口获得输入焦点时,活动窗口就会失去输入焦点。</td>
</tr>
</table>
</center>
</div>
<p><b> </b></p>
<p align="JUSTIFY"> <b></b><font color="#3973DE" face="Times New Roman" size="3">11.1.3
</font><font size="3" color="#3973DE">使用颜色的三种方法</font></p>
<p align="JUSTIFY"> 在调用GDI函数绘图时,可以用不同的方法来选择颜色。Windows用COLORREF数据类型来表示颜色,COLORREF型值的长度是4字节,其中最高位字节可以取三种不同的值,分别对应三种使用颜色的方法。表11.1列出了这些不同的取值及其含义。</p>
<p align="JUSTIFY"><b> </b></p>
<p align="CENTER"> <b>表11.1 </b>COLORREF型值的最高位字节的含义</p>
<table border="1" cellspacing="1" cellpadding="1" width="579">
<tr>
<td width="16%"><b>
<p align="JUSTIFY">取值
</b></td>
<td width="84%"><b>
<p align="JUSTIFY">含义
</b></td>
</tr>
<tr>
<td width="16%">
<p align="JUSTIFY">0x00
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -