【发布时间】:2021-08-18 16:14:41
【问题描述】:
我试图在我的 ui 窗口内的一个特殊矩形中显示用户输入的颜色。 到目前为止,我能够读出用户颜色输入,但不知何故,我绘制的矩形的颜色没有改变。 我尝试使用 InvalidateRect(wnd, NULL, TRUE) 导致窗口重绘,但它不起作用。
似乎我不了解有关 winapi 运行时功能的基本知识。这是我的 cmets 代码:
#include <windows.h>
#include <shlobj.h>
#include <string>
#include <iostream>
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
void createEditProc(HWND);
HWND hColorInput;
WNDPROC ColorEditProc;
struct color {
float r;
float g;
float b;
};
color current_color = { 1, 0.5, 1 };
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"myWindowClass";
wc.lpfnWndProc = WindowProcedure;
if (!RegisterClassW(&wc))
return -1;
HWND hWnd = CreateWindowW(L"myWindowClass", L"My Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 570, 330, NULL, NULL, NULL, NULL);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
createEditProc(hWnd);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HBRUSH newBrush = CreateSolidBrush(RGB(floor(current_color.r * 255), floor(current_color.g * 255), floor(current_color.b * 255)));
HGDIOBJ oldBrush = SelectObject(hdc, newBrush);
Rectangle(hdc, 10, 10, 200, 200);
SelectObject(hdc, oldBrush);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
}
std::string read_textInput(HWND hEdit) {
wchar_t colorcode0[1000];
GetWindowTextW(hEdit, colorcode0, 1000);
std::wstring ws(colorcode0);
std::string colorcode(ws.begin(), ws.end());
return colorcode;
}
LRESULT CALLBACK subEditProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
switch (wParam)
{
case VK_RETURN:
{
std::string color_text = read_textInput(hColorInput);
char* cstr = new char[color_text.length() + 1];
strcpy_s(cstr, color_text.length() + 1, color_text.c_str());
int r, g, b;
sscanf_s(cstr, "%02x%02x%02x", &r, &g, &b);
current_color.r = r / 255.;
current_color.g = g / 255.;
current_color.b = b / 255.;
InvalidateRect(wnd, NULL, TRUE); // is it correct?
}
break; //or return 0; if you don't want to pass it further to def proc. If not your key, skip to default:
}
default:
return CallWindowProc(ColorEditProc, wnd, msg, wParam, lParam);
}
return 0;
}
void createEditProc(HWND hWnd)
{
hColorInput = CreateWindowW(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, 465, 30, 65, 25, hWnd, NULL, NULL, NULL);
ColorEditProc = (WNDPROC)SetWindowLongPtr(hColorInput, GWLP_WNDPROC, (LONG_PTR)subEditProc);
}
函数subEditProc在用户按下回车后读取用户输入的十六进制颜色代码并将其放入current_color结构中。
在我的WM_PAINT 函数中,Rectangle 是用这种颜色的newBrush 绘制的。不知何故,尽管当用户点击 enter 时我的 current_color 确实正确更改,但它从未在 newBrush 中更新。
据我了解,我应该在某处添加重绘功能。可以借助 redrawwindow 函数。但奇怪的是,我从未遇到过使用此功能的工作示例。
我在处理消息WM_KEYDOWN 时添加了InvalidateRect(wnd, NULL, TRUE)。但我不认为这是正确的。此外,当我更改窗口大小并调用消息WM_PAINT 时,它不会更改颜色。
【问题讨论】:
-
InvalidateRect的第一个参数应该是传递编辑窗口句柄时要重绘的窗口的句柄。 -
另外,每次执行
WM_PAINT处理程序时都会泄漏一个画笔对象。使用完画笔后调用DeleteObject,或者使用GetStockObject(DC_BRUSH)和SetDCBrushColor而不是创建实心画笔对象。 -
感谢 cmets。我纠正了舔。关于 InvalidateRect 中的正确句柄...我认为它得到了
wnd句柄。然后这个wnd句柄参与createEditProc 函数,该函数与hWnd句柄(主窗口的句柄)一起使用? -
传入子类控件的自定义窗口过程的
wnd与传入常规窗口过程的hWnd无关。您将不得不以一种或另一种方式获取编辑控件的父窗口句柄。然而,更容易的是,甚至不要子类化编辑控件,并在父窗口中处理 EN_CHANGE 通知。 -
我听从了你的第一个建议,它奏效了!非常喜欢。我发布了一个带有更新的工作代码的答案。