Qt6.6.x Windows平台Frameless窗口结合SetWindowLong绘画异常求助
在Qt6.6+中保留WinAPI窗口样式调用并修复无边框窗口绘画异常的方案
问题根源
Qt6.6版本后对窗口样式的同步逻辑做了底层调整:当通过SetWindowLong直接修改系统窗口样式时,Qt内部维护的窗口状态与系统窗口状态出现不一致,导致客户区计算、绘画布局逻辑冲突,最终引发异常。
解决方案
通过调整样式设置时机、强制同步Qt与系统窗口状态、兼容Qt新的消息处理逻辑,可在保留SetWindowLong调用的前提下修复问题。以下是PyQt6.6+的实现代码:
from PyQt6.QtWidgets import QMainWindow from PyQt6.QtCore import Qt, QEvent import win32api import win32con class FramelessWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) # 启用Qt无边框标志 self.setWindowFlags(self.windowFlags() | Qt.WindowType.FramelessWindowHint) # 强制使用原生窗口句柄,确保样式同步 self.setAttribute(Qt.WidgetAttribute.WA_NativeWindow, True) def showEvent(self, event): super().showEvent(event) # 窗口初始化完成后再修改WinAPI样式,避免与Qt初始化逻辑冲突 hWnd = int(self.winId()) current_style = win32api.GetWindowLong(hWnd, win32con.GWL_STYLE) # 组合需要的系统窗口样式 new_style = current_style | win32con.WS_MINIMIZEBOX | win32con.WS_MAXIMIZEBOX | win32con.WS_CAPTION | win32con.CS_DBLCLKS | win32con.WS_THICKFRAME | win32con.WS_OVERLAPPED win32api.SetWindowLong(hWnd, win32con.GWL_STYLE, new_style) # 强制系统刷新窗口框架,同步样式变更 win32api.SetWindowPos( hWnd, 0, 0, 0, 0, 0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | win32con.SWP_FRAMECHANGED ) # 通知Qt更新窗口几何与绘画状态 self.updateGeometry() self.repaint() def nativeEvent(self, eventType, message): msg = message[0] if msg.message == win32con.WM_NCCALCSIZE: # 先让Qt处理该消息,兼容其6.6+版本的客户区计算逻辑 result, data = super().nativeEvent(eventType, message) if msg.wParam: # 获取系统传递的客户区矩形 rect = msg.lParam[0] # 计算系统边框厚度 def getResizeBorderThickness(hwnd, is_horizontal=True): frame_size = win32api.GetSystemMetrics(win32con.SM_CXSIZEFRAME if is_horizontal else win32con.SM_CYSIZEFRAME) pad_size = win32api.GetSystemMetrics(win32con.SM_CXPADDEDBORDER if is_horizontal else win32con.SM_CYPADDEDBORDER) return frame_size + pad_size tx = getResizeBorderThickness(hWnd) ty = getResizeBorderThickness(hWnd, False) # 调整客户区范围,移除边框占用区域 rect.top += ty rect.bottom -= ty rect.left += tx rect.right -= tx msg.lParam[0] = rect return (True, data) return super().nativeEvent(eventType, message)
关键调整说明
- 延迟样式修改时机:将
SetWindowLong调用移至showEvent中,确保Qt完成窗口初始化后再修改系统样式,避免初始化阶段的逻辑冲突。 - 强制样式同步:调用
SetWindowPos并传入SWP_FRAMECHANGED参数,强制Windows重新计算窗口框架,同步样式变更。 - 兼容Qt消息处理:在
WM_NCCALCSIZE消息处理中,先让Qt执行内部逻辑,再调整客户区矩形,避免覆盖Qt6.6+新增的布局计算逻辑。 - 触发Qt状态更新:通过
updateGeometry和repaint通知Qt同步窗口几何与绘画状态,确保界面渲染正常。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

