【问题标题】:C++ WinAPI TextOut() update textC++ WinAPI TextOut() 更新文本
【发布时间】:2014-03-29 20:00:28
【问题描述】:

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

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() 的所有内容都与文本字体有关。

【问题讨论】:

  • 你不能。使用不同的文本再次调用TextOut,或使窗口无效以强制重绘。
  • 您不必等到 WM_PAINT。请改用GetDC
  • 举个例子会不会很多?

标签: c++ windows winapi wm-paint textout


【解决方案1】:

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

// 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;

【讨论】:

    【解决方案2】:

    为了在处理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() 为 Windows 桌面 GUI 应用程序生成框架。

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

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

    我选择使用默认字体,所以没有做任何修改用于显示文本的字体。如果您需要修改字体,您需要添加代码来创建您想要的字体,将新字体选择到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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-14
      • 2015-10-23
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      • 2016-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多