I did create a new rectangle in the WM_PAINT
but in order to change the text, I also SetWindowText()
, I need a InvalidateRect()
so it seems quite hacky to me. What's the proper way to do that? I'm not sure if I'm calculating the proper height and width properly either. I've tried grow using SetWindowPos()
from WM_PAINT but it failed so I switch to draw it using Rectangle()
. I did that because I wanted the text o vertical center but static control doesn't support that, so I went to do the paiting myself so I can use DrawText()
with DT_CENTER | DT_SINGLELINE | DT_VCENTER
flags. Here's how I'm handling 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;
}
full code:
#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);
}
You can use GetTextExtentPoint32 to find the string length and then you don't need to do calculations.
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;
}