创建没有标题栏的窗口,具有可调整大小的边框并且没有虚假的 6px 白色条纹 [英] Create window without titlebar, with resizable border and without bogus 6px white stripe
问题描述
我想要一个没有标题栏但有可调整大小的框架和阴影的窗口.这可以通过删除 WS_CAPTION 并添加 WS_THICKFRAME 轻松实现,但是,从 Windows 10 开始,有一个 6px 白色非客户区.
使用下面的代码,我创建了一个窗口并将所有客户区涂成黑色,窗口的左、右和下 6px 透明边距,但上边距是白色的.
#ifndef UNICODE#define UNICODE#万一#include <windows.h>LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow){//注册窗口类.const wchar_t CLASS_NAME[] = L"示例窗口类";WNDCLASS wc = { };wc.lpfnWndProc = WindowProc;wc.hInstance = hInstance;wc.lpszClassName = CLASS_NAME;注册类(&wc);//创建窗口.HWND hwnd = CreateWindowEx(0,//可选的窗口样式.CLASS_NAME,//窗口类L"",//窗口文本0,//大小和位置CW_USEDEFAULT、CW_USEDEFAULT、CW_USEDEFAULT、CW_USEDEFAULT、NULL,//父窗口NULL,//菜单hInstance,//实例句柄NULL//附加应用数据);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);//运行消息循环.味精味精 = { };while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}返回0;}LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){开关(微信){案例 WM_DESTROY:PostQuitMessage(0);返回0;案例 WM_PAINT:{油漆结构 ps;HDC hdc = BeginPaint(hwnd, &ps);//把所有东西都涂黑FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOWTEXT));EndPaint(hwnd, &ps);}返回0;}返回 DefWindowProc(hwnd, uMsg, wParam, lParam);}
渲染:
如何去除白色条纹?我还发现了这个相关的 Qt 错误报告
(请参阅下一个示例以了解与 Windows Vista、7、8 的兼容性)
//需要 Dwmapi.lib 和 UxTheme.lib#include <Windows.h>#include <Dwmapi.h>void my_paint(HDC hdc, RECT rc){HBRUSH 笔刷 = CreateSolidBrush(RGB(0, 128, 0));FillRect(hdc, &rc, 画笔);删除对象(画笔);}LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){静态矩形边框厚度;开关(微信){案例 WM_CREATE:{//查找边框粗细SetRectEmpty(&border_thickness);if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_THICKFRAME){AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);边框厚度.左 *= -1;边界厚度.top *= -1;}else if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_BORDER){SetRect(&border_thickness, 1, 1, 1, 1);}边距 = { 0 };DwmExtendFrameIntoClientArea(hwnd, &margins);SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);休息;}案例 WM_PAINT:{油漆结构 ps;HDC hdc = BeginPaint(hwnd, &ps);RECT rc = ps.rcPaint;BP_PAINTPARAMS 参数 = { sizeof(params), BPPF_NOCLIP |BPPF_ERASE };HDC 内存;HPAINTBUFFER hbuffer = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, ¶ms, &memdc);my_paint(memdc, rc);BufferedPaintSetAlpha(hbuffer, &rc, 255);EndBufferedPaint(hbuffer, TRUE);EndPaint(hwnd, &ps);返回0;}案例 WM_NCACTIVATE:返回0;案例 WM_NCCALCSIZE:如果(l参数){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;返回0;}休息;案例 WM_NCHITTEST:{//进行默认处理,但允许从上边框调整大小LRESULT 结果 = DefWindowProc(hwnd, uMsg, wParam, lParam);如果(结果 == HTCLIENT){POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };ScreenToClient(hwnd, &pt);if (pt.y
为了与 Windows Vista/7/8 兼容,请改用此过程.这将在左/上/下边框以及上边框上绘制.此窗口将显示为一个简单的矩形,并调整边框:
//适用于 Windows Vista、7、8、10LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){静态矩形边框厚度;开关(微信){案例 WM_CREATE:{//查找边框粗细SetRectEmpty(&border_thickness);if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_THICKFRAME){AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);边框厚度.左 *= -1;边界厚度.top *= -1;}else if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_BORDER){SetRect(&border_thickness, 1, 1, 1, 1);}边距 = { 0 };DwmExtendFrameIntoClientArea(hwnd, &margins);SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);休息;}案例 WM_PAINT:{油漆结构 ps;HDC hdc = BeginPaint(hwnd, &ps);RECT rc = ps.rcPaint;BP_PAINTPARAMS 参数 = { sizeof(params), BPPF_NOCLIP |BPPF_ERASE };HDC 内存;HPAINTBUFFER hbuffer = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, ¶ms, &memdc);my_paint(memdc, rc);BufferedPaintSetAlpha(hbuffer, &rc, 255);EndBufferedPaint(hbuffer, TRUE);EndPaint(hwnd, &ps);返回0;}案例 WM_NCACTIVATE:返回0;案例 WM_NCCALCSIZE:如果(l参数)返回0;案例 WM_NCHITTEST:{POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };ScreenToClient(hwnd, &pt);矩形 rc;GetClientRect(hwnd, &rc);枚举 {left=1, top=2, right=4, bottom=8};整数命中= 0;if (pt.x rc.right - border_thickness.right) 命中 |= 正确;if (pt.y rc.bottom - border_thickness.bottom) 命中 |= 底部;if (hit & top && hit & left) 返回 HTTOPLEFT;if (hit & top && hit & right) 返回 HTOPRIGHT;if (hit & bottom && hit & left) 返回 HTBOTTOMLEFT;if (hit & bottom && hit & right) 返回 HTBOTTOMRIGHT;if (hit & left) 返回 HTLEFT;if (hit & top) 返回 HTTOP;if (hit & right) 返回 HTRIGHT;if (hit & bottom) 返回 HTBOTTOM;返回HTCLIENT;}案例 WM_DESTROY:PostQuitMessage(0);返回0;}返回 DefWindowProc(hwnd, uMsg, wParam, lParam);}
I want a window without title bar but with resizable frames and shadow. This can easily be achieved by removing WS_CAPTION and adding WS_THICKFRAME, however, since Windows 10, there's a 6px white non-client area.
With the following code I create a window and paint all the client area with black, the window gets a left, right and bottom 6px transparent margins, however 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:
How can I remove the white stripe ? I also found this related Qt bug report QTBUG-47543 which was closed as not being a Qt problem, because it can be reproduced with win32 api.
That's not a bug. In Windows 10 the borders on left/right/bottom are transparent. The top border is not transparent. You should leave it as is. Probably nobody will complain.
To change it, you must modify the non-client area. This is rather difficult in Windows Vista and above. See Custom Window Frame Using DWM for reference.
Find border thickness
Use
DwmExtendFrameIntoClientArea
to get access to non-client areaUse
BeginBufferedPaint
to draw opaque color over non-client area
Windows 10 example:
(See the next example for compatibility 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, ¶ms, &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 instead. This will paint over left/top/bottom borders as well as top border. This window will appear as a simple rectangle, with resizing borders:
//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, ¶ms, &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);
}
这篇关于创建没有标题栏的窗口,具有可调整大小的边框并且没有虚假的 6px 白色条纹的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!