Windows 调色板
目录
第1章调色板
1.1 为什么要使用调色板
如果设置显示器的颜色为256色,如下图所示。那么就意味着:虽然显示器能显示的颜色数可能超过256个,但是显示一帧画面的颜色数最多只能达到256个。

图1.1
直接看下图的程序显示效果:

图1.2
上图有两个16×16的红色方阵。红色分量由0至255逐渐加大。
左边的方阵使用了调色板,颜色相对比较平滑;
右边的方阵未使用调色板,颜色抖动得比较厉害。
所以:在256色显示器上使用调色板是为了获得最好的显示效果。
1.2 使用调色板
使用调色板是很简单的。记住四个函数CreatePalette、SelectPalette、RealizePalette、DeleteObject,一个宏PALETTEINDEX就可以使用调色板了。
上图(图1.2)是一个MFC对话框程序的显示截图。下面对其代码进行说明。
首先给对话框类增加成员变量HPALETTE m_hPalette,如下所示。它表示一个逻辑调色板。
|
class CDlgPalDlg : public CDialog { ... ... ... protected: HPALETTE m_hPalette; }; |
1.2.1 创建逻辑调色板
在CDlgPalDlg的构造函数里,调用CreatePalette函数创建逻辑调色板。具体代码如下:
|
CDlgPalDlg::CDlgPalDlg(CWnd* pParent /*=NULL*/) : CDialog(CDlgPalDlg::IDD, pParent) { LPLOGPALETTE pLogPal = (LPLOGPALETTE)malloc( sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 256); pLogPal->palVersion = 0x300; pLogPal->palNumEntries = 256; for(int i = 0;i < 256;i++) { pLogPal->palPalEntry[i].peRed = i; pLogPal->palPalEntry[i].peGreen = 0; pLogPal->palPalEntry[i].peBlue = 0; pLogPal->palPalEntry[i].peFlags = 0; } m_hPalette = CreatePalette(pLogPal); free(pLogPal); } |
说明:
1、代码 pLogPal->palNumEntries = 256;说明逻辑调色板里有256个颜色。一个逻辑调色板最多也只能有256个颜色;
2、for循环给每个颜色设置R、G、B分量。可以代码里只设置了红色分量,绿、蓝分量都是零。
1.2.2 使用
在对话框窗口绘制函数CDlgPalDlg::OnPaint里用到了逻辑调色板。具体代码如下:
|
void CDlgPalDlg::OnPaint() { CPaintDC dc(this); HBRUSH hBrush = NULL; HGDIOBJ hBrushOld = NULL; int x,y,i; dc.SelectStockObject(BLACK_PEN); {//使用调色板绘制左边的红色方阵 SelectPalette(dc.m_hDC,m_hPalette,FALSE); RealizePalette(dc.m_hDC); for(i = 0;i < 256;i++) { x = (i % 16) * 16; y = (i / 16) * 16; hBrush = CreateSolidBrush(PALETTEINDEX(i)); hBrushOld = SelectObject(dc.m_hDC,hBrush); dc.Rectangle(x,y,x+16,y+16); dc.SelectObject(hBrushOld); DeleteObject(hBrush); } } {/不使用调色板绘制右边的红色方阵 for(i = 0;i < 256;i++) { x = (i % 16) * 16 + 300; y = (i / 16) * 16; hBrush = CreateSolidBrush(RGB(0,0,i)); hBrushOld = SelectObject(dc.m_hDC,hBrush); dc.Rectangle(x,y,x+16,y+16); dc.SelectObject(hBrushOld); DeleteObject(hBrush); } } } |
说明:
1、SelectPalette(dc.m_hDC,m_hPalette,FALSE); 把逻辑调色板选入对话框客户区的dc。第三个参数非常重要,随后再做详细说明;
2、RealizePalette(dc.m_hDC);根据逻辑调色板中的颜色修改系统调色板。这个函数还有更多的技术细节,随后再做详细说明;
3、hBrush = CreateSolidBrush(PALETTEINDEX(i)); 创建一个刷子,注意它的颜色是PALETTEINDEX(i),表示使用调色板里的第i个颜色;
4、绘制右边的红色方阵时,创建的刷子是hBrush = CreateSolidBrush(RGB(0,0,i));即直接使用RGB颜色,而非调色板中的颜色索引。
1.2.3 销毁逻辑调色板
在CDlgPalDlg的析构函数里,调用DeleteObject函数销毁逻辑调色板。具体代码如下:
|
CDlgPalDlg::~CDlgPalDlg() { if(m_hPalette) { DeleteObject(m_hPalette); m_hPalette = NULL; } } |
1.3 系统调色板
上一节说到RealizePalette函数会根据逻辑调色板中的颜色修改系统调色板。假定有两个程序都调用了它,都去修改系统调色板,会出现什么情况?
对上一节的程序稍加修改,就可以使用调色板绘制一个蓝色的方阵。现在同时运行这两个程序,看看什么效果。
绘制红色方阵的程序(以下简称程序R)获得焦点时的显示如下。红色方阵显示非常好,蓝色方阵的显示似乎只用到了三种颜色。

图1.3
绘制蓝色方阵的程序(以下简称程序B)获得焦点时的显示如下。蓝色方阵显示非常好,红色方阵的显示似乎只用到了三种颜色。

图1.4
这些说明:
1、系统调色板是独占资源。一个程序调用RealizePalette函数修改系统调色板后,其它程序都会受到影响;
2、系统调色板里保留了20种颜色,这20种颜色无法被修改。所以程序R调用RealizePalette函数修改系统调色板时只修改了236种颜色,此时程序B显示的颜色其实是被保留的颜色;
3、RealizePalette函数修改系统调色板的条件:一是它的参数hdc必须是屏幕或窗口DC,而不能是打印机、内存DC;二是SelectPalette(hdc,m_hPalette,FALSE)的第三个参数必须为FALSE;三是程序的主窗口必须获得了焦点。
程序R获得焦点的时候,它代码里的RealizePalette函数可以修改系统调色板,此时程序B未获得焦点,它代码里的RealizePalette函数就无法修改系统调色板。
1.4 调色板消息
因为系统调色板是独占资源,因此需要调色板消息协调各个程序对调色板的使用。需要注意:显示器的颜色为256色时,以下消息才会有效。
1.4.1 WM_QUERYNEWPALETTE
当程序主窗口获得焦点时,系统会给这个主窗口发送WM_QUERYNEWPALETTE消息。它的含义是询问程序是否修改了系统调色板?此时有两种回应:
没有修改系统调色板,直接返回FALSE。代码如下:
|
BOOL CDlgPalDlg::OnQueryNewPalette() { return FALSE; } |
修改了系统调色板,返回TRUE。代码如下:
|
BOOL CDlgPalDlg::OnQueryNewPalette() { CClientDC dc(this); SelectPalette(dc.m_hDC,m_hPalette,FALSE); RealizePalette(dc.m_hDC); return TRUE; } |
1.4.2 WM_PALETTECHANGED
当系统调色板被修改后,系统会给所有主窗口发送WM_PALETTECHANGED消息。它通知程序系统调色板被修改了,请做相应的处理。
下面的处理很简单,调用Invalidate函数,重新绘制。
|
void CDlgPalDlg::OnPaletteChanged(CWnd* pFocusWnd) { CDialog::OnPaletteChanged(pFocusWnd); Invalidate(); } |
还可以使用WM_PALETTECHANGED的WPARAM参数(被MFC改成了CWnd*pFocusWnd,pFocusWnd->m_hWnd就是原始的WPARAM参数)。代码如下:
|
void CDlgPalDlg::OnPaletteChanged(CWnd* pFocusWnd) { CDialog::OnPaletteChanged(pFocusWnd); if(pFocusWnd->m_hWnd != m_hWnd) { Invalidate(); } } |
CDlgPalDlg接收到的WM_PALETTECHANGED消息有两种来源:一是其它程序修改了系统调色板;另一个是自身代码里的RealizePalette(dc.m_hDC);对于后一种情况pFocusWnd->m_hWnd 等于m_hWnd,上面代码的Invalidate();不会被执行,窗口也不会重绘。
1.4.3 小心死循环
调用RealizePalette函数会修改系统调色板,会触发WM_PALETTECHANGED消息。如果处理WM_PALETTECHANGED消息时再次调用RealizePalette函数修改系统调色板,就会再次触发WM_PALETTECHANGED消息……如此一来就陷入死循环了。
分析下面的代码:
|
void CDlgPalDlg::OnPaletteChanged(CWnd* pFocusWnd) { CDialog::OnPaletteChanged(pFocusWnd); Invalidate(); } void CDlgPalDlg::OnPaint() { CPaintDC dc(this); SelectPalette(dc.m_hDC,m_hPalette,FALSE); RealizePalette(dc.m_hDC); } |
窗口第一次绘制时会调用RealizePalette,它很可能会修改系统调色板,这样就会调用CDlgPalDlg::OnPaletteChanged里的Invalidate再次重绘。
第二次绘制时仍会调用RealizePalette。因为第一次调用已经修改系统调色板了,系统调色板的颜色与逻辑调色板的颜色已经保持一致了。再次调用RealizePalette不会再修改系统调色板,也就不会再调用CDlgPalDlg::OnPaletteChanged里的Invalidate了。
所以,上述只使用一个逻辑调色板的代码是不会陷入死循环的。
再分析下面的代码:
|
void CDlgPalDlg::OnPaletteChanged(CWnd* pFocusWnd) { CDialog::OnPaletteChanged(pFocusWnd); Invalidate(); } void CDlgPalDlg::OnPaint() { CPaintDC dc(this); SelectPalette(dc.m_hDC,m_hPalRed,FALSE); //选用红色调色板 RealizePalette(dc.m_hDC); {//绘制红色方阵 ... ... ... } SelectPalette(dc.m_hDC,m_hPalBlue,FALSE); //选用蓝色调色板 RealizePalette(dc.m_hDC); {//绘制蓝色方阵 ... ... ... } } |
CDlgPalDlg::OnPaint函数里首先选用红色调色板绘制红色方阵,然后选用蓝色调色板绘制蓝色方阵。结果就是两个RealizePalette都会修改系统调色板,都会触发WM_PALETTECHANGED消息,都会导致Invalidate被调用,都会导致CDlgPalDlg::OnPaint被再次执行……由此陷入了死循环。
所以,程序里如果有多个逻辑调色板,必须保证只有一个是前景调色板,即调用SelectPalette函数选用这个调色板时第三个参数为FALSE;其它调色板必须为背景调色板,即调用SelectPalette函数选用其它调色板时第三个参数为TRUE。
系统调色板的独占使用是这样实现的:调用RealizePalette函数时,焦点所在程序的前景调色板可能会修改系统调色板,背景调色板以及未获得焦点的前景调色板不会修改系统调色板。
Windows 调色板的更多相关文章
- Windows DIB文件操作具体解释-5.DIB和调色板
Windows调色板是256色显卡时期的产物,如今显卡最少也是16bit的了.所以调色板基本上是用不到了的. 可是以下几种情况还是须要去使用和了解调色板: 1.在新显卡上保证256色兼容模式的正常执行 ...
- Windows API 的数据类型与 Delphi 数据类型对照表
Windows 数据类型 Delphi 数据类型 描述 LPSTR PAnsiChar 字符串指针 LPCSTR PAnsiChar 字符串指针 DWORD LongWord 整数 BOOL Long ...
- 【转载】Windows api数据类型
最近在接触windows api函数,看到了很多之前没有看到过的数据类型,发现“个人图书馆”中有个帖子说的挺详细的,特地搬运过来 Windows 数据类型 Delphi 数据类型 描述 LPSTR P ...
- Clipboard获取内容C#
一.获取文本 textBox1.Text = Clipboard.GetData("Text").ToString(); 二.获取图像 pictureBo ...
- 调色板类QPalette——包含了Qt窗口不见的颜色组(collor group),和Windows右键属性外观非常类似
QPalette类包含了Qt窗口不见的颜色组(collor group); 1.Active组,该组的颜色用户当前活动的(active)窗口,即具有键盘或鼠标焦点的窗口; 2.Inactive组,该组 ...
- Windows API 函数列表 附帮助手册
所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...
- windows消息机制详解(转载)
消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键都会使Windows发送一个消息给应用程序.消息本身是作为一个记录传递给应用程序的 ...
- Windows编程入门程序详解
引用:http://blog.csdn.net/jarvischu/article/details/8115390 1. 程序 /******************************* ...
- Windows消息大全(转)
原链接地址: http://www.cnblogs.com/icebutterfly/archive/2011/08/05/2128864.html 表A-1 Windows消息分布 消息范围说 明 ...
随机推荐
- DLL学习笔记一(DLL导入导出)
创建DLL: 先声明导出函数:使用__declspec(dllexport) #include"DLLSample.h" #ifndef _DLL_SAMPLE_H #define ...
- WebForm分页浏览
1.封装类 //封装类 using System; using System.Collections.Generic; using System.Web; /// <summary> // ...
- [转载]单元测试之道(使用NUnit)
首先来看下面几个场景你是否熟悉 1.你正在开发一个系统,你不断地编码-编译-调试-编码-编译-调试……终于,你负责的功能模块从上到下全部完成且编译通过!你长出一口气,怀着激动而又忐忑的心情点击界面上的 ...
- JQuery增删改查
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- C#借助谷歌翻译实现翻译小工具(二)添加托盘图标
接上一节完善小翻译工具 设置Form的ShowInTaskbar属性为False,取消任务栏显示 设置Form的MaximizeBox属性为False,取消最大化显示 窗口添加两个控件 分别是:Con ...
- thinkphp的自动完成功能说明
手册里有一句话很关键: 自动完成是ThinkPHP提供用来完成数据自动处理和过滤的方法,使用create方法创建数据对象的时候会自动完成数据处理. 这句话说明自动完成发生的时间是create()组建数 ...
- Know How To Use Check Box Mapping Of Other Values Property In Oracle Forms
Check Box Mapping of Other Values specifies how any fetched or assigned value that is not one of the ...
- virtualenv -- python虚拟沙盒(linux版本)
有人说:virtualenv.fabric 和 pip 是 pythoneer 的三大神器. 不管认不认同,至少要先认识一下,pip现在倒是经常用到,virtualenv第一次听说,不过,总得尝试一下 ...
- git泄漏原理
之前做过git的加固 但是这东西还是没办法避免的 之前看了乌云的提交的git泄漏,但是都没有详细的原理,去了lijiejie的博客(字太难打了,大师傅别打我 哈哈) 如果一个网站存在git泄漏,git ...
- poj 1696 Space Ant (极角排序)
链接:http://poj.org/problem?id=1696 Space Ant Time Limit: 1000MS Memory Limit: 10000K Total Submissi ...