我想在 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""); 使它们为空,但文本不会改变
我不确定这是否能解决您的问题。但是:对于像
VK_BACK
这样的虚拟键代码,您需要处理WM_KEYDOWN
消息,而不是WM_CHAR
。请参阅https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-keydown
当您使用
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();
}