ホーム ATL/WTL
パレット
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2007/09/23
PR
 WTLではGDIオブジェクトのパレットをCPaletteTというクラステンプレートでカプセル化しています。 テンプレート引数はbool値で、trueの場合はデストラクタでDeleteObject()を呼び出し、 falseの場合は呼び出しません。atlgdi.hヘッダではtypedefによって次のように宣言されています。

// atlgdi.h
typedef CPaletteT<false>  CPaletteHandle;
typedef CPaletteT<true>   CPalette;
			

 WTLのCPaletteクラスは、MFCの同名のクラスとほぼ同じメンバ関数を用意しています。 CPaletteT::CreatePalette()はカスタムパレットを作成します。 カスタムパレットは主に色の種類が少ない、微妙な階調が多用される画像のために使用されます。 CPaletteT::CreateHalftonePalette()はハーフトーンパレットを作成します。 ハーフトーンパレットは主に色の種類が多い画像のために使用されます。

以下に示すのは、CPaletteクラスを使用してクライアント領域に65階調のグラデーションを描画する例です。 グラデーションは微妙な階調で表現するので、カスタムパレットを使用します。 なお、パレットの影響を確認するために256色モードの画面で実行します。 次のスクリーンショットは、上がパレットを使用した場合で、下が使用していない場合の表示です。



プロジェクトファイル ダウンロード(パレット使用)
プロジェクトファイル ダウンロード(パレット未使用)
// stdafx.h
#pragma once

#include <atlbase.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>

#include <atlcrack.h>
#include <atlmisc.h>
			

// MainWindow.h
#pragma once

class CMainWindow : public CWindowImpl<CMainWindow>,
    public CMessageFilter, public CIdleHandler
{
public:
    DECLARE_WND_CLASS(_T("Hello"));

    CPalette m_palette;  // CPalette型のメンバ変数
    
    virtual BOOL PreTranslateMessage(MSG* pMsg){
        return FALSE;
    }

    virtual BOOL OnIdle(){
        return FALSE;
    }

    BEGIN_MSG_MAP(CMainWindow)
        MSG_WM_PAINT(OnPaint)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
    END_MSG_MAP()

    void OnPaint(CDCHandle /*dc*/){
        CPaintDC dc(m_hWnd);

        // パレットを選択
        HPALETTE hOldPalette;
        if(!m_palette.IsNull()){
            hOldPalette = dc.SelectPalette(m_palette, FALSE);
            dc.RealizePalette();
        }

        // クライアント矩形を取得し、グラデーションを描画
        CRect rect, rcLine;
        GetClientRect(rect);
        for(int i=0; i<65; i++){
            // ブラシ作成
            CBrush brush;
            brush.CreateSolidBrush(
                PALETTERGB(min(255, i * 4), min(255, i * 4), min(255, i * 4))
            );
            // 矩形描画
            rcLine.SetRect(0, i * rect.Height() / 65, 
                rect.Width(), (i + 1) * rect.Height() / 65);
            dc.FillRect(rcLine, brush);
        }

        // 元のパレットを選択
        if(!m_palette.IsNull())
            dc.SelectPalette(hOldPalette, FALSE);
    }

    int OnCreate(LPCREATESTRUCT lpCreateStruct){
        CClientDC dc(m_hWnd);
        if(dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE){
            // カスタムパレットを作成
            struct{
                LOGPALETTE lp;
                PALETTEENTRY ape[64];
            }pal;

            LOGPALETTE* pLP = (LOGPALETTE*)&pal;
            pLP->palVersion = 0x300;
            pLP->palNumEntries = 65;

            for(int i=0; i<65; i++){
                pLP->palPalEntry[i].peRed = min(255, i * 4);
                pLP->palPalEntry[i].peGreen = min(255, i * 4);
                pLP->palPalEntry[i].peBlue = min(255, i * 4);
                pLP->palPalEntry[i].peFlags = 0;
            }

            m_palette.CreatePalette(pLP);
        }

        // メッセージループにメッセージフィルタとアイドルハンドラを追加
        CMessageLoop* pLoop = _Module.GetMessageLoop();
        pLoop->AddMessageFilter(this);
        pLoop->AddIdleHandler(this);

        return 0;
    }

    void OnDestroy(){
        // メッセージループからメッセージフィルタとアイドルハンドラを削除
        CMessageLoop* pLoop = _Module.GetMessageLoop();
        pLoop->RemoveMessageFilter(this);
        pLoop->RemoveIdleHandler(this);
        PostQuitMessage(0);
    }
};
			

// SampleProject.cpp
#include "stdafx.h"
#include "MainWindow.h"

CAppModule _Module;

int APIENTRY _tWinMain(HINSTANCE hInstance, 
                       HINSTANCE hPrevInstance, 
                       LPTSTR    lpCmdLine, 
                       int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    _Module.Init(NULL, hInstance);

    CMessageLoop theLoop;
    _Module.AddMessageLoop(&theLoop);

    CMainWindow wnd;
    wnd.Create(NULL, CWindow::rcDefault,
        _T("Hello, ATL/WTL"), WS_OVERLAPPEDWINDOW | WS_VISIBLE);

    int nRet = theLoop.Run();

    _Module.RemoveMessageLoop();

    _Module.Term();

    return nRet;
}
			

 まず、CPaletteクラスのインスタンスをCMainWindowクラスのメンバ変数として宣言します。 この変数は、CPaletteクラスのコンストラクタでNULLに初期化されます。

 次に、WM_CREATEメッセージハンドラで、パレットが必要かどうかをチェックします。 チェックするには、ディスプレイが256色モードかどうかを判定します。

// dcはデバイスコンテキストクラスのインスタンス
if(dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE){
    // 256色モードなのでパレットが必要
}
			

パレットが必要な場合はカスタムパレットを作成します。

 次に、WM_PAINTメッセージハンドラでは、 m_paletteがNULLではない場合(=パレットが必要な場合)、 作成したパレットオブジェクトをSelectPalette()で現在のパレットとして選択し、 RealizePalette()でリアライズします。 SelectPalette()は引数にHPALETTE型の変数を受け取りますが、 CPaletteTクラステンプレートはHPALETTE変換演算子を持っているのでそのまま渡すことができます。 SelectPalette()は以前のパレットハンドルを返すので、 これをhOldPaletteという変数に保存しておきます。 次に、ブラシを使って黒から白へグラデーションを描画します。 最後に、先ほど保存しておいた元のパレットハンドルに戻すため、 再度SelectPalette()を呼び出して元のパレットハンドルを選択します。

 ところで、WTLはストックパレットもサポートしています。 以下に示すのは、WM_PAINTメッセージハンドラでストックパレットを使用して描画する例です。

// WM_PAINTメッセージハンドラ
void OnPaint(CDCHandle /*dc*/){
    CPaintDC dc(m_hWnd);

    // パレットを選択
    HPALETTE hOldPalette = dc.SelectStockPalette(DEFAULT_PALETTE, FALSE);

    // 描画
    ...
    ...

    // 元のパレットを選択
    dc.SelectPalette(hOldPalette, FALSE);
}
			

また、atlmisc.hヘッダに定義されているAtlGetStockPalette()というグローバル関数を使えば、 ストックパレットのハンドルを取得することができます。

// ストックパレットのハンドルを取得
HPALETTE hStockPalette = AtlGetStockPalette(DEFAULT_PALETTE);