?? ch15.htm
字號:
<HR></BLOCKQUOTE><P><A NAME="06"></A><A HREF="06.htm"><B>Figure 15.6.</B></A> <I><BR>Windows makes 236 palette entries available to applications.</I><BLOCKQUOTE> <P><HR><B> </B><FONT COLOR="#000077"><B>Just a Minute:</B></FONT><B> </B>At first glance, it might seem unfair for 20 entries to be removed from the system palette. These entries are removed to keep the basic window display predictable. The 20 reserved palette entries include the colors used by 16-color VGA devices. As long as these palette entries are available, Windows applications that don't use the palette are displayed as expected. <HR></BLOCKQUOTE><H3><FONT COLOR="#000077"><B>The System Palette</B></FONT></H3><P>A palette is one of the attributes that belong to a DC. After you have decidedto use a palette in your application, you must follow these basic steps:<DL> <DD>1. Create a logical palette. This is the process of allocating space for the palette entries and describing the colors that will be included in the palette. As you'll learn, this process is much easier than it sounds. In most cases, when you must create a palette you copy the colors from a bitmap or other object into the new palette. This step is usually performed once, and the logical palette is stored by the application so that it can be used whenever needed.<BR> <BR> 2. Select the palette into a DC. Unlike other GDI objects, <TT>SelectObject</TT> doesn't work for logical palettes. You must use the <TT>SelectPalette</TT> function.<BR> <BR> 3. Realize the palette. Basically, realizing the palette asks the Windows Palette Manager to add your palette to the system palette or map your palette to a reasonably close substitute. Selecting and realizing the palette always happens at the same time; there's no point in selecting a palette unless you intend to realize it immediately.<BR> <BR> 4. Use the palette. If the system palette was updated, the application should redraw itself. This is usually done by invalidating any windows that depend on palette entries.<BR> <BR> 5. Deselect the palette by selecting the previous palette back into the DC.<BR> <BR> 6. Delete the palette object. This step is usually performed only when you're sure the palette is no longer needed.</DL><P>Two messages related to palettes are sent to your application:<UL> <LI>When a window moves into the foreground, Windows sends it a <TT>WM_QUERYNEWPALETTTE</TT> message. In response to this message, your application should realize its palette.<BR> <BR> <LI>If the system palette is changed, all windows in the background receive a <TT>WM_PALETTECHANGED</TT> message. An application in the background should realize its palette to attempt to reassert colors in the system palette. If no free positions in the system palette are available, the Palette Manager maps the requested color to the closest palette entry.</UL><P>In any case, you should invalidate any parts of your application that depend onyour logical palette if the system palette is updated.<H2><FONT COLOR="#000077"><B>The Dib Example</B></FONT></H2><P>As an example of how 256-color bitmaps are displayed, you will now create an MFCexample named Dib. The design of the Dib project uses a basic AppWizard SDI skeletonwith these modifications:<UL> <LI>A reusable class that handles the display of DIBs, <TT>CDIBitmap</TT><BR> <BR> <LI>A reusable class that handles the creation of a new 256-color palette, <TT>CBmpPalette</TT><BR> <BR> <LI>Additional palette message-handling functions</UL><H3><FONT COLOR="#000077"><B>The <TT>CDIBitmap</TT> Class</B></FONT></H3><P>The <TT>CDIBitmap</TT> class does most of the work in the Dib project. The <TT>CDIBitmap</TT>class provides an easy-to-use interface for handling 256-color DIBs. The class interfacefor <TT>CDIBitmap</TT> is shown in Listing 15.2. Save this file as <TT>dib256.h</TT>.<H4><FONT COLOR="#000077">TYPE: Listing 15.2. The CDIBitmap class interface.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>#ifndef DIBMP_TYS</TT><TT>#define DIBMP_TYS</TT><TT>class CDIBitmap</TT><TT>{</TT><TT> friend class CBmpPalette;</TT><TT>//constructors</TT><TT>public:</TT><TT> CDIBitmap();</TT><TT> virtual ~CDIBitmap();</TT><TT>private:</TT><TT> CDIBitmap( const CDIBitmap& dbmp ){};</TT><TT>//operations</TT><TT>public:</TT><TT> inline BITMAPINFO* GetHeaderPtr();</TT><TT> inline BYTE* GetPixelPtr();</TT><TT> virtual void DrawDIB ( CDC* pDC, int x, int y );</TT><TT> virtual BOOL Load( CFile* pFile );</TT><TT> RGBQUAD* GetColorTablePtr();</TT><TT>protected:</TT><TT> int GetPalEntries() const;</TT><TT> int GetPalEntries( BITMAPINFOHEADER& infoHeader ) const;</TT><TT>protected:</TT><TT> int GetWidth() const;</TT><TT> int GetHeight() const;</TT><TT>//implementation</TT><TT>private:</TT><TT> BITMAPINFO* m_pInfo;</TT><TT> BYTE* m_pPixels;</TT><TT>};</TT><TT>#endif</TT></FONT></PRE><P>Note that <TT>CDIBitmap</TT> isn't derived from <TT>CBitmap</TT>, or <TT>CObject</TT>for that matter. The class itself consumes only a few bytes, requiring space fortwo pointers and a virtual function table. <TT>CDIBitmap</TT> has five public functions:<UL> <LI><TT>GetHeaderPtr</TT>: Returns a pointer to the <TT>BITMAPINFO</TT> structure.<BR> <BR> <LI><TT>GetPixelPtr</TT>: Returns a pointer to the beginning of the pixel image array.<BR> <BR> <LI><TT>DrawDIB</TT>: Draws the DIB at a specified location.<BR> <BR> <LI><TT>Load</TT>: Reads a DIB from a <TT>.BMP</TT> file and initializes the <TT>CDIBitmap</TT> object.<BR> <BR> <LI><TT>GetColorTablePtr</TT>: Returns a pointer to the color table.</UL><P>The source code for the implementation of <TT>CDIBitmap</TT> is provided in Listing15.3. Save this file as <TT>dib256.cpp</TT>, and add it to the Dib project.<H4><FONT COLOR="#000077">TYPE: Listing 15.3. The implementation of the CDIBitmapclass.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>#include "stdafx.h"</TT><TT>#include "dib256.h"</TT><TT>CDIBitmap::CDIBitmap()</TT><TT>{</TT><TT> m_pInfo = 0;</TT><TT> m_pPixels = 0;</TT><TT>}</TT><TT>CDIBitmap::~CDIBitmap()</TT><TT>{</TT><TT> delete [] (BYTE*)m_pInfo;</TT><TT> delete [] m_pPixels;</TT><TT>}</TT><TT>BOOL CDIBitmap::Load( CFile* pFile )</TT><TT>{</TT><TT> ASSERT( pFile );</TT><TT> BOOL fReturn = TRUE;</TT><TT> delete [] (BYTE*)m_pInfo;</TT><TT> delete [] m_pPixels;</TT><TT> m_pInfo = 0;</TT><TT> m_pPixels = 0;</TT><TT> DWORD dwStart = pFile->GetPosition();</TT><TT> // Check to make sure we have a bitmap. The first two bytes must</TT><TT> // be `B' and `M'.</TT><TT> BITMAPFILEHEADER fileHeader;</TT><TT> pFile->Read(&fileHeader, sizeof(fileHeader));</TT><TT> if( fileHeader.bfType != 0x4D42 )</TT><TT> return FALSE;</TT><TT> BITMAPINFOHEADER infoHeader;</TT><TT> pFile->Read( &infoHeader, sizeof(infoHeader) );</TT><TT> if( infoHeader.biSize != sizeof(infoHeader) )</TT><TT> return FALSE;</TT><TT> // Store the sizes of the DIB structures</TT><TT> int cPaletteEntries = GetPalEntries( infoHeader );</TT><TT> int cColorTable = 256 * sizeof(RGBQUAD);</TT><TT> int cInfo = sizeof(BITMAPINFOHEADER) + cColorTable;</TT><TT> int cPixels = fileHeader.bfSize - fileHeader.bfOffBits;</TT><TT> // Allocate space for a new bitmap info header, and copy</TT><TT> // the info header that was loaded from the file. Read the</TT><TT> // the file and store the results in the color table.</TT><TT> m_pInfo = (BITMAPINFO*)new BYTE[cInfo];</TT><TT> memcpy( m_pInfo, &infoHeader, sizeof(BITMAPINFOHEADER) );</TT><TT> pFile->Read( ((BYTE*)m_pInfo) + sizeof(BITMAPINFOHEADER),</TT><TT> cColorTable );</TT><TT> //</TT><TT> // Allocate space for the pixel area, and load the pixel</TT><TT> // info from the file.</TT><TT> m_pPixels = new BYTE[cPixels];</TT><TT> pFile->Seek(dwStart + fileHeader.bfOffBits, CFile::begin);</TT><TT> pFile->Read( m_pPixels, cPixels );</TT><TT> return fReturn;</TT><TT>}</TT><TT>// DrawDib uses StretchDIBits to display the bitmap.</TT><TT>void CDIBitmap::DrawDIB( CDC* pDC, int x, int y )</TT><TT>{</TT><TT> HDC hdc = pDC->GetSafeHdc();</TT><TT> if( m_pInfo )</TT><TT> StretchDIBits( hdc, x, y,</TT><TT> GetWidth(),</TT><TT> GetHeight(),</TT><TT> 0, 0,</TT><TT> GetWidth(),</TT><TT> GetHeight(),</TT><TT> GetPixelPtr(),</TT><TT> GetHeaderPtr(),</TT><TT> DIB_RGB_COLORS,</TT><TT> SRCCOPY );</TT><TT>}</TT><TT>BITMAPINFO* CDIBitmap::GetHeaderPtr()</TT><TT>{</TT><TT> return m_pInfo;</TT><TT>}</TT><TT>RGBQUAD* CDIBitmap::GetColorTablePtr()</TT><TT>{</TT><TT> RGBQUAD* pColorTable = 0;</TT><TT> if( m_pInfo != 0 )</TT><TT> {</TT><TT> int cOffset = sizeof(BITMAPINFOHEADER);</TT><TT> pColorTable = (RGBQUAD*)(((BYTE*)(m_pInfo)) + cOffset);</TT><TT> }</TT><TT> return pColorTable;</TT><TT>}</TT><TT>BYTE* CDIBitmap::GetPixelPtr()</TT><TT>{</TT><TT> return m_pPixels;</TT><TT>}</TT><TT>int CDIBitmap::GetWidth() const</TT><TT>{</TT><TT> return m_pInfo->bmiHeader.biWidth;</TT><TT>}</TT><TT>int CDIBitmap::GetHeight() const</TT><TT>{</TT><TT> return m_pInfo->bmiHeader.biHeight;</TT><TT>}</TT><TT>int CDIBitmap::GetPalEntries() const</TT><TT>{</TT><TT> return GetPalEntries( *(BITMAPINFOHEADER*)m_pInfo );</TT><TT>}</TT><TT>int CDIBitmap::GetPalEntries( BITMAPINFOHEADER& infoHeader ) const</TT><TT>{</TT><TT> int nReturn;</TT><TT> if( infoHeader.biClrUsed == 0 )</TT><TT> {</TT><TT> nReturn = ( 1 << infoHeader.biBitCount );</TT><TT> }</TT><TT> else</TT><TT> nReturn = infoHeader.biClrUsed;</TT><TT> return nReturn;</TT><TT>}</TT></FONT></PRE><P>Most of the work in the <TT>CDIBitmap</TT> class is done by the <TT>CDIBitmap::Load</TT>member function. This member function takes a pointer to an MFC <TT>CFile</TT> objectas its only parameter. Later in this hour, you will see how the sample program providesa <TT>CFile</TT> pointer to this function during serialization.</P><P>After verifying that the <TT>CFile</TT> object refers to a Windows bitmap, the<TT>Load</TT> function reads each part of the bitmap data structure and creates aDIB dynamically. Note that there actually are two calls to the new operator; thereis no requirement that the DIB exist in one solid chunk of memory. The <TT>BITMAPINFOHEADER</TT>is stored in one location, and the pixel image array is stored in another location.</P><P>The <TT>CDIBitmap::DrawDIB</TT> member function calls <TT>StretchDIBits</TT> todisplay the DIB. Very little work is actually done in this function. For example,the width and height of the DIB are calculated using <TT>CDIBitmap</TT> member functions.</P><P>The remaining member functions are used to calculate various bits of informationabout the DIB. Only a pointer to the beginning of the <TT>BITMAPINFO</TT> structureand a pointer to the beginning of the pixel image array are stored; all other informationis calculated as it is needed.<H3><FONT COLOR="#000077"><B>The <TT>CBmpPalette</TT> Class</B></FONT></H3><P>You use the <TT>CBmpPalette</TT> class to create a logical palette that containsthe colors used by a <TT>CDIBitmap</TT> object. Although the MFC class library includesa <TT>CPalette</TT> class, you must derive your own class from it in order to doany meaningful work. Listing 15.4 contains the declaration for <TT>CBmpPalette</TT>.Save this file as <TT>dibpal.h</TT>.<H4><FONT COLOR="#000077">TYPE: Listing 15.4. The CBmpPalette class interface.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>#ifndef BMP_PAL_TYS</TT><TT>#define BMP_PAL_TYS</TT><TT>class CBmpPalette : public CPalette</TT><TT>{</TT><TT>public:</TT><TT> CBmpPalette( CDIBitmap* pBmp );</TT><TT>};</TT><TT>#endif</TT></FONT></PRE><P>All the work done by <TT>CBmpPalette</TT> is done in the constructor; there areno member functions other than the function inherited from <TT>CPalette</TT>, theMFC base class. The <TT>CBmpPalette</TT> class is always used with <TT>CDIBitmap</TT>.A pointer to a <TT>CDIBitmap</TT> object is passed to <TT>CBmpPalette</TT> as a constructorparameter.</P><P><TT>CBmpPalette</TT> allocates a logical palette with enough entries to storethe palette required by the <TT>CDIBitmap</TT> object. After storing some basic paletteinformation, the palette entries are filled in, using the values collected from the<TT>CDIBitmap</TT> object. After the palette is created, the logical palette is deleted.The implementation from <TT>CBmpPalette</TT> is provided in Listing 15.5 and is includedin the Dib project as <TT>dibpal.cpp</TT>.<H4><FONT COLOR="#000077">TYPE: Listing 15.5. The implementation of the CBmpPaletteclass.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>#include "stdafx.h"</TT><TT>#include "dib256.h"</TT><TT>#include "dibpal.h"</TT><TT>CBmpPalette::CBmpPalette( CDIBitmap* pBmp )</TT><TT>{</TT><TT> ASSERT( pBmp );</TT><TT> int cPaletteEntries = pBmp->GetPalEntries();</TT><TT> int cPalette = sizeof(LOGPALETTE) +</TT><TT> sizeof(PALETTEENTRY) * cPaletteEntries;</TT><TT> // Since the LOGPALETTE structure is open-ended, you</TT><TT> // must dynamically allocate it.</TT><TT> LOGPALETTE* pPal = (LOGPALETTE*)new BYTE[cPalette];</TT><TT> RGBQUAD* pColorTab = pBmp->GetColorTablePtr();</TT><TT> pPal->palVersion = 0x300;</TT>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -