19.5 Changing a Logical Palette

You can change one or more entries in a logical palette by calling the SetPaletteEntries function. This function accepts the following parameters:

The handle of the palette to be changed and an integer specifying the first palette entry to be changed

An integer specifying the number of entries to be changed

An array of PALETTEENTRY structures, each of which contains the red, green, and blue intensities and flags for each entry

Windows does not map changes made to the palette until the application calls RealizePalette for any device context in which the palette is selected. Because this changes the system palette, colors displayed in the client area will likewise change. For more information about how to respond when Windows changes the system palette, see Section 19.6, “Responding to Changes in the System Palette.”

A second method of updating a logical palette is by animating it. In most cases, an application animates its logical palette when it is necessary to change the palette rapidly and to make those changes immediately apparent.

To animate a palette, the application must first set the flags in the affected palette entries to PC_RESERVED. This flag has two functions:

It enables animation for the palette entry.

It prevents Windows from matching colors displayed in other device contexts to the corresponding color in the system palette.

The following example shows how ShowDIB sets the PC_RESERVED flag in all the entries in an existing logical palette:

for (i = 0; i < pLogPal->palNumEntries; i++) {
     pLogPal->palPalEntry[i].peFlags = (BYTE) PC_RESERVED;
}

SetPaletteEntries(hpalCurrent, 0, pLogPal->palNumEntries,
    pLogPal->palPalEntry);

The AnimatePalette function accepts the same parameters as SetPaletteEntries. Unlike SetPaletteEntries, however, AnimatePalette changes only those palette entries in which the PC_RESERVED flag is set.

When an application calls AnimatePalette, Windows immediately maps the changed entries to the system palette, but it does not rematch the colors displayed in the device contexts by using the palette for which the application called AnimatePalette. In other words, if a pixel was displaying the color in the fifth entry in the system palette before the application called AnimatePalette, it will continue to display the color in that entry after AnimatePalette is called, even if the fifth entry now contains a different color.

To demonstrate palette animation, ShowDIB sets a system timer and then calls AnimatePalette to shift each entry in the palette each time its window receives a WM_TIMER message:

case WM_TIMER:

        /* WM_TIMER is the signal for palette animation. */

        hDC = GetDC(hWnd);
        hOldPal = SelectPalette(hDC, hpalCurrent, 0); {
            PALETTEENTRY peTemp;

            /*
             * Shift all palette entries left by one
             * position and wrap around the first entry.
             */





            peTemp = pLogPal->palPalEntry[0];
            for (i = 0; i < (pLogPal->palNumEntries - 1); i++)
                 pLogPal->palPalEntry[i] =
                 pLogPal->palPalEntry[i + 1];
            pLogPal->palPalEntry[i] = peTemp;
        }

        /* Replace entries in logical palette with new entries. */

        AnimatePalette(hpalCurrent, 0, pLogPal->palNumEntries,
            pLogPal->palPalEntry);

        SelectPalette(hDC, hOldPal, 0);
        ReleaseDC(hWnd, hDC);

        /*
         * Decrement animation count and terminate
         * animation if it reaches zero.
         */

        if (!(--nAnimating))
            PostMessage(hWnd, WM_COMMAND, IDM_ANIMATE0, 0L);
        break;

Animating an entire logical palette will degrade colors displayed by other applications' windows if the active window is using the animated palette, particularly if the animated palette is large enough to “take over” the system palette. For this reason, your application should animate no more entries than it requires.