如何修复 win32 api static 中的错误幽灵文本

问题描述 投票:0回答:2

我想在 Windows API C++ 中创建一个计算器,但第一个版本工作得很好,但我的新代码当按退格按钮时,它将弹出输入 wstring,但静态中的文本不会改变,但静态中的文本不会改变,但静态中的文本不会改变更新比旧文本更长,它将替换

这是我的代码:

// ...
std::vector<HWND> buttons;
HWND inputBox;
std::wstring input = L"0", prevInput, answer;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
    {
        HFONT hFont = DEFAULT_FONT(DEFAULT_SIZE);

        RECT size{};
        GetClientRect(hWnd, &size);

        int width = size.right - size.left, height = size.bottom - size.top;
        Vector2i boardPos = BOARD_POS(height);
        const int spacing = BUTTON_SPACING;
        Vector2i buttonSize = Vector2i(width / 4 - spacing, (height - boardPos.y) / 4 - spacing);

        for (int row = 0; row < BOARD_ROWS; row++)
        {
            for (int col = 0; col < BOARD_COLUMNS; col++)
            {
                HWND hButton = CreateWindowExW(
                    0L,
                    L"Button",                   // Predefined class; Unicode assumed
                    buttonTexts[row][col].c_str(),                   // Button text
                    WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_OWNERDRAW,  // Styles
                    (spacing + (buttonSize.x + spacing) * col) + boardPos.x,     // X position
                    (spacing + (buttonSize.y + spacing) * row) + boardPos.y,                  // Y position
                    buttonSize.x,                  // Button width
                    buttonSize.y,                  // Button height
                    hWnd,                        // Parent window
                    reinterpret_cast<HMENU>(row * BOARD_COLUMNS + col + 1),    // Button ID
                    (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
                    NULL);                       // Pointer not needed
                SendMessage(hButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(0, TRUE));

                buttons.push_back(hButton); // Store button handle
            }
        }

        inputBox = CreateWindowEx(0L, L"Static", input.c_str(), WS_VISIBLE | WS_CHILD, 0, 0, width, boardPos.y - 0, hWnd, NULL, NULL, NULL);
        SendMessage(inputBox, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(0, TRUE));

        DeleteObject(hFont);

        break;
    }

    case WM_DRAWITEM:
    {
        LPDRAWITEMSTRUCT lpdis = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);

        if (lpdis->CtlID >= 1 && lpdis->CtlID <= buttons.size())
        {
            TEXTMETRIC tm;
            GetTextMetrics(lpdis->hDC, &tm);

            WCHAR symbol[3];
            GetWindowText(lpdis->hwndItem, symbol, 3);

            SIZE textSize;
            GetTextExtentPoint32(lpdis->hDC, symbol, wcslen(symbol), &textSize);

            // Calculate button dimensions
            int buttonWidth = lpdis->rcItem.right - lpdis->rcItem.left;
            int buttonHeight = lpdis->rcItem.bottom - lpdis->rcItem.top;

            // Define the roundness of the rectangle (change this value to adjust the roundness)
            int cornerRadius = 10;

            // Draw the round rectangle button
            HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
            HBRUSH hBrush = CreateSolidBrush(RGB(59, 59, 59));
            SelectObject(lpdis->hDC, hPen);
            SelectObject(lpdis->hDC, hBrush);
            RoundRect(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom, cornerRadius, cornerRadius);

            // Set the background mode and background color for the text
            SetBkMode(lpdis->hDC, TRANSPARENT);
            SetBkColor(lpdis->hDC, RGB(59, 59, 59));

            // Calculate the position to center the text inside the button
            int textX = (buttonWidth - textSize.cx) / 2;
            int textY = (buttonHeight - textSize.cy) / 2;

            // Set the text color to white
            SetTextColor(lpdis->hDC, RGB(255, 255, 255));

            // Draw the text inside the button
            DrawText(lpdis->hDC, symbol, -1, &lpdis->rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

            DeleteObject(hPen);
            DeleteObject(hBrush);
        }

        break;
    }

    case WM_CTLCOLORSTATIC:
    {
        HDC hdcStatic = (HDC)wParam;
        SetBkColor(hdcStatic, RGB(32, 32, 32));  // Set the background color (red in this example)
        SetTextColor(hdcStatic, RGB(255, 255, 255));  // Set the text color (green in this example)
        return (LRESULT)GetStockObject(NULL_BRUSH);  // Return the handle to a null brush to prevent background erasure
    }

    case WM_CHAR:
    {
        int keyCode = (int)wParam;
        std::wstring op = L"+-*/";

        switch (keyCode)
        {
        case VK_BACK:
            if(input.length() > 0)
        {
            input = input.substr(0, input.length() - 1);
            SetWindowText(inputBox, input.c_str());
        }
            break;

        case 0x0D:
            answer = double2wstr(CalculateInput(input));
            input = L"0";
            break;

        default:
            for (int k = 0; k < op.size(); k++)
            {
                if (wParam == op[k]) input += op[k];
            }

            if (keyCode >= 0x30 && keyCode <= 0x39) /* ranges 0...9 */
            {
                input += (wchar_t)keyCode;
            }

            break;
        }
        break;
    }

    case WM_SIZE:
    {

        /* Uncomment if you want when user resize window ratio will use
        {
            RECT size{};
            GetWindowRect(hWnd, &size);

            int width = min(size.right - size.left, size.bottom - size.top), height = width * WINDOW_RATIO;
            SetWindowPos(hWnd, NULL, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER);
        }
        */

        {
            RECT size{};
            GetClientRect(hWnd, &size);

            int width = size.right - size.left, height = size.bottom - size.top;
            Vector2i boardPos = BOARD_POS(height);
            const int spacing = BUTTON_SPACING;
            Vector2i buttonSize = Vector2i(width / BOARD_COLUMNS - spacing, (height - boardPos.y) / BOARD_ROWS - spacing);

            HWND targetButton = buttons[0 * BOARD_COLUMNS + 0];

            RECT button;
            GetClientRect(targetButton, &button);

            // Calculate the new font size based on the window size
            int newFontSize = ((button.right - button.left) + (button.bottom - button.top)) / 4;

            // Create a new font with the updated size
            HFONT hFont = DEFAULT_FONT(newFontSize);

            for (int row = 0; row < BOARD_ROWS; row++)
            {
                for (int col = 0; col < BOARD_COLUMNS; col++)
                {
                    HWND hButton = buttons[row * BOARD_COLUMNS + col]; // Get the button handle from the stored vector

                    SetWindowPos(
                        hButton,
                        NULL,
                        (spacing + (buttonSize.x + spacing) * col) + boardPos.x,
                        (spacing + (buttonSize.y + spacing) * row) + boardPos.y,
                        buttonSize.x,
                        buttonSize.y,
                        SWP_NOZORDER);
                    // Set the new font for the button
                    SendMessage(hButton, WM_SETFONT, WPARAM(hFont), TRUE);

                    // Invalidate the button to trigger a repaint
                    InvalidateRect(hButton, nullptr, TRUE);
                }
            }

            SetWindowPos(inputBox, NULL, 0, 0, width, boardPos.y - 0, SWP_NOZORDER);
            // Set the new font for the button
            SendMessage(inputBox, WM_SETFONT, WPARAM(hFont), TRUE);

            // Invalidate the button to trigger a repaint
            InvalidateRect(inputBox, nullptr, TRUE);
        }

        break;
    }

    case WM_COMMAND:
    {
        // Handle button press
        int buttonID = LOWORD(wParam);

        // special button char
        std::vector<std::wstring> special = { L"\uE94D", L"CE", L"C", L"\uE94F", L"\uE94E" };
        std::vector<std::wstring> op = { L"\uE948", L"\uE949", L"\uE947", L"\uE94A" };

        // Check if the button ID corresponds to one of our buttons
        if (buttonID >= 1 && buttonID <= buttons.size())
        {
            int buttonIndex = buttonID - 1;
            HWND hButton = buttons[buttonIndex];

            WCHAR temp[3];
            GetWindowText(hButton, temp, 3);

            if (!Filter(special, temp))
            {
                if (input.size() != 0 && input[0] == L'0') input.erase(0, 1);
                input += TranslateUnicode(temp);
            }
            else
            {
                if (wcscmp(temp, special[0].c_str()) == 0)
                {
                    NegateNumber(input);
                }
                else if (wcscmp(temp, special[1].c_str()) == 0)
                {
                    EraseFinalNumber(input);
                }
                else if (wcscmp(temp, special[2].c_str()) == 0)
                {
                    input.clear();
                }
                else if (wcscmp(temp, special[3].c_str()) == 0)
                {
                    if (!input.empty()) input.pop_back();
                }
                else if (wcscmp(temp, special[4].c_str()) == 0)
                {
                    answer = double2wstr(CalculateInput(input));
                    input = answer;
                }

                
            }


            SetFocus(hWnd);
        }

        break;
    }

    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
    {
        if (input != prevInput)
        {
            if (answer.empty())
            {
                SetWindowTextW(inputBox, input.c_str());
                prevInput = input;
            }
            else
            {
                SetWindowTextW(inputBox, (prevInput + L"=" + answer).c_str());
                prevInput = input;
            }

            answer.clear();
        }

        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    }

    return 0;
}
// ...

这不是我的完整代码。我的完整代码在这里https://github.com/Octopus-Computer/W32Calc/blob/master/Source/Main.cpp

你能帮我吗?

我尝试使用静态空 SetWindowText(inputBox, L""); 使它们为空,但文本不会改变

c++ winapi
2个回答
0
投票

我不确定这是否能解决您的问题。但是:对于像

VK_BACK
这样的虚拟键代码,您需要处理
WM_KEYDOWN
消息,而不是
WM_CHAR
。请参阅https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-keydown


0
投票

当您使用

SetWindowText(inputBox, ...)
时,您必须告诉父窗口重绘受影响的区域,因为主窗口本身并不知道您的输入框在视觉上发生了变化。为此,每当更新文本时,请为
InvalidateRect()
文本控件的整个工作区设置一个带有
inputBox
的失效矩形,如下所示:

SetWindowTextW(inputBox, input.c_str());
RECT inputBoxRect = {};
GetClientRect(inputBox, &inputBoxRect);
InvalidateRect(hWnd, &inputBoxRect, TRUE);

这里应用于您的窗口过程:

if (input != prevInput) {
    if (answer.empty()) {
        SetWindowTextW(inputBox, input.c_str());
        RECT inputBoxRect = {};
        GetClientRect(inputBox, &inputBoxRect);
        InvalidateRect(hWnd, &inputBoxRect, TRUE);
        prevInput = input;
    } else {
        SetWindowTextW(inputBox, (prevInput + L"=" + answer).c_str());
        RECT inputBoxRect = {};
        GetClientRect(inputBox, &inputBoxRect);
        InvalidateRect(hWnd, &inputBoxRect, TRUE);
        prevInput = input;
    }

    answer.clear();
}
© www.soinside.com 2019 - 2024. All rights reserved.