modify frameless

This commit is contained in:
brige 2025-11-16 16:50:17 +08:00
parent 9a24595873
commit dfa0d513e6
2 changed files with 24 additions and 40 deletions

View File

@ -24,10 +24,9 @@ namespace Gdiplus
#include "FrameTitleBar.h" #include "FrameTitleBar.h"
#pragma comment (lib,"Dwmapi.lib") // Adds missing library, fixes error LNK2019: unresolved external symbol __imp__DwmExtendFrameIntoClientArea #pragma comment (lib,"Dwmapi.lib")
#pragma comment (lib,"user32.lib") #pragma comment (lib,"user32.lib")
// 无边框样式:不使用 CAPTION 与系统按钮,避免在 Win7 显示原生按钮
constexpr unsigned long BorderlessFlag = WS_POPUP | WS_THICKFRAME | WS_SYSMENU; constexpr unsigned long BorderlessFlag = WS_POPUP | WS_THICKFRAME | WS_SYSMENU;
inline bool IsCompositionEnabled() { inline bool IsCompositionEnabled() {
@ -103,10 +102,9 @@ bool FramelessDelegateWin::nativeEvent(const QByteArray & eventType, void* messa
return true; return true;
} }
NCCALCSIZE_PARAMS* ncParam = reinterpret_cast<NCCALCSIZE_PARAMS*>(msg->lParam); NCCALCSIZE_PARAMS* ncParam = reinterpret_cast<NCCALCSIZE_PARAMS*>(msg->lParam);
// 最大化时将客户区严格对齐到工作区,避免左右空隙
ncParam->rgrc[0].left = rc->left(); ncParam->rgrc[0].left = rc->left();
ncParam->rgrc[0].top = rc->top(); ncParam->rgrc[0].top = rc->top();
ncParam->rgrc[0].right = rc->right(); ncParam->rgrc[0].right = rc->right() + 1;
ncParam->rgrc[0].bottom = rc->bottom(); ncParam->rgrc[0].bottom = rc->bottom();
*result = 0; *result = 0;
return true; return true;
@ -123,7 +121,7 @@ bool FramelessDelegateWin::nativeEvent(const QByteArray & eventType, void* messa
} else { } else {
clientRect->top = before.top; clientRect->top = before.top;
clientRect->left = before.left; clientRect->left = before.left;
clientRect->right = before.right; clientRect->right = before.right + 1;
clientRect->bottom = before.bottom + 1; clientRect->bottom = before.bottom + 1;
} }
} }
@ -132,12 +130,8 @@ bool FramelessDelegateWin::nativeEvent(const QByteArray & eventType, void* messa
return true; return true;
} }
case WM_NCPAINT: { case WM_NCPAINT: {
if (!IsCompositionEnabled()) { *result = 0;
*result = 0; return true;
return true;
} else {
break;
}
} }
case WM_SETFOCUS: { case WM_SETFOCUS: {
Qt::FocusReason reason; Qt::FocusReason reason;
@ -153,17 +147,13 @@ bool FramelessDelegateWin::nativeEvent(const QByteArray & eventType, void* messa
} }
break; break;
case WM_NCACTIVATE: { case WM_NCACTIVATE: {
if (!IsCompositionEnabled()) { *result = 1;
*result = 1; return true;
return true;
}
} }
break;
case WM_NCHITTEST: { case WM_NCHITTEST: {
return OnNCTitTest(msg, result); return OnNCTitTest(msg, result);
} }
case WM_GETMINMAXINFO: { case WM_GETMINMAXINFO: {
// 使用工作区定义最大化位置与大小,避免遮挡任务栏
MINMAXINFO* mmi = reinterpret_cast<MINMAXINFO*>(msg->lParam); MINMAXINFO* mmi = reinterpret_cast<MINMAXINFO*>(msg->lParam);
HMONITOR monitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST); HMONITOR monitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi; MONITORINFO mi;
@ -172,17 +162,19 @@ bool FramelessDelegateWin::nativeEvent(const QByteArray & eventType, void* messa
if (monitor && GetMonitorInfo(monitor, &mi)) { if (monitor && GetMonitorInfo(monitor, &mi)) {
const RECT& work = mi.rcWork; const RECT& work = mi.rcWork;
const RECT& rcMon = mi.rcMonitor; const RECT& rcMon = mi.rcMonitor;
mmi->ptMaxPosition.x = work.left; const int frameX = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
mmi->ptMaxPosition.y = work.top; const int frameY = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
mmi->ptMaxSize.x = work.right - work.left;
mmi->ptMaxSize.y = work.bottom - work.top; mmi->ptMaxPosition.x = work.left - frameX;
// 限制拖动最大尺寸为监视器大小(非必须,但较合理) mmi->ptMaxPosition.y = work.top - frameY;
mmi->ptMaxTrackSize.x = rcMon.right - rcMon.left; mmi->ptMaxSize.x = (work.right - work.left) + frameX * 2;
mmi->ptMaxTrackSize.y = rcMon.bottom - rcMon.top; mmi->ptMaxSize.y = (work.bottom - work.top) + frameY * 2;
mmi->ptMaxTrackSize.x = (rcMon.right - rcMon.left) + frameX * 2;
mmi->ptMaxTrackSize.y = (rcMon.bottom - rcMon.top) + frameY * 2;
} }
if (::IsZoomed(msg->hwnd)) { if (::IsZoomed(msg->hwnd)) {
// 最大化时不叠加系统边框内边距
frames_.setLeft(0); frames_.setLeft(0);
frames_.setTop(0); frames_.setTop(0);
frames_.setRight(0); frames_.setRight(0);
@ -230,7 +222,6 @@ void FramelessDelegateWin::OnShow() {
} }
mainWidget_->setAttribute(Qt::WA_Resized); mainWidget_->setAttribute(Qt::WA_Resized);
// 仅当存在有效的窗口放置信息length 已设置)时才恢复窗口位置,避免首次显示使用未初始化的数据
if (!isFirstShow_ && mainWidget_->isMaximized() && wndPlaceMent_.length == sizeof(wndPlaceMent_)) { if (!isFirstShow_ && mainWidget_->isMaximized() && wndPlaceMent_.length == sizeof(wndPlaceMent_)) {
QMetaObject::invokeMethod( QMetaObject::invokeMethod(
this, this,
@ -374,15 +365,12 @@ void FramelessDelegateWin::SetNativeWindowLong() {
} }
HWND hwnd = reinterpret_cast<HWND>(mainWidget_->winId()); HWND hwnd = reinterpret_cast<HWND>(mainWidget_->winId());
unsigned long style = BorderlessFlag; unsigned long style = BorderlessFlag;
// 避免父窗口与子窗口重叠绘制导致闪烁,启用剪裁样式
style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS; style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
// 显式清理可能由 Qt 或系统设置的标题栏与系统按钮标志,确保不显示原生按钮
style &= ~WS_CAPTION; style &= ~WS_CAPTION;
style &= ~WS_MINIMIZEBOX; style &= ~WS_MINIMIZEBOX;
style &= ~WS_MAXIMIZEBOX; style &= ~WS_MAXIMIZEBOX;
// 根据 Qt 窗口标志与大小约束,启用系统最小化/最大化按钮能力
const bool canResize = (mainWidget_->maximumSize() == QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); const bool canResize = (mainWidget_->maximumSize() == QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
if (mainWidget_->windowFlags().testFlag(Qt::WindowMinimizeButtonHint) && canResize) { if (mainWidget_->windowFlags().testFlag(Qt::WindowMinimizeButtonHint) && canResize) {
style |= WS_MINIMIZEBOX; style |= WS_MINIMIZEBOX;
@ -394,7 +382,7 @@ void FramelessDelegateWin::SetNativeWindowLong() {
::SetWindowLongPtr(hwnd, GWL_STYLE, style); ::SetWindowLongPtr(hwnd, GWL_STYLE, style);
if (IsCompositionEnabled()) { if (IsCompositionEnabled()) {
ExtendFrameIntoClientArea(mainWidget_->windowHandle(), 1, 0, 0, 0); ExtendFrameIntoClientArea(mainWidget_->windowHandle(), 1, 1, 0, 0);
} }
RECT rect; RECT rect;
GetWindowRect(hwnd, &rect); GetWindowRect(hwnd, &rect);
@ -445,10 +433,6 @@ bool FramelessDelegateWin::OnNCTitTest(MSG* msg, qintptr* result) {
*result = HTTOP; *result = HTTOP;
return true; return true;
} }
if (y > rect.top() + borderY && y < rect.top() + borderY) {
*result = HTCAPTION;
return true;
}
if (!maxSized && y >= rect.bottom() - borderY && y <= rect.bottom()) { if (!maxSized && y >= rect.bottom() - borderY && y <= rect.bottom()) {
*result = HTBOTTOM; *result = HTBOTTOM;
return true; return true;

View File

@ -18,16 +18,16 @@
<number>0</number> <number>0</number>
</property> </property>
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>6</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>0</number> <number>6</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>6</number>
</property> </property>
<item> <item>
<widget class="FrameTitleBar" name="titleFrame"> <widget class="FrameTitleBar" name="titleFrame">
@ -55,7 +55,7 @@
<widget class="QWidget" name="body" native="true"> <widget class="QWidget" name="body" native="true">
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing"> <property name="spacing">
<number>2</number> <number>0</number>
</property> </property>
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
@ -64,10 +64,10 @@
<number>3</number> <number>3</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>0</number> <number>3</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>6</number>
</property> </property>
<item> <item>
<widget class="QStackedWidget" name="menuWidget"> <widget class="QStackedWidget" name="menuWidget">