【问题标题】:Child Windows not showing子窗口不显示
【发布时间】:2014-01-05 20:47:01
【问题描述】:
ATOM MyRegisterChildClass(void)
{
    WNDCLASSEX wcex = {0};
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.lpfnWndProc = ChildProc;
    wcex.hInstance = hInst;
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 8);
    wcex.lpszClassName = ChildClassName;
    return RegisterClassEx(&wcex);
}
static HFONT newFont;
static HWND hChild[9];
unsigned char k[9] = {0};
char text[] = {' ', 'X', '0'};
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int i;
    static int sx, sy;
    switch (message)
    {
    case WM_CREATE:
        MyRegisterChildClass();
        for(i = 0; i < 9; i++)
            hChild[i] = CreateWindow(ChildClassName, NULL, WS_CHILD |
            WS_DLGFRAME | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL);
        break;
    case WM_SIZE:
        if(wParam == SIZE_MINIMIZED)
            break;
        sx = LOWORD(lParam)/3;
        sy = HIWORD(lParam)/3;
        if(newFont)
            DeleteObject(newFont);
        newFont = CreateFont(min(sx, sy), 0, 0, 0, FW_NORMAL, 0, 0, 0,
            DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
            DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
        for(i = 0; i < 9; i++)
        {
            MoveWindow(hChild[i], (i%3)*sx, (i/3)*sy, sx, sy, TRUE);
            UpdateWindow(hChild[i]);
        }
        break;
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case ID_NEW:
            for(i = 0; i < 9; i++)
            {
                k[i] = 0;
                InvalidateRect(hChild[i], NULL, TRUE);
                UpdateWindow(hChild[i]);
            }
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;


    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
RECT rt;
int s, i;
char *ch;
switch(message)
{
case WM_LBUTTONDOWN:
    for(i = 0; hWnd != hChild[i]; i++);
    if(k[i])
        break;
    else
        k[i] = 1;
    InvalidateRect(hWnd, NULL, TRUE);
    UpdateWindow(hWnd);
    srand(lParam);
    for(i = s = 0; i < 9; i++)
        if(k[i])
            s++;
    if(s == 9)
        MessageBox(hWnd, L"...",L"...", MB_OK|MB_ICONQUESTION);
    else
    {
        while(true)
        {
            s = rand()*9/(RAND_MAX+1);
            if(k[s])
                continue;
            k[s] = 2;
            InvalidateRect(hChild[s], NULL, TRUE);
            UpdateWindow(hChild[s]);
            break;
        }
    }
    break;
case WM_PAINT:
    for(i = 0; hWnd != hChild[i]; i++);
    if(k[i])
    {
        ch = text+k[i];
        hDC = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &rt);
        SelectObject(hDC, newFont);
        DrawTextA(hDC, ch, 1, &rt, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
        EndPaint(hWnd, &ps);
    }
    else
        DefWindowProc(hWnd, message, wParam, lParam);
    break;
default:
    DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

我正在尝试做井字游戏。这是我手工编写的代码(这里没有由 Visual Studio 生成的标准代码)。我做了9个子窗口。 此代码运行,但它不显示子窗口并且当我按下鼠标左键时没有反应。在调试器的帮助下,我看到消息 WM_LBUTTONDOWN 和 WM_PAINT 永远不会发送到 ChildProc 函数。 怎么了?

【问题讨论】:

    标签: c++ winapi


    【解决方案1】:
        for(i = 0; i < 9; i++)
            hChild[i] = CreateWindow(ChildClassName, NULL, WS_CHILD |
            WS_DLGFRAME | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL);
    

    你犯了一个传统的错误,你盲目地希望winapi函数能够成功。那是空想, CreateWindow() 失败并返回 NULL。您也可以使用调试器看到一些东西,您会看到 hChild 数组只包含空值。 总是编写防御性代码,至少使用 assert() 来支持您的假设:

        for(i = 0; i < 9; i++) {
            hChild[i] = CreateWindow(ChildClassName, ...);
            assert(hChild[i]);
        }
    

    您的代码中有很多其他地方应该这样做。您现在将不得不在诊断故障方面遇到麻烦。

    实际的 bug 位于 ChildProc() 中:

    default:
        DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
    

    或者换句话说,它总是返回 0。这不行,您应该只在处理消息时返回该值。您没有处理每条消息。再次使用调试器并在 ChildProc 中的 switch() 语句上设置断点。您将看到第一条消息处理不当,WM_NCCREATE。这要求您返回 TRUE 以继续创建窗口。你没有,你返回 FALSE。所以这是创建窗口的快速结束。您必须返回 DefWindowProc() 的值。修复:

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    

    请注意,您还使用 WndProc() 中的 WM_CREATE 消息玩危险游戏。返回 0 是偶然的,您应该始终将消息传递给 DefWindowProc(),因为您实际上并没有处理 WM_CREATE,您只是将它用作通知。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-31
      • 1970-01-01
      • 2020-11-24
      • 2011-11-10
      • 2011-09-15
      相关资源
      最近更新 更多