目录

第1章调色板    1

1.1 为什么要使用调色板    1

1.2 使用调色板    2

1.2.1 创建逻辑调色板    2

1.2.2 使用    3

1.2.3 销毁逻辑调色板    4

1.3 系统调色板    5

1.4 调色板消息    6

1.4.1 WM_QUERYNEWPALETTE    6

1.4.2 WM_PALETTECHANGED    7

1.4.3 小心死循环    8

第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 调色板的更多相关文章

  1. Windows DIB文件操作具体解释-5.DIB和调色板

    Windows调色板是256色显卡时期的产物,如今显卡最少也是16bit的了.所以调色板基本上是用不到了的. 可是以下几种情况还是须要去使用和了解调色板: 1.在新显卡上保证256色兼容模式的正常执行 ...

  2. Windows API 的数据类型与 Delphi 数据类型对照表

    Windows 数据类型 Delphi 数据类型 描述 LPSTR PAnsiChar 字符串指针 LPCSTR PAnsiChar 字符串指针 DWORD LongWord 整数 BOOL Long ...

  3. 【转载】Windows api数据类型

    最近在接触windows api函数,看到了很多之前没有看到过的数据类型,发现“个人图书馆”中有个帖子说的挺详细的,特地搬运过来 Windows 数据类型 Delphi 数据类型 描述 LPSTR P ...

  4. Clipboard获取内容C#

    一.获取文本  textBox1.Text = Clipboard.GetData("Text").ToString(); 二.获取图像             pictureBo ...

  5. 调色板类QPalette——包含了Qt窗口不见的颜色组(collor group),和Windows右键属性外观非常类似

    QPalette类包含了Qt窗口不见的颜色组(collor group); 1.Active组,该组的颜色用户当前活动的(active)窗口,即具有键盘或鼠标焦点的窗口; 2.Inactive组,该组 ...

  6. Windows API 函数列表 附帮助手册

    所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...

  7. windows消息机制详解(转载)

    消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键都会使Windows发送一个消息给应用程序.消息本身是作为一个记录传递给应用程序的 ...

  8. Windows编程入门程序详解

    引用:http://blog.csdn.net/jarvischu/article/details/8115390 1.     程序 /******************************* ...

  9. Windows消息大全(转)

    原链接地址: http://www.cnblogs.com/icebutterfly/archive/2011/08/05/2128864.html 表A-1 Windows消息分布 消息范围说 明 ...

随机推荐

  1. 学习java annotation

    Annotation介绍 内置注解 自定义注解 元注解 /** * 测试自定义注解的使用 * */ @SxtAnnotation01 public class Demo02 { @Annotation ...

  2. NSIS学习记录の----win8.1和win10对于NSIS创建的卸载快捷方式无法在开始目录下显示

    NSIS提供了很好的软件卸载功能编写的方法,但是针对win8.1和win10操作系统,由于开始目录的权限限制,我们有时候并不能完美的完成所需要的功能----卸载程序的快捷方式不能显示.话不多说,下面提 ...

  3. ViewState

    ViewState就像一个记录本,由于WebFormd的无状态性,刷新了页面.那么这个页面就和上一个页面没有任何关系了.为了使刷新前的页面和本页面产生联系,ViewState的作用就是记录刷新前页面的 ...

  4. C语言中的二维数组和数组指针的那些事

    其实很多人就想弄明白这个定义了的数组指针里面赋值给的a究竟是什么 a是一个列地址,那么*a是什么,*a还是个地址它存储了行地址.如果我们定义一个指针,那他就有点二级指针的味道.因为它存储的是一个地址, ...

  5. 如何用linux远程登录windows计算机

    大家可能试过用windows远程登录另一个windows pc机,今天大家将会学到如何用 linux远程登录你的windows系统. 首先大家要做到得救是将自己linux和windows操作机的IP地 ...

  6. CodeForces 527B Error Correct System

    Error Correct System Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I6 ...

  7. 【转载】CMake 简介和 CMake 模板

    转载自我的博客: CMake 简介和 CMake 模板 . 如果你用 Linux 操作系统,使用 cmake 会简单很多,可以参考一个很好的教程: CMake 入门实战 | HaHack .如果你用 ...

  8. R 给data.frame(dataframe)添加一列

    x<-data.frame(apple=c(1,4,2,3),pear=c(4,8,5,2)) x # apple pear # 1 1 4 # 2 4 8 # 3 2 5 # 4 3 2 x$ ...

  9. 长链非编码RNA(lncRNA)

    长链非编码RNA(lncRNA) 转自:http://blog.sina.com.cn/s/blog_909da11301010bkz.html     长链非编码RNA(lncRNA)是一类转录本长 ...

  10. shell脚本批量ping测试IP是否通

    #!/bin/bash rm -f result.txt cat ip.txt | fping > result.txt 2行代码就搞定,很方便,初学shell,很强大,问了下同事,但是shel ...