1

我正在使用 WinAPI 创建一个 Windows 应用程序。在处理窗口的消息时,我正在使用该TextOut()函数向用户显示更新的文本。WM_PAINT

case WM_PAINT:
{
     PAINTSTRUCT ps;
     HDC hdc;
     hdc = BeginPaint(hwnd, &ps);
     SelectObject(hdc, hfDefault);

     // display the user data in the window
     TextOut(hdc,10,70, "Points: 0", 9);
     TextOut(hdc,10,85, "Level: 0", 8);

     // ...
     EndPaint(hwnd, &ps);
}
break;

如何更改TextOut()调用函数后打印的文本以及确定打印文本长度的最后一个参数?

我发现关于使用的一切都是TextOut()关于文本字体的。

4

2 回答 2

4

也许是这样的......

// I'll assume hwnd is global
void OnSomeActionToRefreshValues()
{
    HDC hdc = ::GetDc(hwnd);
    DrawValues(hdc, 88, 99);
    ReleaseDC(hdc);
}

void DrawValues(HDC hdc, int points, int level)
{
    // Might need a rectangle here to overwrite old text
    SelectObject(hdc, hfDefault);    // I assume hfDefault is global
    TCHAR text[256];
    swprintf_s(text, 256, L"Points: %d", points);
    TextOut(hdc, 10, 70, text, wcslen(text));
    swprintf_s(text, 256, L"Level: %d", level);
    TextOut(hdc, 10, 85, text, wcslen(text));
}

在你赢得过程中:

case WM_PAINT:
    PAINTSTRUCT ps;
    HDC hdc;
    hdc = BeginPaint(hwnd,&ps);
    DrawValues(hdc, 88, 99);
    EndPaint(hwnd,&ps);
    break;
于 2014-02-26T19:24:39.863 回答
0

为了在处理WM_PAINT消息时更新窗口中显示的文本,您需要有一些源来显示文本字符串。

由于您的原始帖子有些陈旧,Windows API 已随着新版本的 Windows 发生变化,当前版本的 Windows 10 和 Windows 11 已经处于测试阶段。

Windows 因为 Windows XP 是 WinAPI 的 16 位 UNICODE,所以人们大多使用wchar_t文本字符。这要求文本字符串常量需要L修饰符,如L"wchar_t text".

使用 Visual Studio 2019,我整理了一个在 Windows 10 上运行的简单示例。这是一个简单的 Windows WinAPI 桌面 GUI 应用程序。我从 Visual Studio 中的一个新项目开始,并让 IDE 为带有wWinMain()MyRegisterClass()InitInstance()WndProc().

然后我修改了生成的源代码以执行以下操作:

  • 在主窗口中出现四个按钮以允许数据更改
  • 显示两个文本字符串,这些字符串使用按钮点击次数进行更新

我选择使用默认字体,所以没有做任何修改用于显示文本的字体。如果您需要修改字体,您需要添加代码来创建您想要的字体,选择新字体到HDC用于绘制文本,然后使用TextOut()新字体绘制文本。使用字体后,您需要将其换回,然后将其删除。

在此处输入图像描述

第一步是创建一个用于管理按钮和按钮点击的数据区域。我选择在InitInstance().

static struct {
    const wchar_t* txt;    // pointer to text to display on button face
    int      iCount;       // count of number of times button clicked
    HWND     hwnd;         // button window handle which identifies the button
} myButtons[] = {
    {L"Points up", 0, 0},
    {L"Points dwn", 0, 0},
    {L"Level up", 0, 0},
    {L"Level dwn", 0, 0}
};

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   // create the displayed window along with the buttons.
   // the buttons are in a single row at the top of the window.

   POINT myPoint = { 10, 10 };  // x, y

   for (auto &a : myButtons) {
       a.hwnd = CreateWindow(
           L"BUTTON",  // Predefined class; Unicode assumed 
           a.txt,      // Button text 
           WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles 
           myPoint.x,  // x position 
           myPoint.y,  // y position 
           100,        // Button width
           50,         // Button height
           hWnd,       // Parent window
           NULL,       // No menu.
           (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
           NULL);      // Pointer not needed.

       myPoint.x += 100 + 20;    // button width plus a separation distance
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

更新显示窗口的源代码如下。我们有两个函数,一个按钮单击处理程序来确定单击了哪个按钮,以及一个修改显示窗口WndProc()的消息处理程序。WM_PAINT

// process a button click event and return an indication
// whether the button handle matches one we are managing (1)
// or not managing (0).
int buttonClick(HWND hWnd, HWND hButton)
{
    // look through the list of buttons to see if the window handle
    // of the button event matches one of our buttons.
    for (auto &a : myButtons) {
        if (a.hwnd == hButton) {
            // this is one of our buttons so we increment button click count.
            // then invalidate the window area and update to trigger WM_PAINT message.
            a.iCount++;
            InvalidateRect(hWnd, NULL, TRUE);
            UpdateWindow(hWnd);
            return 1;    // indicate we processed this event.
        }
    }
    return 0;    // indicate we did not process this event
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            int wmCode = HIWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                // not a menu event so see if it is a button click or not.
                if (wmCode == BN_CLICKED) {
                    // if we are managing this button then we skip
                    // the DefWindowProc() otherwise it is called.
                    if (buttonClick(hWnd, (HWND)lParam))
                        break;
                }
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);

            // TODO: Add any drawing code that uses hdc here...

            // create the text strings we are going to display/update

            wchar_t myText[2][64];
            // following swprintf_s() works because template
            // generates the proper call with the additional buffer
            // size argument.
            swprintf_s(myText[0], L"Points: %d", myButtons[0].iCount - myButtons[1].iCount);
            swprintf_s(myText[1], L"Level: %d", myButtons[2].iCount - myButtons[3].iCount);

            // get the text metrics of the font we are using to draw the text so
            // that we can find out how tall the letters are and can adjust the
            // distance for each line of text properly.
            TEXTMETRIC myTextMetric = { 0 };
            GetTextMetrics(hdc , &myTextMetric);

            // we will use a POINT struct for maintaining the point at which
            // the text output will start. x coordinate is horizontal position
            // and y coordinate is the vertical position.
            POINT myPoint = { 10, 150 };  // x, y
            int   myMargin = 5;

            // iterate over the list of strings we are displaying and
            // display each one on a separate line.
            for (auto &a : myText) {
                TextOut(hdc, myPoint.x, myPoint.y, a, wcslen(a));
                myPoint.y += myTextMetric.tmHeight + myMargin;
            }

            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
于 2021-08-25T17:51:52.620 回答