PyQt6实现Windows带标题栏透明内容窗口(可拖拽调整)
问题描述
需在Windows平台使用PyQt6开发一款屏幕覆盖窗口,具体需求:
- 基于PyQt6开发
- 具备常规窗口外观,标题栏与边框完全不透明
- 支持常规拖拽移动和调整大小操作
- 窗口内容区域完全透明(禁止使用
setWindowOpacity(.8)这类整体透明方式) - 仅适配Windows平台
尝试多种方案未达预期:
- 启用
FramelessWindowHint后可实现内容透明,但丢失系统自带的拖拽和调整大小功能 - 添加自定义调整手柄后,窗口调整时出现抖动
- 未启用无框属性时,窗口背景始终为黑色
解决方案
核心思路:保留Windows系统自带的标题栏和边框(避免自定义交互的抖动问题),通过PyQt6的WA_TranslucentBackground属性配合样式表/窗口掩码实现内容区域完全透明。
方案一:样式表实现内容透明(简单易用)
import sys from PyQt6.QtWidgets import QMainWindow, QApplication, QWidget, QVBoxLayout from PyQt6.QtCore import Qt, QRect from PyQt6.QtGui import QPainter, QColor class ScreenOverlayWindow(QMainWindow): def __init__(self): super().__init__() self.init_ui() def init_ui(self): # 基础窗口设置 self.setWindowTitle("屏幕元素捕获窗口") self.setGeometry(300, 300, 400, 300) # 启用半透明背景属性(Windows平台下生效) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) # 可选:设置窗口始终置顶 self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.Window) # 中心部件(内容区域) central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) # 设置内容区域完全透明 central_widget.setStyleSheet("background-color: rgba(0, 0, 0, 0);") def paintEvent(self, event): # 可选:绘制内容区域边框,方便可视化窗口范围 painter = QPainter(self) painter.setPen(QColor(0, 128, 255)) title_bar_height = self.style().pixelMetric(self.style().PixelMetric.PM_TitleBarHeight) border_rect = QRect(0, title_bar_height, self.width(), self.height() - title_bar_height) painter.drawRect(border_rect) if __name__ == '__main__': app = QApplication(sys.argv) window = ScreenOverlayWindow() window.show() sys.exit(app.exec())
关键说明
- 保留系统交互:未使用
FramelessWindowHint,完全依赖Windows系统自带的标题栏拖拽、边框调整大小功能,无抖动问题。 - 内容透明实现:通过
WA_TranslucentBackground属性配合中心部件的透明样式表,实现内容区域完全透明,标题栏和边框保持系统默认的不透明状态。 - 可视化边框:paintEvent中绘制的边框仅用于直观显示窗口范围,可根据需求删除。
方案二:窗口掩码实现精确透明控制
如果需要更精确地控制透明区域(比如仅保留标题栏和四周边框),可使用窗口掩码:
import sys from PyQt6.QtWidgets import QMainWindow, QApplication, QWidget from PyQt6.QtCore import Qt, QRegion, QRect from PyQt6.QtGui import QPainter, QColor class ScreenOverlayWindow(QMainWindow): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("屏幕元素捕获窗口") self.setGeometry(300, 300, 400, 300) self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.Window) self.update_window_mask() def update_window_mask(self): # 获取系统标题栏高度和边框宽度 title_bar_height = self.style().pixelMetric(self.style().PixelMetric.PM_TitleBarHeight) border_width = 2 # 适配Windows系统边框宽度,可根据实际调整 # 创建窗口掩码:仅保留标题栏和四周边框,中间内容区域透明 region = QRegion(0, 0, self.width(), title_bar_height) # 标题栏区域 # 左侧边框 region += QRegion(0, title_bar_height, border_width, self.height() - title_bar_height) # 右侧边框 region += QRegion(self.width() - border_width, title_bar_height, border_width, self.height() - title_bar_height) # 底部边框 region += QRegion(border_width, self.height() - border_width, self.width() - 2*border_width, border_width) self.setMask(region) def resizeEvent(self, event): # 窗口大小变化时更新掩码 self.update_window_mask() super().resizeEvent(event) if __name__ == '__main__': app = QApplication(sys.argv) window = ScreenOverlayWindow() window.show() sys.exit(app.exec())
关键说明
- 精确透明控制:通过
QRegion定义窗口可见区域,仅保留标题栏和边框,中间内容区域完全透明。 - 动态更新掩码:窗口大小变化时自动更新掩码,确保边框始终正常显示。
内容的提问来源于stack exchange,提问作者rrz
相关产品推荐
相关产品推荐

