0

Visual Studio のダイアログ デザイン ツールで作成されたダイアログ ボックスに、所有者が拡張スタイルを描画する 256 色のボタンの配列を作成したいと考えています。これを行うために、ダイアログ プロシージャの WM_INITDIALOG メッセージ ハンドラにループを追加しました。

for (i=0; i<=255; i++)
{

int xp, yp;
HWND status;

xp = rect_pos.left+16*(i%16);
yp = rect_pos.top+16*(i>>4);
status = CreateWindow (
    TEXT("button"),
    "\0",
    WS_CHILD|WS_VISIBLE|BS_OWNERDRAW|BS_PUSHBUTTON,
    xp,
    yp,
    15,
    15,
    hDlg,
    (HMENU) 5000+i,     // id used to report events
    hInst,
    NULL
);

if (status == NULL)
    xp =7;
}

WM_CTLCOLORBTN メッセージのメッセージ ハンドラーを追加しました。

case WM_CTLCOLORBTN:
{   
    int     zz;

    zz = GetWindowLong ((HWND) lParam, GWL_ID); // window identifier
    zz -= 5000;
    if ((zz >= 0) && (zz <= 255))
    {
        HBRUSH BS;

        SetTextColor ((HDC) wParam, Collector.Color);
        SetBkColor ((HDC) wParam,   Collector.Color); 

        return ((LRESULT) Collector.Brush);       

    }
    break;
}

多かれ少なかれ機能しますが、最初の 64 個のボタンしか表示されません。各ボタンに色を付けるために別のブラシを使用するつもりですが、デバッグ用に、明確に定義された 1 つのブラシに置き換えました。私はコードをデバッグし、各ボタンの x/y 座標が適切であり、hMenu createwindow 呼び出しで提供された ID が適切であることを確認しました。WM_CTLCOLORBTN ハンドラで 256 個のボタンすべてが色付けされるのを見ました。createwindow 呼び出しが失敗 (NULL) を返さないことを確認するためのチェックを含めました。createwindow 呼び出しで x/y パラメーターを交換することで、16 ボタンの 4 行または 16 ボタンの 4 列のいずれかを取得できます。

createwindow 呼び出しから BS_OWNERDRAW ビットを削除すると、256 個のボタンすべてが描画されます。

BS_OWNERDRAW では 64 個のボタンに制限があるかのようです :-(

どんな助けでも大歓迎です!

ティア、マイク

4

2 に答える 2

1

BS_OWNERDRAWスタイルと組み合わせてWM_DRAWITEMメッセージを処理していますか?

あなたの場合、 BS_PUSHBUTTONが設定されているときにBS_OWNERDRAWスタイルを使用しているときにボタンが表示されるのは驚くべきことです。

BS_OWNERDRAWのドキュメントへの次のリンクで説明されているように、WM_DRAWITEMを処理し、他のBS_ボタン スタイルを指定しないようにする必要があります。

MSDN のボタン スタイル

また興味深いのは、WM_CTLCOLORBUTTONメッセージが受信され、BS_PUSHBUTTONスタイルを含むボタンに対して無視される可能性があることです。そのウィンドウ メッセージに関するドキュメントについては、次のリンクを参照してください。

MSDN の WM_CTLCOLORBUTTON

あなたのコード スニペットで私が見ることができることから、おそらく次のことをしたいと思うでしょう:

  1. 子ボタンを作成するときに BS_OWNERDRAW を設定します。
  2. ダイアログで WM_DRAWITEM を処理し、ボタンを正しい状態で描画します。WM_CTLCOLORBUTTON を処理する必要がないことに注意してください。ブラシとフォントを使用し、WM_DRAWITEM ハンドラー内で必要に応じて DC を変更します。

また、アプリケーションによっては、独自のウィンドウ クラスを作成してボタンのグリッドを独自に表現し、好みに合わせて項目を描画するだけでもメリットがある場合があります。これは、内部状態を表示するだけで、ユーザーがボタンのグリッドを管理または操作する必要がない場合に適しています。

于 2009-07-08T18:09:41.007 に答える
0

アドバイスと助けを与えてくれたすべての人に感謝します。私は今、これを満足のいくように機能させています。ボタンに色を付け、選択した場合、または入力フォーカスがある場合は、ボタンを黒のアウトラインで囲みました。以下にいくつかのコードスニペットを追加して、最終的な状態を示しますが、ここに概要を示します。まず、私のシステムには、所有者が描画したボタンが、作成された最初の子64ボタンのWM_CTLCOLORBTNに応答するレガシーコードがあると思います。次に、ボタンを作成し、WM_DRAWITEMメッセージとWM_COMMAND/BN_CLICKEDメッセージに適切に応答するだけでよいと思います。

これが私のダイアログボックスハンドラーからのコードスニペットです。

WM_INITDIALOGコードで-ボタンを作成します

        for (i=0; i<=255; i++)
        {
            int xp, yp;
            HWND status;

            xp = rect_pos.left+16*(i&0x0F);
            yp = rect_pos.top+16*(i>>4);

            status = CreateWindow 
                (
                TEXT("button"),
                "\0",
                WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_OWNERDRAW,
                xp,
                yp,
                15,
                15,
                hDlg,
                (HMENU) (5000+i),                       // id used to report events
                hInst,
                NULL
                );

            if (status == NULL)
                xp =7;


            SetFocus (status);

        }

WM_DRAWITEMメッセージに応答する

case WM_DRAWITEM:                           // Owner drawn botton
    {
        LPDRAWITEMSTRUCT lpDrawItem;
        HBRUSH  BS, BS_Old;
        HPEN    PN_Old;
        int     sz=15;
        int     cntl;

        cntl =  LOWORD (wParam) - 5000;

        lpDrawItem = (LPDRAWITEMSTRUCT) lParam;

        if (lpDrawItem->CtlType != ODT_BUTTON)
            return FALSE;

        BS = CreateSolidBrush (ColorRef[cntl]);

        if (lpDrawItem->itemState & (ODS_SELECTED | ODS_FOCUS))
        {
            sz = 14;
            PN_Old = (HPEN) SelectObject(lpDrawItem->hDC, GetStockObject(BLACK_PEN));
        }
        else
            PN_Old = (HPEN) SelectObject(lpDrawItem->hDC, GetStockObject(NULL_PEN));

        BS_Old = (HBRUSH) SelectObject(lpDrawItem->hDC, BS);
        Rectangle (lpDrawItem->hDC, 0, 0, sz, sz);
        SelectObject(lpDrawItem->hDC, PN_Old);
        SelectObject(lpDrawItem->hDC, BS_Old);
        DeleteObject (BS);

        return true;
    }

そして最後にWM_COMMANDコードで

    if (HIWORD(wParam) == BN_CLICKED) 
    { 
        if ((LOWORD(wParam) >= 5000) && (LOWORD(wParam) <=5255))
        {

            Color[0] = ColorRef[LOWORD(wParam)-5000] & 0xFF;
            Color[1] = (ColorRef[LOWORD(wParam)-5000] >> 16) & 0xFF;
            Color[2] = (ColorRef[LOWORD(wParam)-5000] >> 8 ) & 0xFF;

            InvalidateRect (hDlg, NULL, TRUE);

            goto Set_Color;
        } 
     } 
于 2009-07-13T16:56:48.910 に答える