PyQt-Frameless-Window 自定义标题栏完全指南:从 TitleBar 到 StandardTitleBar

PyQt-Frameless-Window 自定义标题栏完全指南:从 TitleBar 到 StandardTitleBar

PyQt-Frameless-Window 自定义标题栏完全指南:从 TitleBar 到 StandardTitleBar

【免费下载链接】PyQt-Frameless-WindowA cross-platform frameless window based on PyQt/PySide, support Win32, Linux and macOS.项目地址: https://gitcode.com/gh_mirrors/py/PyQt-Frameless-Window

想要用 PyQt5 做出像 Spotify、VS Code 那样干净漂亮的"无边框窗口",却总被系统默认标题栏拖后腿?PyQt-Frameless-Window就是为这个痛点而生的跨平台开源库,它基于 PyQt/PySide,完整支持 Win32、Linux 和 macOS,自带了移动窗口、边缘拉伸、窗口阴影、窗口动画以及 Win11 Snap Layout、Win10/11 亚克力与 Mica 模糊等高级能力。而这一切体验的核心,正是它的自定义标题栏体系。本文将带你从默认的TitleBar一路走到StandardTitleBar,学会如何打造属于自己的个性化标题栏。

什么是 PyQt-Frameless-Window?快速认识这个跨平台无边框窗口库

PyQt-Frameless-Window 是一个专门解决"无边框窗口"痛点的 Python 库。普通窗口去掉系统边框后,会立刻失去拖拽移动、缩放、阴影等基础能力,体验很差。这个库通过 Win32 API、X11 和 macOS 原生接口的封装,帮你把这些能力全部找回来:

  • 🖱️窗口移动:按住标题栏任意拖动
  • 📐边缘拉伸:5 像素宽的热区缩放(Windows 平台)
  • 🌫️窗口阴影与动画:原生级视觉反馈
  • 🪟Win11 Snap Layout:悬停最大化按钮即可分屏
  • 🎨亚克力 / Mica / Aero 模糊:按系统版本自动适配

安装非常简单,一条 pip 命令即可搞定:

pip install PyQt5-Frameless-Window

3 分钟上手:第一个无边框窗口的极简写法

使用这个库,你只需要继承FramelessWindowFramelessMainWindow,项目核心入口定义在 qframelesswindow/init.py 中,会根据当前操作系统自动选择对应的窗口实现:

import sys from PyQt5.QtWidgets import QApplication from qframelesswindow import FramelessWindow class Window(FramelessWindow): def __init__(self, parent=None): super().__init__(parent=parent) self.setWindowTitle("PyQt-Frameless-Window") self.titleBar.raise_() # 别忘了把标题栏置顶 if __name__ == '__main__': app = QApplication(sys.argv) demo = Window() demo.show() sys.exit(app.exec_())

注意self.titleBar.raise_()这一行,它确保自定义标题栏始终显示在所有内容之上,是新手最容易漏掉的关键一步。

认识默认标题栏 TitleBar:三按钮与拖拽逻辑

FramelessWindow默认使用TitleBar作为标题栏,它的完整实现位于 qframelesswindow/titlebar/init.py。这个类继承自TitleBarBase,自带三件套:

  • minBtn:最小化按钮
  • maxBtn:最大化 / 还原按钮(图标会随状态自动切换)
  • closeBtn:关闭按钮(悬停时变为红色)

标题栏高度固定为32px,三个按钮统一为46×32尺寸。除了按钮之外,TitleBarBase还内置了完整的交互逻辑,比如:

  • 双击标题栏空白处切换最大化状态(可用setDoubleClickEnabled(False)关闭)
  • 鼠标按住空白区域拖动窗口(自动避开按钮区域,通过canDrag()判断)
  • 监听窗口状态变化,实时更新最大化按钮的图标

升级到 StandardTitleBar:图标 + 标题一步到位

如果你希望标题栏左侧显示窗口图标窗口标题,直接把默认标题栏替换成StandardTitleBar即可。它是TitleBar的子类,在原有三按钮基础上增加了iconLabeltitleLabel两个标签:

from PyQt5.QtGui import QIcon from qframelesswindow import FramelessWindow, StandardTitleBar class Window(FramelessWindow): def __init__(self, parent=None): super().__init__(parent=parent) # 替换默认标题栏 self.setTitleBar(StandardTitleBar(self)) self.setWindowIcon(QIcon("logo.png")) self.setWindowTitle("我的应用") self.titleBar.raise_()

更贴心的是,StandardTitleBar会自动监听windowIconChangedwindowTitleChanged信号——窗口图标或标题一旦变化,标题栏立刻同步更新,无需手动干预。当然,你也可以通过setTitle()setIcon()手动控制。

如何自定义标题栏样式:从按钮换色到 QSS 美化

标题栏按钮都继承自TitleBarButton(定义在 qframelesswindow/titlebar/title_bar_buttons.py),每个按钮都有普通 / 悬停 / 按下三种状态,每种状态都可独立配置图标颜色和背景色。

方式一:Python 方法直接设置

self.minBtn.setHoverColor(Qt.white) self.minBtn.setHoverBackgroundColor(QColor(0, 100, 182)) self.minBtn.setPressedColor(Qt.white) self.minBtn.setPressedBackgroundColor(QColor(54, 57, 65))

方式二:QSS 属性选择器(更优雅)

self.maxBtn.setStyleSheet(""" TitleBarButton { qproperty-normalColor: black; qproperty-normalBackgroundColor: transparent; qproperty-hoverColor: white; qproperty-hoverBackgroundColor: rgb(0, 100, 182); qproperty-pressedColor: white; qproperty-pressedBackgroundColor: rgb(54, 57, 65); } """)

由于按钮颜色都是通过pyqtProperty暴露的,QSS 可以直接用qproperty-xxx语法修改,非常适合做主题换肤。参考完整示例见 examples/demo.py。

完整实战:打造一款带图标的 CustomTitleBar

把上面所有知识串起来,我们就能写一个真正属于自己的自定义标题栏——在StandardTitleBar基础上换一套蓝白配色:

from PyQt5.QtCore import Qt from PyQt5.QtGui import QColor from qframelesswindow import FramelessWindow, StandardTitleBar class CustomTitleBar(StandardTitleBar): def __init__(self, parent): super().__init__(parent) # 给最小化按钮换上蓝色悬停效果 self.minBtn.setHoverColor(Qt.white) self.minBtn.setHoverBackgroundColor(QColor(0, 100, 182)) self.minBtn.setPressedColor(Qt.white) self.minBtn.setPressedBackgroundColor(QColor(54, 57, 65)) # 最大化与关闭按钮同理,可继续扩展... class Window(FramelessWindow): def __init__(self, parent=None): super().__init__(parent=parent) self.setTitleBar(CustomTitleBar(self)) # 换上新标题栏 self.setWindowIcon(QIcon("logo.png")) self.setWindowTitle("PyQt-Frameless-Window") self.titleBar.raise_()

除了换色,你还可以往标题栏里塞菜单栏、搜索框、工具栏等任意控件。比如 examples/main_window.py 就演示了如何把QMenuBar放进标题栏,做出类似 Chrome 那种一体化顶部栏的效果。另外,项目还提供了FramelessMainWindowFramelessDialog,分别对应主窗口和对话框场景。

与 Qt Designer 集成:记住 32px 标题栏空间

如果你习惯用 Qt Designer 画界面,集成也很顺畅。核心技巧只有一个:在设计稿顶部为标题栏预留 32px 高度,否则内容会被标题栏遮挡:

编译好 ui 文件后,用多继承的方式组合FramelessWindowUi_Form即可无缝衔接,具体细节可以参考 docs/source/usage.md 文档。

进阶玩法:macOS 系统按钮与 Acrylic 毛玻璃效果

适配 macOS 原生红绿灯按钮

在 macOS 上,你可以隐藏自定义标题栏按钮,改用系统原生按钮。此时只需重写systemTitleBarRect()方法,把系统按钮区域挪到右上角,参考 examples/demo.py:

def systemTitleBarRect(self, size: QSize) -> QRect: return QRect(size.width() - 75, 0, 75, size.height())

一键开启亚克力 / Mica 模糊

想要半透明毛玻璃质感?换用AcrylicWindow即可,examples/acrylic_demo.py 里有最小示例:

from qframelesswindow import AcrylicWindow class Window(AcrylicWindow): def __init__(self, parent=None): super().__init__(parent=parent) self.setWindowTitle("Acrylic Window") self.titleBar.raise_() # Win11 上还可以启用 Mica 效果 # self.windowEffect.setMicaEffect(self.winId(), isDarkMode=False, isAlt=False)

Win10 使用亚克力、Win11 使用 Mica、Win7 自动回退 Aero,库会自动按系统版本选择最佳效果,更多细节见 docs/source/window-effect.md。

常见问题与避坑指南

  1. 标题栏被内容遮挡:检查是否漏了self.titleBar.raise_()
  2. Win10 下拖动亚克力窗口卡顿:这是系统限制,可在拖动时临时关闭亚克力效果(文档提供了setAcrylicEffectEnabled()思路)。
  3. 菜单栏显示异常:使用FramelessMainWindow时记得self.setMenuWidget(self.titleBar),并参考 examples/main_window.py 的完整写法。
  4. 导入报错:Windows 平台依赖 pywin32,Linux 依赖 xcffib,macOS 依赖 pyobjc,请先安装对应平台的依赖。

从默认的TitleBar到带图标标题的StandardTitleBar,再到完全自定义的CustomTitleBar,PyQt-Frameless-Window 用清晰的继承体系把"自定义标题栏"这件事变得极其简单。现在就去动手改造你的第一个无边框窗口吧!🚀

【免费下载链接】PyQt-Frameless-WindowA cross-platform frameless window based on PyQt/PySide, support Win32, Linux and macOS.项目地址: https://gitcode.com/gh_mirrors/py/PyQt-Frameless-Window

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考