Win32API オーナードローボタンについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
vion

Win32API オーナードローボタンについて

#1

投稿記事 by vion » 16年前

こんにちは。

オーナードローボタンについて質問なんですが
CreateWindowで第一引数を"BUTTON"にしプッシュボタンを作ろうとします。

その際、プッシュボタンをオーナードローで表示したく、しかもアニメーション(例えば、ボタンが点滅したり)で実現したいと思っています。
その場合のアプローチの仕方を教えてもらえないでしょうか。

いくつかやってみて疑問も出たので同時に質問させてください。
親ウィンドウのWM_PAINTを受け取る際にBeginPaintでボタンウィンドウのハンドルを用い、
デバイスコンテキストハンドルを取得してプッシュボタンの描画を実現しようとすると、
CPU負荷が極端に掛かるのはどうしてなんですか?

また、ボタンウィンドウ用にウィンドウクラスを登録し、プロシージャを独自に実装すれば出来るかと思いましたが、
ボタンウィンドウではプロシージャを持たせることが出来ないんですか?

toyo

Re:Win32API オーナードローボタンについて

#2

投稿記事 by toyo » 16年前

アニメーションさせるならオーナードローだけでは無理ですね
タイマーイベントで変化させればいいでしょう
コントロールのプロシージャをフックするのをサブクラス化といいます
猫でもわかるを参考に作ってみました
http://www.kumei.ne.jp/c_lang/sdk/sdk_36.htm
#include <windows.h>
#define ID_BUTTON1    1000
HWND hBWnd; //標準コントロールのHWND
WNDPROC Org_BWnd;   //オリジナルプロシージャのアドレス
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK MySubProc(HWND, UINT, WPARAM, LPARAM);
BOOL InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
LPCTSTR szClassName = TEXT("subcl01");        //ウィンドウクラス
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
                   LPSTR lpsCmdLine, int nCmdShow)
{
    MSG msg;
    if (!hPrevInst) {
        if (!InitApp(hCurInst))
            return FALSE;
    }
    if (!InitInstance(hCurInst, nCmdShow)) {
        return FALSE;
    }
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
//ウィンドウ・クラスの登録
BOOL InitApp(HINSTANCE hInst)
{
    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;    //プロシージャ名
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;        //インスタンス
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;    //メニュー名
    wc.lpszClassName = szClassName;
    return (RegisterClass(&wc));
}
//ウィンドウの生成
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
    HWND hWnd;
    hWnd = CreateWindow(szClassName,
        TEXT("猫でもわかるサブクラス化"),    //タイトルバーにこの名前が表示されます
        WS_OVERLAPPED | WS_SYSMENU,    //ウィンドウの種類
        CW_USEDEFAULT,    //X座標
        CW_USEDEFAULT,    //Y座標
        250,    //幅
        120,    //高さ
        NULL,            //親ウィンドウのハンドル、親を作るときはNULL
        NULL,            //メニューハンドル、クラスメニューを使うときはNULL
        hInst,            //インスタンスハンドル
        NULL);
    if (!hWnd)
        return FALSE;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return TRUE;
}
//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    PAINTSTRUCT ps;
    HDC hdc;
    HINSTANCE hInst;
    LPCTSTR color[/url] = { TEXT("赤 "), TEXT("緑 ")};
    static click;
    switch (msg) {
    case WM_CREATE:
        hInst = ((LPCREATESTRUCT)lp)->hInstance;
        hBWnd = CreateWindow(TEXT("BUTTON"),
            NULL,
            WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
            10, 50,
            100, 30,
            hWnd,
            (HMENU)ID_BUTTON1,
            hInst,
            NULL);
        //ウィンドウのサブクラス化
        Org_BWnd = (WNDPROC)GetWindowLong(hBWnd, GWL_WNDPROC);
        SetWindowLong(hBWnd, GWL_WNDPROC, (LONG)MySubProc);
        SetTimer(hBWnd, 1, 10, NULL);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        TextOut(hdc, 10, 10, color[click], 2); 
        EndPaint(hWnd, &ps);
        break;
    case WM_COMMAND:
        switch (LOWORD(wp)) {
        case ID_BUTTON1:
            click = click ? 0 : 1;
            InvalidateRect(hWnd, NULL, FALSE);
            break;
        default:
            return(DefWindowProc(hWnd, msg, wp,lp));
        }
        break;
        break;
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        //一応終了時にサブクラス化の解除
        //アプリケーションが終了してしまうので必要ないといえばない
        SetWindowLong(hBWnd, GWL_WNDPROC, (LONG)Org_BWnd);
        PostQuitMessage(0);
        break;
    default:
        return (DefWindowProc(hWnd, msg, wp, lp));
    }
    return 0L;
}
//コントロールのサブクラス化
LRESULT CALLBACK MySubProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    HDC hDC;
    HBRUSH hBrush, hOldBrush;
    static BYTE color;
    static int lclick;
    static int sign = 2;
    switch (msg) {
    case WM_TIMER:
        hDC = GetDC(hWnd);
        if (lclick) {
            hBrush = CreateSolidBrush(RGB(0, color, 0));
        }
        else {
            hBrush = CreateSolidBrush(RGB(color, 0, 0));
        }
        color += sign;
        if (color == 254) {
            sign = -2;
        }
        if (color == 0) {
            sign = 2;
        }
        hOldBrush = SelectObject(hDC, hBrush);
        Rectangle(hDC, 0, 0, 100, 30);
        SelectObject(hDC, hOldBrush);
        DeleteObject(hBrush);
        ReleaseDC(hWnd, hDC);
        return 0; //メッセージの処理をしたら0を返す
    case WM_LBUTTONUP:
        lclick = lclick ? 0 : 1;
        break; //親にクリックメッセージを渡すため元のプロシージャへ
    default:
        break;
    }
    //自分で処理しないものは元のプロシージャにやってもらう
    return (CallWindowProc(Org_BWnd, hWnd, msg, wp, lp));
}

vion

Re:Win32API オーナードローボタンについて

#3

投稿記事 by vion » 16年前

>コントロールのプロシージャをフックするのをサブクラス化といいます

なるほどー!!
キーワードを頂いただけでなく実際に組んでいただき感謝感激です。
おかげでコードを眺めながら具体的に検討できます。

理解し、自分なりにアレンジするまで少し時間がかかりそうなので
その際に疑問が出れば、また次回質問することにします。

toyoさん、ありがとうございました!!

閉鎖

“C言語何でも質問掲示板” へ戻る