如何根据文本大小自动正确增长标签?

问题描述

我确实在 WM_PAINT 中创建了一个新矩形,但为了更改文本,我还 SetWindowText(),我需要一个 InvalidateRect() 所以它对我来说似乎很hacky。这样做的正确方法是什么?我不确定我是否正确计算了正确的高度和宽度。我曾尝试使用 WM_PAINT 中的 SetWindowPos() 进行增长,但它失败了,所以我切换到使用 Rectangle() 绘制它。我这样做是因为我想要文本 o 垂直居中,但静态控件不支持它,所以我自己去做了 paiting,这样我就可以使用 DrawText()DT_CENTER | DT_SINGLELINE | DT_VCENTER 标志。以下是我处理 VM_PAINT 的方式:

case WM_PAINT:
        { 
            PAINTSTRUCT ps;
            RECT rt = {0};
            GetClientRect(hwnd,&rt);
            
            int height = rt.right - rt.left;
            int width = rt.bottom - rt.top;
            int len = GetwindowTextLength(hwnd);
            wchar_t s[len+1];
            GetwindowText(hwnd,s,len+1);
            int flags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
            HDC dc = BeginPaint(hwnd,&ps);
            
            // calculate the width and height
            DrawText(dc,-1,&rt,DT_CALCRECT | flags);
            width += rt.right;
            height += rt.bottom;
            
            // update width and height
            rt.right = width;
            rt.bottom = height;

            Rectangle(dc,rt.left,rt.top,rt.right,rt.bottom);

            // this prevent from painting the border. 
            InflateRect(&rt,-1);
            FillRect(dc,GetSysColorBrush(COLOR_BTNFACE));
            SetBkMode(dc,TRANSPARENT);
            DrawText(dc,flags);
            EndPaint(hwnd,&ps);
            return 0;
        }
        

完整代码

#pragma comment(lib,"user32.lib")
#pragma comment(lib,"Comctl32.lib")
#pragma comment(lib,"Gdi32.lib")

#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE

#include <windows.h>
#include <Commctrl.h>
#include <crtdbg.h>
#include <strsafe.h>
#include <string.h>
#include <assert.h>

LRESULT CALLBACK WndProc(HWND,UINT,WParaM,LParaM);
LRESULT CALLBACK ButtonProc(HWND hwnd,UINT uMsg,WParaM wParam,LParaM lParam);

WNDPROC oldButtonProc;
HINSTANCE ghInstance;
HWND hTab;
HFONT hdDfaultFont;
HWND btn;

enum 
{
    BTN_ID = 10,BTN2_ID,};


int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PWSTR pCmdLine,int nCmdshow)
{

    MSG  msg = {0};
    HWND hwnd;
    WNDCLASSW wc = {0};

    wc.lpszClassName = L"Window";
    wc.hInstance     = hInstance;
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpfnWndProc   = WndProc;
    wc.hCursor = LoadCursor(0,IDC_ARROW);
    
    //InitComControls();
    if(!RegisterClass(&wc)) {
        return -1;
    }

    int width = 540;
    int height = 460;
    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight = GetSystemMetrics(SM_CYSCREEN);
    int cx = (screenWidth - width) / 2;
    int cy = (screenHeight - height) / 2;
    hwnd = CreateWindowW(wc.lpszClassName,L"Window",WS_OVERLAPPEDWINDOW | WS_VISIBLE,cx,cy,width,height,NULL,hInstance,NULL);
    ghInstance = hInstance;

    while (GetMessage(&msg,0))
    {
        if (!IsDialogMessage(hwnd,&msg))
        {
            TranslateMessage(&msg);
            dispatchMessage(&msg);
        }
    }

    DeleteObject(hdDfaultFont);
    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,LParaM lParam)
{

  switch(msg)
  {
      case WM_CREATE:
      {
            btn =
            CreateWindow(L"static",L"init text",SS_NOTIFY |
                WS_VISIBLE | WS_CHILD | WS_TABSTOP,20,30,hwnd,(HMENU) BTN_ID,NULL);
            oldButtonProc = (WNDPROC) SetwindowLongPtr(btn,GWLP_WNDPROC,(LONG_PTR) ButtonProc);
            HWND btn2 =
            CreateWindow(L"Button",L"Click me!",WS_VISIBLE | WS_CHILD | WS_TABSTOP,10,50,70,25,(HMENU) BTN2_ID,NULL);
            SetDefaultFont(btn2);
      }
      break;

    case WM_COMMAND:
    {
        switch(LOWORD(wParam))
        {
            case BTN2_ID:
            {
                SetwindowText(btn,L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0");
                InvalidateRect(btn,TRUE);
            }
            break;
        }
    }
    break;    
    
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
  }

  return DefWindowProc(hwnd,msg,wParam,lParam);
}

LRESULT CALLBACK ButtonProc(HWND hwnd,LParaM lParam)
{
    switch(msg)
    {
        case WM_PAINT:
        { 
            PAINTSTRUCT ps;
            RECT rt = {0};
            GetClientRect(hwnd,&rt);
            
            int height = rt.right - rt.left;
            int width = rt.bottom - rt.top;
            
            int len = GetwindowTextLength(hwnd);
            wchar_t s[len+1];
            GetwindowText(hwnd,len+1);

            int flags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
            HDC dc = BeginPaint(hwnd,DT_CALCRECT | flags);
            width += rt.right;
            height += rt.bottom;
            
            // update width and height
            rt.right = width;
            rt.bottom = height;
            Rectangle(dc,rt.bottom);
            InflateRect(&rt,&ps);
            return 0;
        }
        break;
    }

    return CallWindowProc(oldButtonProc,lParam);
}

解决方法

您可以使用 GetTextExtentPoint32 来查找字符串长度,然后您无需进行计算。

case WM_PAINT:
{
    PAINTSTRUCT ps;
    RECT rt = { 0 };
    GetClientRect(hwnd,&rt);
    int len = GetWindowTextLength(hwnd);
    wchar_t s[len + 1];
    GetWindowText(hwnd,s,len + 1);
    int flags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
    HDC dc = BeginPaint(hwnd,&ps);

    SIZE sz;
    GetTextExtentPoint32(dc,len,&sz);
    rt.right = sz.cx + 10;  //I added 10 to make the display less crowded.
    rt.bottom = sz.cy;

    Rectangle(dc,rt.left,rt.top,rt.right,rt.bottom);

    // this prevent from painting the border. 
    InflateRect(&rt,-1,-1);
    FillRect(dc,&rt,GetSysColorBrush(COLOR_BTNFACE));
    SetBkMode(dc,TRANSPARENT);
    DrawText(dc,flags);
    EndPaint(hwnd,&ps);
    return 0;
}
,

为了回答 X 问题的 XY 部分,DT_VCENTER | DT_SINGLELINE 意味着单行文本,在这种情况下,具有 SS_CENTERIMAGE 样式的静态控件将使文本居中垂直文本。

SS_CENTERIMAGE - 位图在包含它的静态控件中居中。控件未调整大小,因此对于控件来说太大的位图将被剪裁。 如果静态控件包含单行文本,则文本在客户区中垂直居中控制。