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



我确实在WM_PAINT中创建了一个新的矩形,但为了改变文本,我也SetWindowText(),我需要一个InvalidateRect(),所以它对我来说似乎很hackky。正确的做法是什么?我不确定我是否计算正确的高度和宽度。我试过使用SetWindowPos()从WM_PAINT增长,但它失败了,所以我切换到使用Rectangle()绘制它。我这样做是因为我想让文本垂直居中,但静态控制不支持,所以我自己去做绘画,这样我就可以使用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, s, -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, -1);
FillRect(dc, &rt, GetSysColorBrush(COLOR_BTNFACE));
SetBkMode(dc, TRANSPARENT);
DrawText(dc, s, -1, &rt, 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, NULL, 
hInstance, NULL);
ghInstance = hInstance;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DeleteObject(hdDfaultFont);
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
btn =
CreateWindow(L"static", L"init text",
SS_NOTIFY |
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
0, 0, 20, 30,
hwnd, (HMENU) BTN_ID, NULL, 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, 
hwnd, (HMENU) BTN2_ID,
NULL, NULL);
SetDefaultFont(btn2);
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case BTN2_ID:
{
SetWindowText(btn, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0");
InvalidateRect(btn, NULL, TRUE);
}
break;
}
}
break;    

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, 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, s, len+1);
int flags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
HDC dc = BeginPaint(hwnd, &ps);

// calculate the width and height
DrawText(dc, s, -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);
InflateRect(&rt, -1, -1);
FillRect(dc, &rt, GetSysColorBrush(COLOR_BTNFACE));
SetBkMode(dc, TRANSPARENT);
DrawText(dc, s, -1, &rt, flags);
EndPaint(hwnd, &ps);
return 0;
}
break;
}
return CallWindowProc(oldButtonProc, hwnd, msg, wParam, 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, s, 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, s, -1, &rt, flags);
EndPaint(hwnd, &ps);
return 0;
}

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

SS_CENTERIMAGE-位图位于包含它的静态控件的中心。没有调整控件的大小,因此对于控件来说太大的位图将被剪切。如果静态控件包含单行文本,则该文本垂直居中于控件的客户端区域。

最新更新