AI+PySide6实现自定义窗口标题栏目(titleBar)

AI+PySide6实现自定义窗口标题栏目(titleBar)

本教程将详细介绍如何使用 PySide6 实现一个功能完整的自定义标题栏,适合没有 PySide 基础的初学者学习。

目录

  1. 效果与完整代码
  2. 窗口布局
  3. 窗口事件
  4. 窗口按钮事件
  5. 完整代码解析

效果与完整代码

title_bar

完整代码

python 复制代码
# title_bar.py
from PySide6.QtWidgets import (
                                QWidget,
                                QVBoxLayout,
                                QHBoxLayout,
                                QLabel,
                                QPushButton,
                                QStyle,
                                QApplication,
                            )
from PySide6.QtGui import QMouseEvent
from PySide6.QtCore import Qt


class TitleBar(QWidget):
    """
    自定义标题栏
    """

    def __init__(self, parent=None):
        """构造函数

        :param parent: 父类窗口
        """
        super().__init__(parent)
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        self.setup_ui()
        self.setup_event_bind()

    def setup_ui(self):
        """设置界面"""
        # 全局使用垂直布局
        layout = QVBoxLayout(self)

        # 标题栏使用水平布局
        title_layout = QHBoxLayout()

        # 窗口图标 窗口标题 窗口按钮
        self.icon_label = QLabel(
            pixmap=self.style().standardPixmap(
                QStyle.StandardPixmap.SP_DialogApplyButton
            )
        )
        self.title_label = QLabel("自定义标题栏")
        self.min_btn = QPushButton(
            icon=self.style().standardPixmap(QStyle.StandardPixmap.SP_TitleBarMinButton)
        )
        self.max_btn = QPushButton(
            icon=self.style().standardPixmap(QStyle.StandardPixmap.SP_TitleBarMaxButton)
        )
        self.close_btn = QPushButton(
            icon=self.style().standardPixmap(
                QStyle.StandardPixmap.SP_TitleBarCloseButton
            )
        )

        # 最大化窗口 可勾选 默认不勾选
        self.max_btn.setCheckable(True)
        self.max_btn.setChecked(False)

        # 固定控件大小
        self.min_btn.setFixedSize(16, 16)
        self.max_btn.setFixedSize(16, 16)
        self.close_btn.setFixedSize(16, 16)

        # 添加布局与控件
        layout.addLayout(title_layout)
        title_layout.addWidget(self.icon_label)
        title_layout.addWidget(self.title_label)
        title_layout.addWidget(self.min_btn)
        title_layout.addWidget(self.max_btn)
        title_layout.addWidget(self.close_btn)
        layout.addWidget(QLabel("Hello World"))

    def setup_event_bind(self):
        """设置事件绑定"""
        # 缩小窗口 放大窗口与恢复窗口 关闭窗口
        self.min_btn.clicked.connect(self.showMinimized)
        self.max_btn.clicked.connect(self.toggle_max_restore)
        self.close_btn.clicked.connect(self.close)

    def toggle_max_restore(self, checked: bool):
        """切换窗口最大与恢复"""
        if checked:
            self.max_btn.setIcon(
                self.style().standardPixmap(
                    QStyle.StandardPixmap.SP_TitleBarNormalButton
                )
            )
            self.showMaximized()
        else:
            self.max_btn.setIcon(
                self.style().standardPixmap(QStyle.StandardPixmap.SP_TitleBarMaxButton)
            )
            self.showNormal()

    def mousePressEvent(self, event: QMouseEvent):
        if event.button() == Qt.LeftButton:
            window = self.window().windowHandle()
            if window:
                window.startSystemMove()
            event.accept()


def main():
    """主函数"""
    app = QApplication([])
    title_bar = TitleBar()
    title_bar.setStyleSheet("background-color:grey;")
    title_bar.show()
    app.exec()


if __name__ == "__main__":
    main()

窗口布局

1.0 布局示意图

title_bar

  • 绿色水平布局(窗口图标,标题栏,窗口图标)
  • 整体垂直布局

1.1 基础概念

在 PySide6 中,布局管理器用于自动排列和调整控件的位置和大小。我们的自定义标题栏使用了两种布局:

  • QVBoxLayout: 垂直布局,控件从上到下排列
  • QHBoxLayout: 水平布局,控件从左到右排列

1.2 界面与布局结构

ruby 复制代码
class TitleBar(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)  # 移除默认边框
        self.setup_ui()
        self.setup_event_bind()

关键点解释:

  • QWidget: 所有用户界面对象的基础类
  • setWindowFlags(Qt.WindowType.FramelessWindowHint): 移除系统默认的窗口边框,这样我们才能使用自定义标题栏

1.3 布局层次结构

scss 复制代码
TitleBar (QVBoxLayout - 主布局)
├── title_layout (QHBoxLayout - 标题栏布局)
│   ├── icon_label (QLabel - 窗口图标)
│   ├── title_label (QLabel - 窗口标题)
│   ├── min_btn (QPushButton - 最小化按钮)
│   ├── max_btn (QPushButton - 最大化按钮)
│   └── close_btn (QPushButton - 关闭按钮)
└── QLabel ("Hello World" - 示例内容区域)

1.4 创建布局和控件

ini 复制代码
def setup_ui(self):
    """设置界面"""
    # 全局使用垂直布局
    layout = QVBoxLayout(self)

    # 标题栏使用水平布局
    title_layout = QHBoxLayout()

    # 创建窗口图标
    self.icon_label = QLabel(
        pixmap=self.style().standardPixmap(
            QStyle.StandardPixmap.SP_DialogApplyButton
        )
    )
    
    # 创建窗口标题
    self.title_label = QLabel("自定义标题栏")
    
    # 创建窗口按钮
    self.min_btn = QPushButton(
        icon=self.style().standardPixmap(QStyle.StandardPixmap.SP_TitleBarMinButton)
    )
    self.max_btn = QPushButton(
        icon=self.style().standardPixmap(QStyle.StandardPixmap.SP_TitleBarMaxButton)
    )
    self.close_btn = QPushButton(
        icon=self.style().standardPixmap(
            QStyle.StandardPixmap.SP_TitleBarCloseButton
        )
    )

关键点解释:

  1. QLabel: 用于显示文本或图片的控件

  2. QPushButton: 按钮控件

  3. self.style().standardPixmap() : 获取系统标准图标,确保在不同操作系统上都有原生外观

  4. 标准图标类型

    • SP_DialogApplyButton: 对话框应用按钮图标
    • SP_TitleBarMinButton: 标题栏最小化按钮图标
    • SP_TitleBarMaxButton: 标题栏最大化按钮图标
    • SP_TitleBarCloseButton: 标题栏关闭按钮图标

1.5 控件属性设置

python 复制代码
# 最大化窗口 可勾选 默认不勾选
self.max_btn.setCheckable(True)
self.max_btn.setChecked(False)

# 固定控件大小
self.min_btn.setFixedSize(16, 16)
self.max_btn.setFixedSize(16, 16)
self.close_btn.setFixedSize(16, 16)

关键点解释:

  • setCheckable(True): 使按钮可以被选中/取消选中
  • setFixedSize(width, height): 设置控件的固定大小

1.6 布局管理

php 复制代码
# 添加布局与控件
layout.addLayout(title_layout)  # 将标题栏布局添加到主布局
title_layout.addWidget(self.icon_label)  # 添加图标
title_layout.addWidget(self.title_label)  # 添加标题
title_layout.addWidget(self.min_btn)  # 添加最小化按钮
title_layout.addWidget(self.max_btn)  # 添加最大化按钮
title_layout.addWidget(self.close_btn)  # 添加关闭按钮
layout.addWidget(QLabel("Hello World"))  # 添加内容区域

窗口事件

2.1 窗口拖动功能

为了实现窗口拖动,我们需要重写 mousePressEvent 方法:

scss 复制代码
def mousePressEvent(self, event: QMouseEvent):
    if event.button() == Qt.LeftButton:
        window = self.window().windowHandle()
        if window:
            window.startSystemMove()
        event.accept()

关键点解释:

  1. QMouseEvent: 鼠标事件类,包含鼠标操作的所有信息
  2. event.button() == Qt.LeftButton: 检查是否为鼠标左键点击
  3. self.window().windowHandle(): 获取窗口句柄
  4. window.startSystemMove(): 启动系统级别的窗口移动操作

2.2 跨平台支持

这个实现方式的优势在于:

  • Linux (Wayland/X11) : startSystemMove() 方法在 Linux 的两种显示服务器上都能正常工作
  • Windows: 在 Windows 系统上同样支持原生窗口移动
  • macOS: 也支持 macOS 的窗口移动

这比传统的实现方式(如记录鼠标位置并手动移动窗口)更加可靠和跨平台。

2.3 事件处理机制

csharp 复制代码
event.accept()  # 接受事件,阻止事件继续传播

event.accept() 告诉系统我们已经处理了这个事件,不需要进一步处理。

窗口按钮事件

3.1 事件绑定

setup_event_bind 方法中,我们将按钮的点击事件连接到相应的处理函数:

python 复制代码
def setup_event_bind(self):
    """设置事件绑定"""
    # 缩小窗口 放大窗口与恢复窗口 关闭窗口
    self.min_btn.clicked.connect(self.showMinimized)
    self.max_btn.clicked.connect(self.toggle_max_restore)
    self.close_btn.clicked.connect(self.close)

关键点解释:

  • clicked.connect(): 将按钮的点击信号连接到相应的槽函数
  • 信号槽机制是 PySide6 的核心特性,用于实现对象间的通信

3.2 最小化窗口

lua 复制代码
self.min_btn.clicked.connect(self.showMinimized)

showMinimized() 是 QWidget 的内置方法,直接将窗口最小化到任务栏。

3.3 最大化与恢复窗口

python 复制代码
def toggle_max_restore(self, checked: bool):
    """切换窗口最大与恢复"""
    if checked:
        self.max_btn.setIcon(
            self.style().standardPixmap(
                QStyle.StandardPixmap.SP_TitleBarNormalButton
            )
        )
        self.showMaximized()
    else:
        self.max_btn.setIcon(
            self.style().standardPixmap(QStyle.StandardPixmap.SP_TitleBarMaxButton)
        )
        self.showNormal()

关键点解释:

  1. checked 参数 : 由于我们设置了 setCheckable(True),这个参数表示按钮的选中状态

  2. 图标切换

    • 最大化时显示恢复图标 (SP_TitleBarNormalButton)
    • 恢复时显示最大化图标 (SP_TitleBarMaxButton)
  3. 窗口状态方法

    • showMaximized(): 将窗口最大化
    • showNormal(): 将窗口恢复到正常大小

3.4 关闭窗口

lua 复制代码
self.close_btn.clicked.connect(self.close)

close() 是 QWidget 的内置方法,关闭窗口并退出应用程序。

完整代码解析

4.1 导入模块

python 复制代码
from PySide6.QtWidgets import (
    QWidget,        # 基础窗口控件
    QVBoxLayout,    # 垂直布局
    QHBoxLayout,    # 水平布局
    QLabel,         # 标签控件
    QPushButton,    # 按钮控件
    QStyle,         # 样式相关类
    QApplication,   # 应用程序类
)
from PySide6.QtGui import QMouseEvent  # 鼠标事件
from PySide6.QtCore import Qt         # 核心枚举和类

4.2 主函数

python 复制代码
def main():
    """主函数"""
    app = QApplication([])          # 创建应用程序实例
    title_bar = TitleBar()          # 创建自定义标题栏实例
    title_bar.setStyleSheet("background-color:grey;")  # 设置背景色
    title_bar.show()                # 显示窗口
    app.exec()                      # 进入事件循环

关键点解释:

  1. QApplication([]): 创建应用程序对象,管理 GUI 应用程序
  2. setStyleSheet(): 设置控件样式,这里设置背景色为灰色
  3. show(): 显示窗口
  4. app.exec(): 进入应用程序的主事件循环

4.3 运行程序

ini 复制代码
if __name__ == "__main__":
    main()

这是 Python 的标准写法,确保只有直接运行此文件时才会执行 main() 函数。

总结

通过本教程,我们学习了如何:

  1. 创建自定义布局: 使用 QVBoxLayout 和 QHBoxLayout 组织界面元素
  2. 添加窗口控件: 创建图标、标题和按钮等界面元素
  3. 实现窗口拖动 : 使用 startSystemMove() 实现跨平台窗口拖动
  4. 处理窗口操作: 实现最小化、最大化/恢复、关闭等功能

本文使用 人言兑.md-公众号排版编辑器 排版

相关推荐
开心_开心急了2 小时前
Ai加Flutter实现自定义标题栏(appBar)
前端·flutter
布列瑟农的星空2 小时前
SSE与流式传输(Streamable HTTP)
前端·后端
GISer_Jing2 小时前
跨境营销前端AI应用业务领域
前端·人工智能·aigc
oak隔壁找我2 小时前
Node.js的package.json
前端·javascript
talenteddriver2 小时前
web: http请求(自用总结)
前端·网络协议·http
全栈派森2 小时前
Flutter 实战:基于 GetX + Obx 的企业级架构设计指南
前端·flutter
Awu12273 小时前
Vue3自定义渲染器:原理剖析与实践指南
前端·vue.js·three.js
支撑前端荣耀3 小时前
从零实现前端监控告警系统:SMTP + Node.js + 个人邮箱 完整免费方案
前端·javascript·面试
进击的野人3 小时前
Vue.js 插槽机制深度解析:从基础使用到高级应用
前端·vue.js·前端框架