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 + -
显示快捷键?