Python入坑系列-pyside6桌面开发之QmainWindow自定义标题栏
bigegpt 2024-10-12 05:26 30 浏览
通过本文章,可以掌握以下内容:
- QMainWindow布局
- QMainWindow常用属性和方法介绍
- QMainWindow图标和背景设置
- 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大牛,所以我也只能一步步自己去...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- linux安装minio (74)
- ubuntuunzip (67)
- vscode使用技巧 (83)
- secure-file-priv (67)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)