16. 调色盘管理器.txt
来自「本书介绍了在Microsoft Windows 98、Microsoft Win」· 文本 代码 · 共 1,827 行 · 第 1/5 页
TXT
1,827 行
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{
static HPALETTE hPalette ;
static int cxClient, cyClient ;
HBRUSH hBrush ;
HDC hdc ;
int i ;
LOGPALETTE * plp ;
PAINTSTRUCT ps ;
RECT rect ;
switch (message)
{
case WM_CREATE:
// Set up a LOGPALETTE structure and create a palette
plp = malloc (sizeof (LOGPALETTE) + 64 * sizeof (PALETTEENTRY)) ;
plp->palVersion = 0x0300 ;
plp->palNumEntries = 65 ;
for (i = 0 ; i < 65 ; i++)
{
plp->palPalEntry[i].peRed = (BYTE) min (255, 4 * i) ;
plp->palPalEntry[i].peGreen = (BYTE) min (255, 4 * i) ;
plp->palPalEntry[i].peBlue = (BYTE) min (255, 4 * i) ;
plp->palPalEntry[i].peFlags = 0 ;
}
hPalette = CreatePalette (plp) ;
free (plp) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
// Select and realize the palette in the device context
SelectPalette (hdc, hPalette, FALSE) ;
RealizePalette (hdc) ;
// Draw the fountain of grays
for (i = 0 ; i < 65 ; i++)
{
rect.left = i * cxClient / 64 ;
rect.top = 0 ;
rect.right = (i + 1) * cxClient / 64 ;
rect.bottom = cyClient ;
hBrush = CreateSolidBrush (PALETTEINDEX (i)) ;
FillRect (hdc, &rect, hBrush) ;
DeleteObject (hBrush) ;
}
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_QUERYNEWPALETTE:
if (!hPalette)
return FALSE ;
hdc = GetDC (hwnd) ;
SelectPalette (hdc, hPalette, FALSE) ;
RealizePalette (hdc) ;
InvalidateRect (hwnd, NULL, FALSE) ;
ReleaseDC (hwnd, hdc) ;
return TRUE ;
case WM_PALETTECHANGED:
if (!hPalette || (HWND) wParam == hwnd)
break ;
hdc = GetDC (hwnd) ;
SelectPalette (hdc, hPalette, FALSE) ;
RealizePalette (hdc) ;
UpdateColors (hdc) ;
ReleaseDC (hwnd, hdc) ;
break ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
「调色盘」索引的颜色不同于调色盘RGB颜色,其高字节是1,而低字节的值是目前在设备内容中选择的、逻辑调色盘中的索引。在GRAYS3中,逻辑调色盘有65个项目,用于这些项目的索引从0到64。值
PALETTEINDEX (0)
指黑色,
PALETTEINDEX (32)
指灰色,而
PALETTEINDEX (64)
指白色。
因为Windows不需要执行最近颜色的搜索,所以使用调色盘索引比使用RGB值更有效。
查询调色盘支持
您可以容易地验证:当Windows在16位或24位显示模式下执行时,GRAYS2和GRAYS3程序执行良好。但是在某些情况下,要使用调色盘管理器的Windows应用程序可能要先确定设备驱动程序是否支持它。这时,您可以呼叫GetDeviceCaps,并以视讯显示的设备内容句柄和PASTERCAPS作为参数。函数将传回由一系列旗标组成的整数。通过在传回值和常数RC_PALETTE之间执行位操作来检验支持的调色盘:
RC_PALETTE & GetDeviceCaps (hdc, RASTERCAPS)
如果此值非零,则视讯显示器设备驱动程序将支持调色盘操作。在这种情况之下,来自GetDeviceCaps的其它三个重要项目也是可用的。函数呼叫
GetDeviceCaps (hdc, SIZEPALETTE)
将传回在显示卡上调色盘表的总尺寸。这与同时显示的颜色总数相同。因为调色盘管理器只用于每图素8位的视讯显示模式,所以此值将是256。
函数呼叫
GetDeviceCaps (hdc, NUMRESERVED)
传回在调色盘表中的颜色数,该表是设备驱动程序为系统保留的,此值是20。不呼叫调色盘管理器,这些只是Windows应用程序在256色显示模式下使用的纯色。要使用其余的236种颜色,程序必须使用调色盘管理器函数。
一个附加项目也可用:
GetDeviceCaps (hdc, COLORRES)
此值告诉您加载到硬件调色盘表的RGB颜色值分辨率(以位计)。这些是进入数字模拟转换器的位。某些视讯显示卡只使用6位ADC,所以该值是18。其余使用8位的ADC,所以值是24。
Windows程序注意颜色分辨率并因此采取一些动作是很有用的。例如,如果该颜色分辨率是18,那么程序将不可能要求到128种灰阶,因为只有64个离散的灰阶可用。要求到128种灰阶就不必用多余的项目来填充硬件调色盘表。
系统调色盘
我在前面提过,Windows系统调色盘直接与显示卡上的硬件调色盘查询表相符(然而,硬件调色盘查询表可能比系统调色盘的颜色分辨率低)。程序可以通过呼叫下面的函数来获得系统调色盘中的某些或全部的RGB项目:
GetSystemPaletteEntries (hdc, uStart, uNum, &pe) ;
只有显示卡模式支持调色盘操作时,该函数才能执行。第二个和第三个参数是无正负号整数,显示第一个调色盘项目的索引和调色盘项目数。最后一个参数是指向PALETTEENTRY型态的指针。
您可以在几种情况下使用该函数。程序可以定义PALETTEENTRY结构如下:
PALETTEENTRY pe ;
然后可按下面的方法多次呼叫GetSystemPaletteEntries:
GetSystemPaletteEntries (hdc, i, 1, &pe) ;
其中的i从0到某个值,该值小于从GetDeviceCaps(带有SIZEPALETTE索引255)传回的值。或者,程序要获得所有的系统调色盘项目,可以通过定义指向PALETTEENTRY结构的指针,然后重新配置足够的内存块,以储存与调色盘大小指定同样多的PALETTEENTRY结构。
GetSystemPaletteEntries函数确实允许您检验硬件调色盘表。系统调色盘中的项目按图素值增加的顺序排列,这些值用于表示视讯显示缓冲区中的颜色。我将简单地讨论一下具体作法。
其它调色盘函数
我们在前面看过,Windows程序能够改变系统调色盘,但只是间接改变:第一步建立逻辑调色盘,它基本上是程序要使用的RGB颜色值数组。CreatePalette函数不会导致系统调色盘或者显示卡调色盘表的任何变化。逻辑调色盘必须在任何事情发生之前就选进设备内容并显现。
程序可以通过呼叫
GetPaletteEntries (hPalette, uStart, uNum, &pe) ;
来查询逻辑调色盘中的RGB颜色值。您可以按使用GetSystemPaletteEntries的方法来使用此函数。但是要注意,第一个参数是逻辑调色盘的句柄,而不是设备内容的句柄。
建立逻辑调色盘以后,让您改变其中的值的相应函数是:
SetPaletteEntries (hPalette, uStart, uNum, &pe) ;
另外,记住呼叫此函数不引起系统调色盘的任何变化-即使目前调色盘选进了设备内容。此函数也不改变逻辑调色盘的尺寸。要改变逻辑调色盘的尺寸,请使用ResizePalette。
下面的函数接受RGB颜色引用值作为最后的参数,并将索引传回给逻辑调色盘,该逻辑调色盘与和它最接近的RGB颜色值相对应:
iIndex = GetNearestPaletteIndex (hPalette, cr) ;
第二个参数是COLORREF值。如果希望的话,呼叫GetPaletteEntries就可以获得逻辑调色盘中实际的RGB颜色值。
如果程序在8位显示模式下需要多于236种自订颜色,则可以呼叫GetSystemPaletteUse。这允许程序设定254种自订颜色;系统仅保留黑色和白色。不过,程序仅在最大化充满全屏幕时才允许这样,而且它还将一些系统颜色设为黑色和白色,以便标题列和菜单等仍然可见。
位映像操作问题
从第五章可以了解到,GDI允许使用不同的「绘画模式」或「位映像操作」来画线并填充区域。用SetROP2设定绘画模式,其中的「2」表示两个对象之间的二元(binary)位映像操作。三元位映像操作用于处理BitBlt和类似功能。这些位映像操作决定了正在画的对象图素与表面图素的结合方式。例如,您可以画一条直线,以便在线的图素与显示的图素按位异或的方式相结合。
位映像操作就是在图素位上照着各个位的顺序进行操作。改变调色盘会影响到这些位映像操作。位映像操作的操作对象是图素位,而这些图素位可能与实际颜色没有关联。
透过执行GRAYS2或GRAYS3程序,您自己就可以得出这个结论。调整尺寸时,拖动顶部或底部的边界穿过窗口,Windows利用反转背景图素位的位映像操作来显示拖动尺寸的边界,其目的是使拖动尺寸边界总是可见的。但在GRAYS2和GRAYS3程序中,您将看到各种随机变换的颜色,这些颜色恰好与对应于调色盘表中未使用的项目,那是反转显示图素位的结果。可视颜色没有反转-只有图素位反转了。
正如您在表16-1中所看到的一样,20种标准保留颜色位于系统调色盘的顶部和底部,以便位映像操作的结果仍然正常。然而,一旦您开始修改调色盘-尤其是替换了保留颜色-那么颜色对象的位映像操作就变得没有意义了。
唯一保证的是位映像操作将用黑色和白色运作。黑色是系统调色盘中的第一个项目(所有的图素位都设为0),而白色是最后的项目(所有的图素位都设为1)。这两个项目不能改变。如果需要预知在颜色对象上进行位映像操作的结果,则可以先获得系统调色盘表,然后查看不同图素位值的RGB颜色值。
查看系统调色盘
在Windows下执行的程序将处理逻辑调色盘,为使逻辑调色盘更好地服务于所有使用逻辑调色盘的程序,Windows将在系统调色盘中设定颜色。该系统调色盘复制了显示卡的硬件对照表内容。这样,查看系统调色盘有助于调适调色盘应用程序。
因为对于这个问题有三种截然不同的处理方式,所以我将向您展示三个程序,以显示系统调色盘的内容。
SYSPAL1程序,如程序16-4所示,使用了前面所讲的GetSystemPaletteEntries函数。
程序16-4 SYSPAL1
SYSPAL1.C
/*---------------------------------------------------------------------------
SYSPAL1.C -- Displays system palette
(c) Charles Petzold, 1998
-----------------------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName [] = TEXT ("SysPal1") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?