0

我想创建一个包含 256 个彩色按钮的数组,所有者为使用 Visual Studio 对话框设计工具创建的对话框绘制扩展样式。我在对话过程中向 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 个按钮。我打算使用不同的画笔为每个按钮着色,但对于调试用途,我替换了一个定义明确的画笔。我已经调试了代码并对每个按钮的 x/y 坐标和 hMenu createwindow 调用中提供的 ID 是正确的感到满意。我看到所有 256 个按钮都在 WM_CTLCOLORBTN 处理程序中着色。我包括了一项检查以确保 createwindow 调用不返回失败 (NULL)。通过在 createwindow 调用中交换 x/y 参数,我可以获得 4 行 16 个按钮或 4 列 16 个按钮。

如果我从 createwindow 调用中删除 BS_OWNERDRAW 位,则会绘制所有 256 个按钮。

就好像 BS_OWNERDRAW 有 64 个按钮的限制 :-(

任何帮助将不胜感激!

TIA,迈克

4

2 回答 2

1

您是否将WM_DRAWITEM消息与BS_OWNERDRAW样式一起处理?

在您的情况下,让我感到惊讶的是,在使用BS_OWNERDRAW样式时显示任何按钮,而BS_PUSHBUTTON已设置。

如以下BS_OWNERDRAW文档链接中所述,您需要处理WM_DRAWITEM并避免指定任何其他BS_按钮样式。

MSDN 中的按钮样式

同样令人好奇的是,对于包含BS_PUSHBUTTON样式的按钮,可能会收到WM_CTLCOLORBUTTON消息,然后将其忽略。查看以下链接以获取有关该窗口消息的文档。

WM_CTLCOLORBUTTON 来自 MSDN

从我在您的代码片段中可以看到,您很可能需要执行以下操作:

  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 回答