【问题标题】:update color in runtime in winapi window using gdi使用 gdi 在 winapi 窗口中的运行时更新颜色
【发布时间】: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 通知。
  • 我听从了你的第一个建议,它奏效了!非常喜欢。我发布了一个带有更新的工作代码的答案。

标签: c++ winapi gdi


【解决方案1】:

刚刚理解了我的错误,在这里我为需要这种功能的人发布了一个工作示例:

#include <windows.h>
#include <shlobj.h>
#include <string>
#include <iostream>

LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);

void createEditProc(HWND);

HWND hColorInput, hWnd, hMainWindow;
WNDPROC ColorEditProc;

struct color {
    float r;
    float g;
    float b;
};
color current_color = { 1, 0.5, 1 }; // We set initial color of the window.

// Here is the main window. Here I define the handle hMainWindow to repaint it later.

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;

    hMainWindow = 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;
}


// WinMain call back function

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);
        DeleteObject(newBrush);
        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(hMainWindow, NULL, TRUE); // here I pass hMainWindow handle causing it to repaint.
        }
        break; 
        }
    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);
}


【讨论】:

    猜你喜欢
    • 2018-03-15
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 1970-01-01
    • 2012-10-15
    • 1970-01-01
    • 2018-01-26
    • 2018-04-07
    相关资源
    最近更新 更多