Create a window without a title, with a variable dimension and without a fictitious white stripe of 6 pixels

I want a window without a title, but with resizable and shadowed. This can be easily achieved by removing WS_CAPTION and adding WS_THICKFRAME, however, starting with Windows 10, there is a white area without a 6px click.

Using the following code, I create a window and paint the entire client area in black, the window receives transparent fields to the left, right and bottom by 6 pixels, but the top margin is white.

#ifndef UNICODE #define UNICODE #endif #include <windows.h> LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) { // Register the window class. const wchar_t CLASS_NAME[] = L"Sample Window Class"; WNDCLASS wc = { }; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME; RegisterClass(&wc); // Create the window. HWND hwnd = CreateWindowEx( 0, // Optional window styles. CLASS_NAME, // Window class L"", // Window text 0, // Size and position CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, // Parent window NULL, // Menu hInstance, // Instance handle NULL // Additional application data ); ShowWindow(hwnd, nCmdShow); LONG lStyle = GetWindowLong(hwnd, GWL_STYLE); lStyle |= WS_THICKFRAME; lStyle = lStyle & ~WS_CAPTION; SetWindowLong(hwnd, GWL_STYLE, lStyle); SetWindowPos(hwnd, NULL, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER); // Run the message loop. MSG msg = { }; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); // Paint everything black FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOWTEXT)); EndPaint(hwnd, &ps); } return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } 

Renders: image showing a problem

How to remove a white strip? I also found this related Qt QTBUG-47543 error report , which was closed as not a Qt problem, because it can be played using win32 api.

+10
source share
5 answers

It's not a mistake. On Windows 10, the left / right / bottom borders are transparent. The upper border is not transparent. You must leave it as it is. Probably no one will complain.

To change it, you must change the scope without a client. This is quite complicated in Windows Vista and higher. See Custom Window Frame using DWM for reference.

  • Find border thickness

  • Use DwmExtendFrameIntoClientArea to access a non-client area

  • Use BeginBufferedPaint to paint an opaque color over a non-client area.

Example Windows 10:

enter image description here

(see the following compatibility example with Windows Vista, 7, 8)

 //requires Dwmapi.lib and UxTheme.lib #include <Windows.h> #include <Dwmapi.h> void my_paint(HDC hdc, RECT rc) { HBRUSH brush = CreateSolidBrush(RGB(0, 128, 0)); FillRect(hdc, &rc, brush); DeleteObject(brush); } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static RECT border_thickness; switch (uMsg) { case WM_CREATE: { //find border thickness SetRectEmpty(&border_thickness); if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_THICKFRAME) { AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL); border_thickness.left *= -1; border_thickness.top *= -1; } else if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_BORDER) { SetRect(&border_thickness, 1, 1, 1, 1); } MARGINS margins = { 0 }; DwmExtendFrameIntoClientArea(hwnd, &margins); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); break; } case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); RECT rc = ps.rcPaint; BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE }; HDC memdc; HPAINTBUFFER hbuffer = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, &params, &memdc); my_paint(memdc, rc); BufferedPaintSetAlpha(hbuffer, &rc, 255); EndBufferedPaint(hbuffer, TRUE); EndPaint(hwnd, &ps); return 0; } case WM_NCACTIVATE: return 0; case WM_NCCALCSIZE: if (lParam) { NCCALCSIZE_PARAMS* sz = (NCCALCSIZE_PARAMS*)lParam; sz->rgrc[0].left += border_thickness.left; sz->rgrc[0].right -= border_thickness.right; sz->rgrc[0].bottom -= border_thickness.bottom; return 0; } break; case WM_NCHITTEST: { //do default processing, but allow resizing from top-border LRESULT result = DefWindowProc(hwnd, uMsg, wParam, lParam); if (result == HTCLIENT) { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; ScreenToClient(hwnd, &pt); if (pt.y < border_thickness.top) return HTTOP; } return result; } case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int) { const wchar_t CLASS_NAME[] = L"Sample Window Class"; WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = CLASS_NAME; RegisterClass(&wc); CreateWindowEx(0, CLASS_NAME, NULL, WS_VISIBLE | WS_THICKFRAME | WS_POPUP, 10, 10, 600, 400, NULL, NULL, hInstance, NULL); MSG msg = {}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } 

For compatibility with Windows Vista / 7/8, use this procedure. This will draw the borders to the left / top / bottom as well as the top border. This window will appear as a simple rectangle with varying sizes:

enter image description here

 //for Windows Vista, 7, 8, 10 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static RECT border_thickness; switch (uMsg) { case WM_CREATE: { //find border thickness SetRectEmpty(&border_thickness); if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_THICKFRAME) { AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL); border_thickness.left *= -1; border_thickness.top *= -1; } else if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_BORDER) { SetRect(&border_thickness, 1, 1, 1, 1); } MARGINS margins = { 0 }; DwmExtendFrameIntoClientArea(hwnd, &margins); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); break; } case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); RECT rc = ps.rcPaint; BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE }; HDC memdc; HPAINTBUFFER hbuffer = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, &params, &memdc); my_paint(memdc, rc); BufferedPaintSetAlpha(hbuffer, &rc, 255); EndBufferedPaint(hbuffer, TRUE); EndPaint(hwnd, &ps); return 0; } case WM_NCACTIVATE: return 0; case WM_NCCALCSIZE: if (lParam) return 0; case WM_NCHITTEST: { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; ScreenToClient(hwnd, &pt); RECT rc; GetClientRect(hwnd, &rc); enum {left=1, top=2, right=4, bottom=8}; int hit = 0; if (pt.x < border_thickness.left) hit |= left; if (pt.x > rc.right - border_thickness.right) hit |= right; if (pt.y < border_thickness.top) hit |= top; if (pt.y > rc.bottom - border_thickness.bottom) hit |= bottom; if (hit & top && hit & left) return HTTOPLEFT; if (hit & top && hit & right) return HTTOPRIGHT; if (hit & bottom && hit & left) return HTBOTTOMLEFT; if (hit & bottom && hit & right) return HTBOTTOMRIGHT; if (hit & left) return HTLEFT; if (hit & top) return HTTOP; if (hit & right) return HTRIGHT; if (hit & bottom) return HTBOTTOM; return HTCLIENT; } case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } 
+3
source

Just a little more detailed; to remove the white bar, you just need to remove the corresponding value from the first rectangle in NCCALCSIZE. pywin32 code:

  if msg == WM_NCCALCSIZE: if wParam: res = CallWindowProc( wndProc, hWnd, msg, wParam, lParam ) sz = NCCALCSIZE_PARAMS.from_address(lParam) sz.rgrc[0].top -= 6 # remove 6px top border! return res 
+2
source

Change the style of the dialogue.

 LONG lStyle = GetWindowLong(hwnd, GWL_STYLE); lStyle |= WS_THICKFRAME; // 6px white stripe cause of this. lStyle = lStyle & ~WS_CAPTION; 
0
source

I was looking for ways to remove the title bar from my application, and the code in this post does exactly what I want.

However, when I compiled the code and added the following, I noticed that the dialog does not receive user input !!! I can move the window around the screen, but I cannot close it.

 case WM_CHAR: { if ( 'i' == wParam) MessageBoxA( hwnd , "All done....", "Info!", MB_OK|MB_ICONINFORMATION) ; break; } 

Any ideas how to fix this ????

0
source

@Sergio Martins: What is the โ€œrightโ€ solution to remove 6px white lines in a Qt application now? Since QTBUG-47543 is already closed, and lStyle | = WS_THICKFRAME only removes the shadow and makes the window not movable.

0
source

Source: https://habr.com/ru/post/1257343/


All Articles