Win32 API - 如何使可调整大小的文本框类似于 MS-Paint 中的文本

Win32 API - How to make resizable textbox similar to text in MS-Paint

我尝试使用 Visual Studio 为我自己的简单 Paint win32 项目复制 MS-Paint 中的文本按钮。 用户点击按钮,select一个矩形区域作为文本框,然后在中输入文本:

我做了一些研究,但不知道如何将其应用到我的项目中。我试图首先在屏幕上的特定位置创建一个文本框(单击按钮后)并允许用户输入文本(稍后我将尝试弄清楚如何允许用户进入 select 文本区域)。这是代码片段:

HWND textbox; //global variable

//LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            case IDC_TEXTBOX:
                CreateWindowEx(
                    NULL, L"textbox", L"",
                    WS_CHILD | WS_VISIBLE | WS_BORDER,
                    100, 100, 100, 100, hWnd, (HMENU)0, NULL, NULL
                );


                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
case WM_CREATE:
        CreateWindowEx(NULL, L"BUTTON", L"CreateTextBox",
            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 10, 150, 40, hWnd,
            (HMENU)IDC_TEXTBOX, NULL, NULL);
        break;

结果如下:

很简单,但是我写的代码不起作用。单击按钮后不会出现文本框。因此,取得了零进展,我不知道现在该做什么。所以问题是:为什么我的解决方案失败了?以及 如何在我的项目中正确实现 MS-Paint 中的文本按钮?

感谢大家的评论,我找到了解决方案,它们是:

  1. 为什么我的问题的解决方案失败了:“文本框”不是正确的windowclass。在这种情况下,我将它们更改为编辑(更多关于 EDIT control)并且我需要的 window 出现了。

  2. 如何在我的项目中实现 MS-Paint 中的文本按钮:当用户按住鼠标左键时按钮并拖动鼠标到 select 文本区域,我们绘制一个矩形。当鼠标左键弹起时(用户已完成 selecting 文本区域),我们在矩形区域中创建一个 window。这是相关代码:

int fromX, fromY;
int toX, toY;
bool isPreview;
bool isDrawingTextbox = false;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        HANDLE_MSG(hWnd, WM_CREATE, OnCreate);
        HANDLE_MSG(hWnd, WM_COMMAND, OnCommand);
        HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy);
        HANDLE_MSG(hWnd, WM_PAINT, OnPaint);
        HANDLE_MSG(hWnd, WM_LBUTTONDOWN, OnLButtonDown);
        HANDLE_MSG(hWnd, WM_LBUTTONUP, OnLButtonUp);
        HANDLE_MSG(hWnd, WM_MOUSEMOVE, OnMouseMove);

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

BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
    CreateWindowEx(NULL, L"BUTTON", L"CreateTextBox",
        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 10, 150, 40, hwnd,
        (HMENU)IDC_TEXTBOX, NULL, NULL);

    return TRUE;
}

void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
    switch (id)
    {
    case IDC_TEXTBOX:
        isDrawingTextbox = true;
        break;
    default:
        break;
    }
}

void OnDestroy(HWND hwnd)
{
    PostQuitMessage(0);
}

void OnPaint(HWND hwnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    if (isDrawingTextbox) {
        HPEN hPen = CreatePen(PS_DASHDOT, 3, RGB(0, 0, 0));
        Rectangle(hdc, fromX, fromY, toX, toY);
    }
 

    EndPaint(hwnd, &ps);
}

void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
    isPreview = true;
    fromX = x;
    fromY = y;

    HDC hdc = GetDC(hwnd);
    MoveToEx(hdc, x, y, NULL);
}

void OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
{
    isPreview = false;
    
    if (isDrawingTextbox) {
        if (toY < fromY) {
            int temp = fromY;
            fromY = toY;
            toY = temp;
        }

        if (toX < fromX) {
            int temp = fromX;
            fromX = toX;
            toX = temp;
        }

        int width = abs(fromX - toX);
        int height = abs(fromY - toY);
        CreateWindowEx(
            NULL, L"EDIT", L"",
            WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE,
            fromX, fromY, width, height, hwnd, (HMENU)0, NULL, NULL
        );
    }
}

void OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
{
    if (isPreview) {
        toX = x;
        toY = y;

        InvalidateRect(hwnd, NULL, TRUE);
    }
}

这是我自己解决问题的方法。请随时回答您更好的解决方案。