百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Python入坑系列-pyside6桌面开发之QmainWindow自定义标题栏

bigegpt 2024-10-12 05:26 30 浏览

通过本文章,可以掌握以下内容:

  1. QMainWindow布局
  2. QMainWindow常用属性和方法介绍
  3. QMainWindow图标和背景设置
  4. QMainWindow无边框设计实现

1、QMainWindow布局

主窗口提供了用于构建应用程序的用户界面的框架,其主要布局如下

  • Menu Bar:菜单栏,通过添加QMenuBar
# 实例化QMenuBar
self.menuBarInstance = QMenuBar(self)
# 创建菜单
fileMenu = self.menuBarInstance.addMenu("文件")
# 创建动作
exitAction = QAction("退出", self)
exitAction.triggered.connect(self.close)
# 将动作添加到菜单
fileMenu.addAction(exitAction)
  • Toolbars:工具栏,通过往窗口添加QToolBar
# 实例化QToolBar
toolBar = QToolBar("我的工具栏", self)
self.addToolBar(toolBar)
# 创建动作
exitAction = QAction("退出", self)
exitAction.triggered.connect(self.close)
# 将动作添加到菜单
fileMenu.addAction(exitAction)
  • Dock Widgets:停靠部件,比如浮窗的拖动部件,通过往窗口添加QDockWidgets
# 创建一个QDockWidget
dock = QDockWidget("菜单", self)
self.addDockWidget(Qt.LeftDockWidgetArea, dock)
# 创建一个列表作为菜单项容器
menuList = QListWidget()
dock.setWidget(menuList)
  • Central Widget:占据主窗口中心区域的部件,通常是标准 Qt 小部,通过添加Widget部件
# 实例化一个QWidget作为中心部件
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
# 创建一个布局
layout = QVBoxLayout()
# 添加一些控件到布局中
layout.addWidget(QLabel("这是一个标签"))
# 将布局设置给中心部件
centralWidget.setLayout(layout)
  • Status Bar:状态栏显示,通过添加QStatusBar
# 实例化一个QStatusBar
statusBar = QStatusBar()
# 将状态栏设置为主窗口的状态栏
self.setStatusBar(statusBar)
# 在状态栏中添加一些信息
statusBar.addWidget(QLabel("这是状态栏信息"))

2、QMainWindow常用属性和方法

属性

  • windowTitle::窗口的标题。
  • menuBar:窗口的菜单栏。
  • statusBar:窗口的状态栏。
  • centralWidget:窗口的中心部件。
  • toolBars:窗口的工具栏列表。
  • dockWidgets:窗口的停靠窗口列表。
  • animated:操作停靠小部件和工具栏是否有动画
  • dockNestingEnabled:停靠部件是否可以嵌套
  • dockOptions:QMainWindow的停靠行为
  • documentMode:选项卡式停靠小部件的选项卡栏是否设置为文档模式
  • iconSize:此主窗口中工具栏图标的大小
  • tabShape:用于选项卡式停靠小部件的选项卡形状
  • toolButtonStyle:主窗口中工具栏按钮的样式
  • unifiedTitleAndToolBarOnMac:窗口是否在macOS上使用统一的标题和工具栏外观

方法

  • setWindowFlags(Qt.WindowFlags flags):用于指定窗口的各种属性和行为。例如,你可以设置窗口为无边框、始终在顶层显示、不显示在任务栏等

窗口装饰标志

Qt.MSWindowsFixedSizeDialogHint

Windows平台上,使对话框窗口的大小固定,不能被用户调整。

Qt.X11BypassWindowManagerHint

在X11平台(Linux/Unix)上,使窗口绕过窗口管理器,直接与系统交互。这通常用于需要完全控制窗口显示和行为的特殊窗口

Qt.FramelessWindowHint

创建一个无边框窗口。这通常用于自定义窗口的外观。

Qt.NoDropShadowWindowHint

禁用窗口的阴影效果。这在自定义窗口绘制时可能有用,特别是在需要精确控制窗口外观的情况下。

Qt.WindowTitleHint

窗口将包含一个标题栏。这是大多数窗口的默认行为。

Qt.WindowSystemMenuHint

窗口将包含一个系统菜单,通常位于标题栏的左上角。

Qt.WindowMinimizeButtonHint

窗口将包含一个最小化按钮。

Qt.WindowMaximizeButtonHint

窗口将包含一个最大化按钮。

Qt.WindowCloseButtonHint

窗口将包含一个关闭按钮。

Qt.WindowContextHelpButtonHint

窗口将包含一个上下文帮助按钮,在用户点击时通常会显示帮助信息。

Qt.WindowStaysOnTopHint

窗口将始终保持在其他窗口之上。

Qt.WindowStaysOnBottomHint

窗口将始终保持在其他窗口之下。

Qt.CustomizeWindowHint

允许窗口被自定义,通常与其他窗口标志一起使用,以提供特定的窗口外观和行为。

常用窗口标志

Qt.Widget

默认值,指示对象是一个控件

Qt.Window

使控件成为一个窗口,这会给它提供窗口装饰

Qt.Dialog

示窗口是一个对话框

Qt.Sheet

指示窗口是一个Mac风格的表单(仅在Mac OS X中有效)

Qt.Drawer

指示窗口是一个Mac风格的抽屉(仅在Mac OS X中有效)

Qt.Popup

指示窗口是一个弹出窗口

Qt.Tool

指示窗口是一个工具窗口。工具窗口是一个小窗口,通常用于提供模式或非模式对话框

Qt.ToolTip

指示窗口是一个工具提示

Qt.SplashScreen

指示窗口是一个启动画面

Qt.Desktop

指示窗口是桌面。这是一个特殊的窗口,不能创建

Qt.SubWindow

指示窗口是一个子窗口

  • addDockWidget(area, dockwidget, orientation): 在指定区域和方向添加一个停靠窗口。以下是停靠的枚举值

常用的停靠窗口标志

QMainWindow.AnimatedDocks

与属性相同animated。

QMainWindow.AllowNestedDocks

与属性相同dockNestingEnabled。

QMainWindow.AllowTabbedDocks

用户可以将一个停靠小部件放置在另一个停靠小部件的“顶部”。这两个小部件堆叠在一起,并出现一个选项卡栏,用于选择哪个小部件可见。

QMainWindow.ForceTabbedDocks

每个停靠区域都包含一堆选项卡式停靠小部件。换句话说,停靠小部件不能在停靠区域中彼此相邻放置。如果设置此选项,AllowNestedDocks 不起作用。

QMainWindow.VerticalTabs

主窗口两侧的两个垂直停靠区域垂直显示其选项卡。如果未设置此选项,所有停靠区域都会在底部显示其选项卡。暗示AllowTabbedDocks。也可以看看setTabPosition()。

QMainWindow.GroupedDragging

拖动扩展坞的标题栏时,所有与其关联的选项卡都将被拖动。暗示AllowTabbedDocks。如果某些 QDockWidget 在允许的区域有限制,则效果不佳。(这个枚举值是在 Qt 5.6 中添加的。)

  • addDockWidget(area, dockwidget): 在指定区域添加一个停靠窗口。
  • addToolBar(area, toolbar): 在指定区域添加一个工具栏。
  • addToolBar(title): 创建一个新的工具栏,使用提供的标题。
  • addToolBar(toolbar): 添加一个预先创建的工具栏。
  • addToolBarBreak([area=Qt.TopToolBarArea]): 在指定区域添加一个工具栏断点。
  • centralWidget(): 返回当前设置为中心部件的QWidget对象。
  • corner(corner): 返回指定角落的停靠区域。
  • dockOptions(): 返回当前的停靠选项。
  • dockWidgetArea(dockwidget): 返回指定停靠窗口所在的区域。
  • documentMode(): 返回文档模式的启用状态。
  • iconSize(): 返回工具栏图标的大小。
  • insertToolBar(before, toolbar): 在指定的工具栏之前插入一个工具栏。
  • insertToolBarBreak(before): 在指定的工具栏之前插入一个工具栏断点。
  • isAnimated(): 返回窗口是否启用动画。
  • isDockNestingEnabled(): 返回是否允许停靠窗口嵌套。
  • isSeparator(pos): 检查指定位置是否为分隔符。
  • menuBar(): 返回窗口的菜单栏。
  • menuWidget(): 返回设置为菜单栏的自定义QWidget对象。
  • removeDockWidget(dockwidget): 移除指定的停靠窗口。
  • removeToolBar(toolbar): 移除指定的工具栏。
  • removeToolBarBreak(before): 移除指定位置的工具栏断点。
  • resizeDocks(docks, sizes, orientation): 调整一组停靠窗口的大小。
  • restoreDockWidget(dockwidget): 恢复停靠窗口的状态。
  • restoreState(state[, version=0]): 恢复窗口的状态。
  • saveState([version=0]): 保存窗口的当前状态。
  • setCentralWidget(widget): 设置中心部件。
  • setCorner(corner, area): 设置窗口角落的停靠区域。
  • setDockOptions(options): 设置停靠选项。
  • setDocumentMode(enabled): 启用或禁用文档模式。
  • setIconSize(iconSize): 设置工具栏图标的大小。
  • setMenuBar(menubar): 设置窗口的菜单栏。
  • setMenuWidget(menubar): 设置自定义的菜单栏部件。
  • setStatusBar(statusbar): 设置窗口的状态栏。
  • setTabPosition(areas, tabPosition): 设置停靠窗口的标签位置。
  • setTabShape(tabShape): 设置停靠窗口的标签形状。
  • setToolButtonStyle(toolButtonStyle): 设置工具按钮的样式。
  • splitDockWidget(after, dockwidget, orientation): 将一个停靠窗口分割为两个。
  • statusBar(): 返回窗口的状态栏。
  • tabPosition(area): 返回指定区域的标签位置。
  • tabShape(): 返回停靠窗口的标签形状。
  • tabifiedDockWidgets(dockwidget): 返回与指定停靠窗口标签化的所有停靠窗口。
  • tabifyDockWidget(first, second): 将两个停靠窗口标签化。
  • takeCentralWidget(): 移除并返回中心部件。
  • toolBarArea(toolbar): 返回指定工具栏所在的区域
  • toolBarBreak(toolbar): 检查指定工具栏之前是否有工具栏断点。
  • toolButtonStyle(): 返回工具按钮的样式。
  • unifiedTitleAndToolBarOnMac(): 返回是否在Mac OS上使用统一的标题栏和工具栏样式。
  • createPopupMenu(): 创建一个包含所有可停靠窗口和工具栏的可见性控制项的弹出菜单。这个方法通常用于提供一个上下文菜单,允许用户选择哪些工具栏或停靠窗口是可见的。

3、QMainWindow图标和背景设置

设置logo图标

# 设置窗口图标
self.setWindowIcon(QIcon('path/to/your/icon.png'))

设置背景

  • 通过样式设置颜色
# 使用样式表设置背景颜色
self.setStyleSheet("background-color: lightblue;")
  • 通过样式设置图片
# 使用样式表设置背景图片
self.setStyleSheet("background-image: url('path/to/your/image.jpg');")
  • 通过QPainter绘制背景图片
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("通过paintEvent设置背景")
    def paintEvent(self, event):
        painter = QPainter(self)
        pixmap = QPixmap("path/to/your/image.jpg")
        P·ainter.drawPixmap(self.rect(), pixmap)
if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())

4、QMainWindow无边框设计实现

实现无边框设计,pyside6目前没有很好的解决方案。主要思路是设置无边框,通过自定义标题栏来实现窗口的基本属性,事件。下面是具体例子:

from PySide6.QtCore import QSize, Qt, QEvent
from PySide6.QtGui import QPalette, QRegion
from PySide6.QtWidgets import *

class CustomTitleBar(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.setAutoFillBackground(True)
        self.setBackgroundRole(QPalette.ColorRole.Highlight)
        self.initial_pos = None
        title_bar_layout = QHBoxLayout(self)
        title_bar_layout.setContentsMargins(1, 1, 1, 1)
        title_bar_layout.setSpacing(2)

        self.title = QLabel("自定义工具栏", self)
        self.title.setStyleSheet(
            """font-weight: bold;
               border: 2px solid black;
               border-radius: 12px;
               margin: 2px;
            """
        )
        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
        if title := parent.windowTitle():
            self.title.setText(title)
        # 只设置自定义标题拖动
        self.title.mousePressEvent = parent.title_mousePressEvent
        self.title.mouseMoveEvent = parent.title_mouseMoveEvent
        self.title.mouseReleaseEvent = parent.title_mouseReleaseEvent
        title_bar_layout.addWidget(self.title)
        # Min button
        self.min_button = QToolButton(self)
        min_icon = self.style().standardIcon(
            QStyle.StandardPixmap.SP_TitleBarMinButton
        )
        self.min_button.setIcon(min_icon)
        self.min_button.clicked.connect(self.window().showMinimized)

        # Max button
        self.max_button = QToolButton(self)
        max_icon = self.style().standardIcon(
            QStyle.StandardPixmap.SP_TitleBarMaxButton
        )
        self.max_button.setIcon(max_icon)
        self.max_button.clicked.connect(self.window().showMaximized)

        # Close button
        self.close_button = QToolButton(self)
        close_icon = self.style().standardIcon(
            QStyle.StandardPixmap.SP_TitleBarCloseButton
        )
        self.close_button.setIcon(close_icon)
        self.close_button.clicked.connect(self.window().close)

        # Normal button
        self.normal_button = QToolButton(self)
        normal_icon = self.style().standardIcon(
            QStyle.StandardPixmap.SP_TitleBarNormalButton
        )
        self.normal_button.setIcon(normal_icon)
        self.normal_button.clicked.connect(self.window().showNormal)
        self.normal_button.setVisible(False)
        # Add buttons
        buttons = [
            self.min_button,
            self.normal_button,
            self.max_button,
            self.close_button,
        ]
        for button in buttons:
            button.setFocusPolicy(Qt.FocusPolicy.NoFocus)
            button.setFixedSize(QSize(28, 28))
            button.setStyleSheet(
                """QToolButton { border: 2px solid white;
                                 border-radius: 12px;
                                }
                """
            )
            title_bar_layout.addWidget(button)

    def window_state_changed(self, state):
        if state == Qt.WindowState.WindowMaximized:
            self.normal_button.setVisible(True)
            self.max_button.setVisible(False)
        else:
            self.normal_button.setVisible(False)
            self.max_button.setVisible(True)
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Custom Title Bar")
        self.setMinimumSize(600, 400)
        self.setWindowFlags(Qt.FramelessWindowHint)
        # 使用QSS设置边框样式为圆角
        self.setStyleSheet("MainWindow{border-radius: 1px;}")
        central_widget = QWidget()
        self.title_bar = CustomTitleBar(self)
        work_space_layout = QVBoxLayout()
        work_space_layout.setContentsMargins(11, 11, 11, 11)
        work_space_layout.addWidget(QLabel("Hello, World!", self))
        centra_widget_layout = QVBoxLayout()
        centra_widget_layout.setContentsMargins(0, 0, 0, 0)
        centra_widget_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
        centra_widget_layout.addWidget(self.title_bar)
        centra_widget_layout.addLayout(work_space_layout)
        central_widget.setLayout(centra_widget_layout)
        self.setCentralWidget(central_widget)

    def changeEvent(self, event):
        if event.type() == QEvent.Type.WindowStateChange:
            self.title_bar.window_state_changed(self.windowState())
        super().changeEvent(event)
        event.accept()

    def window_state_changed(self, state):
        self.normal_button.setVisible(state == Qt.WindowState.WindowMaximized)
        self.max_button.setVisible(state != Qt.WindowState.WindowMaximized)

    def title_mousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self.initial_pos = event.position().toPoint()
        super().mousePressEvent(event)
        event.accept()

    def title_mouseMoveEvent(self, event):
        if self.initial_pos is not None:
            delta = event.position().toPoint() - self.initial_pos
            self.window().move(
                self.window().x() + delta.x(),
                self.window().y() + delta.y(),
            )
        super().mouseMoveEvent(event)
        event.accept()

    def title_mouseReleaseEvent(self, event):
        self.initial_pos = None
        super().mouseReleaseEvent(event)
        event.accept()

if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

效果如下,可以实现放大,缩小,标题栏拖动功能:

上面例子没有实现窗口边框可拖动放大缩小的功能,是个遗憾。github上的有实现,可以参考:https://github.com/alexpdev/QtFrameless。

相关推荐

Go语言泛型-泛型约束与实践(go1.7泛型)

来源:械说在Go语言中,Go泛型-泛型约束与实践部分主要探讨如何定义和使用泛型约束(Constraints),以及如何在实际开发中利用泛型进行更灵活的编程。以下是详细内容:一、什么是泛型约束?**泛型...

golang总结(golang实战教程)

基础部分Go语言有哪些优势?1简单易学:语法简洁,减少了代码的冗余。高效并发:内置强大的goroutine和channel,使并发编程更加高效且易于管理。内存管理:拥有自动垃圾回收机制,减少内...

Go 官宣:新版 Protobuf API(go pro版本)

原文作者:JoeTsai,DamienNeil和HerbieOng原文链接:https://blog.golang.org/a-new-go-api-for-protocol-buffer...

Golang开发的一些注意事项(一)(golang入门项目)

1.channel关闭后读的问题当channel关闭之后再去读取它,虽然不会引发panic,但会直接得到零值,而且ok的值为false。packagemainimport"...

golang 托盘菜单应用及打开系统默认浏览器

之前看到一个应用,用go语言编写,说是某某程序的windows图形化客户端,体验一下发现只是一个托盘,然后托盘菜单的控制面板功能直接打开本地浏览器访问程序启动的webserver网页完成gui相关功...

golang标准库每日一库之 io/ioutil

一、核心函数概览函数作用描述替代方案(Go1.16+)ioutil.ReadFile(filename)一次性读取整个文件内容(返回[]byte)os.ReadFileioutil.WriteFi...

文件类型更改器——GoLang 中的 CLI 工具

我是如何为一项琐碎的工作任务创建一个简单的工具的,你也可以上周我开始玩GoLang,它是一种由Google制作的类C编译语言,非常轻量和快速,事实上它经常在Techempower的基准测...

Go (Golang) 中的 Channels 简介(golang channel长度和容量)

这篇文章重点介绍Channels(通道)在Go中的工作方式,以及如何在代码中使用它们。在Go中,Channels是一种编程结构,它允许我们在代码的不同部分之间移动数据,通常来自不同的goro...

Golang引入泛型:Go将Interface「」替换为“Any”

现在Go将拥有泛型:Go将Interface{}替换为“Any”,这是一个类型别名:typeany=interface{}这会引入了泛型作好准备,实际上,带有泛型的Go1.18Beta...

一文带你看懂Golang最新特性(golang2.0特性)

作者:腾讯PCG代码委员会经过十余年的迭代,Go语言逐渐成为云计算时代主流的编程语言。下到云计算基础设施,上到微服务,越来越多的流行产品使用Go语言编写。可见其影响力已经非常强大。一、Go语言发展历史...

Go 每日一库之 java 转 go 遇到 Apollo?让 agollo 来平滑迁移

以下文章来源于GoOfficialBlog,作者GoOfficialBlogIntroductionagollo是Apollo的Golang客户端Apollo(阿波罗)是携程框架部门研...

Golang使用grpc详解(golang gcc)

gRPC是Google开源的一种高性能、跨语言的远程过程调用(RPC)框架,它使用ProtocolBuffers作为序列化工具,支持多种编程语言,如C++,Java,Python,Go等。gR...

Etcd服务注册与发现封装实现--golang

服务注册register.gopackageregisterimport("fmt""time"etcd3"github.com/cor...

Golang:将日志以Json格式输出到Kafka

在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:https://github.com/...

如何从 PHP 过渡到 Golang?(php转golang)

我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗旨,从零开始,开始学习。因为我司没有专门的Golang大牛,所以我也只能一步步自己去...