Python入坑系列:桌面GUI开发之Pyside6
阅读本章之后,你可以掌握这些内容:
- Pyside6的Signals and Slots、Envents的作用,如何使用?
- PySide6的Window、Dialogs and Alerts、Widgets、layouts 、Toolbars and Menus都是些什么,有哪些效果?
- 通过CSS类似样式文件怎么控制PySide6的组件样式?
安装Pyside6
- 环境版本
python | 3.10.6 |
pip | 22.3.1 |
- 直接安装
pip install pyside6
- 指定版本安装
pip install pyside6==6.6.2
Pyside6核心介绍
每个Qt应用程序的核心是QApplication类,每个应用程序都需要一个(且只有一个)QApplication对象来运行。QApplication对象保存应用程序的事件循环—控制所有用户与GUI交互的核心循环,与应用程序的每次交互—无论是按下键、单击鼠标还是移动鼠标—都会生成一个事件,该事件被放置在事件队列中。在事件循环中,在每次迭代时检查队列,如果发现等待事件,则将事件和控制传递给该事件的特定事件处理程序。事件处理程序处理事件,然后将控制传递回事件循环以等待更多事件。
制作一个简单桌面程序,只需要五步:
第一步:引入模块,如果偷懒,可以将import内容改成*
from PySide6.QtWidgets import QApplication, QWidget
第二步:创建QApplication对象,可以将sys.argv改成[],不接收命令行参数
app = QApplication(sys.argv)
第三步:构建QWidget对象或者QMainWindow对象
window = QMainWindow()
第四步:显示控件
window = QWidget()
window.show()
第五步:执行
app.exec()
1、Signals and Slots
信号(Signals)和插槽(Slots)是实现对象间通信的关键机制,这一机制允许对象在发生特定事件时通知其他对象,是一种事件驱动编程的核心概念,广泛应用于Qt应用程序中,特别是在GUI开发中。
信号(Signals):信号是组件在发生某些事情时发出的通知。比如从按下按钮,到输入框的文本改变,到窗口的文本改变。许多信号是由用户的动作发起的,但这不是一个规则。除了通知发生的事情外,信号还可以发送数据以提供有关发生的事情的额外上下文
插槽(Slots):用于信号接收器的名称。在Python中,应用程序中的任何函数(或方法)都可以用作插槽——只需将信号连接到它。如果信号发送数据,那么接收函数也将接收该数据。许多Qt小部件也有自己的内置插槽,这意味着您可以直接将Qt小部件连接在一起
2、Events
在Qt应用程序中,用户与应用程序的每一次交互都是一个事件。事件有很多种类型,每种类型代表不同类型的交互。Qt使用事件对象来表示这些事件,这些对象封装了发生了什么的信息。这些事件被传递给发生交互的小部件上的特定事件处理器。通过定义自定义的或扩展的事件处理器,你可以改变你的小部件对这些事件的响应方式。事件处理器就像定义其他方法一样,但名称是针对它们处理的事件类型的。小部件接收的主要事件之一是QMouseEvent。QMouseEvent事件为小部件上的每一次鼠标移动和按钮点击创建。
以下是可用于处理鼠标事件的事件处理器:
- mousePressEvent(event): 当鼠标按钮被按下时调用。
- mouseReleaseEvent(event): 当鼠标按钮被释放时调用。
- mouseDoubleClickEvent(event): 当鼠标按钮被双击时调用。
- mouseMoveEvent(event): 当鼠标移动时调用,但只有当至少一个鼠标按钮被按下时才会触发
3、Widget
部件(Widgets)是构建图形用户界面(GUI)的基本元素。小部件可以是一个按钮、文本框、标签、窗口等等。PySide提供了一系列预定义的小部件,允许开发者创建丰富的桌面应用程序。Pyside所有组件都继承自QWidget。
4、Layouts
在PySide(Qt for Python)中,布局是管理窗口或对话框中小部件位置和大小的对象。布局不仅可以自动调整小部件的大小以适应窗口,还可以在用户调整窗口大小时保持小部件之间的相对位置不变。使用布局是创建具有良好组织和可适应不同屏幕尺寸的图形用户界面(GUI)的关键。以下是几种可用基础布局:
- QVBoxLayout:将小部件垂直排列。
- QHBoxLayout:将小部件水平排列。
- QGridLayout:在一个网格中排列小部件。这是一种更灵活的布局方式,允许你在行和列中精确地放置小部件
- QFormLayout:用于表单布局,将标签与字段水平排列。
- QStackedLayout:允许你在相同的空间内堆叠多个小部件,每次只显示一个
小部件示例
以下展示的是几个简单的示例
1、Window
- 源代码:
import sys
from PySide6.QtCore import QSize
from PySide6.QtWidgets import QApplication, QMainWindow
def start():
app = QApplication(sys.argv)
window = QMainWindow()
window.setFixedSize(QSize(400, 300))
window.show()
app.exec()
if __name__ == '__main__':
start()
- 效果图:
2、Dialogs and Alerts
- 源代码:
import sys
from PySide6.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QMainWindow, QApplication, QPushButton
class CustomDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("HELLO!")
QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
self.layout = QVBoxLayout()
message = QLabel("Something happened, is that OK?")
self.layout.addWidget(message)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press me for a dialog!")
button.clicked.connect(self.button_clicked)
self.setCentralWidget(button)
def button_clicked(self, s):
print("click", s)
dlg = CustomDialog(self)
if dlg.exec():
print("Success!")
else:
print("Cancel!")
def start():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
if __name__ == '__main__':
start()
- 效果图:
3、Widgets
- 源代码:
import sys
from PySide6.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Widgets App")
layout = QVBoxLayout()
widgets = [QCheckBox,QComboBox,QDateEdit,QDateTimeEdit,QDial,QDoubleSpinBox,
QFontComboBox,QLCDNumber,QLabel,QLineEdit,QProgressBar,QPushButton,
QRadioButton,QSlider,QSpinBox,QTimeEdit,QTextEdit]
for widget in widgets:
widget_instance = widget() # 创建widget的实例
if isinstance(widget_instance, QDateEdit):
# 如果widget是QDateEdit类型,则启用日历弹出窗口
widget_instance.setCalendarPopup(True)
layout.addWidget(widget_instance) # 将widget实例添加到布局中
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def start():
"""组件的例子:https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QFontComboBox.html#qfontcombobox"""
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
if __name__ == '__main__':
start()
- 效果:
4、Layouts
- 源代码:
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout
from PySide6.QtGui import QPalette, QColor
class Color(QWidget):
def __init__(self, color):
super(Color, self).__init__()
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.Window, QColor(color))
self.setPalette(palette)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My App")
layout = QGridLayout()
layout.addWidget(Color('red'), 0, 0)
layout.addWidget(Color('green'), 1, 0)
layout.addWidget(Color('blue'), 1, 1)
layout.addWidget(Color('purple'), 2, 1)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
def start():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
if __name__ == '__main__':
start()
- 效果图:
4、Toolbars and Menus
- 源代码:
import sys
from PySide6.QtCore import QSize, Qt
from PySide6.QtGui import QAction, QIcon
from PySide6.QtWidgets import QMainWindow, QApplication, QLabel, QToolBar, QCheckBox, QStatusBar
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
label = QLabel("Hello!")
label.setAlignment(Qt.AlignCenter)
self.setCentralWidget(label)
toolbar = QToolBar("My main toolbar")
toolbar.setIconSize(QSize(16, 16))
self.addToolBar(toolbar)
button_action = QAction(QIcon("icons/bug.png"), "&Your button", self)
button_action.setStatusTip("This is your button")
button_action.triggered.connect(self.onMyToolBarButtonClick)
button_action.setCheckable(True)
toolbar.addAction(button_action)
toolbar.addSeparator()
button_action2 = QAction(QIcon("icons/bug.png"), "Your &button2", self)
button_action2.setStatusTip("This is your button2")
button_action2.triggered.connect(self.onMyToolBarButtonClick)
button_action2.setCheckable(True)
toolbar.addAction(button_action2)
toolbar.addWidget(QLabel("Hello"))
toolbar.addWidget(QCheckBox())
self.setStatusBar(QStatusBar(self))
menu = self.menuBar()
file_menu = menu.addMenu("&File")
file_menu.addAction(button_action)
file_menu.addSeparator()
file_menu.addAction(button_action2)
def onMyToolBarButtonClick(self, s):
print("click", s)
def start():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
if __name__ == '__main__':
start()
- 效果图:
如果需要图标的可以免费下载:
https://p.yusukekamiyamane.com/icon/downloads/fugue-icons-3.5.6.zip
QSS样式使用
QSS全称是 Qt Style Sheets(Qt 样式表),适用于小部件样式,语法几乎与html的css相同,功能上要弱一些。Pyside的样式支持两种方式:
1、代码直接引用
定义样式字符串,然后通过设置setStyleSheet来引用样式。
- 源代码:
import sys
from PySide6.QtCore import Slot, QSize
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QMainWindow, QWidget
def start():
app = QApplication(sys.argv)
window = QMainWindow()
window.setFixedSize(QSize(300,200))
layout = QVBoxLayout()
button = QPushButton("Click me")
btn_style = """ QPushButton {
background-color: red;
color: blue;
}
"""
button.setFixedSize(QSize(100,50))
button.setStyleSheet(btn_style)
button.clicked.connect(say_hello)
layout.addWidget(button)
widget = QWidget()
widget.setLayout(layout)
window.setCentralWidget(widget)
window.show()
app.exec()
@Slot()
def say_hello():
print("Button clicked, Hello!")
if __name__ == '__main__':
start()
- 效果图:
2、通过*.qss样式文件引用
1)定义样式文件,如btn_style.qss
/*匹配QLineEdit及其子类控件*/
QLineEdit{
color:yellow;
}
/*匹配QPushButton,QLineEdit,QTextEdit控件及其子控件,多个用逗号分隔*/
QPushButton,QLineEdit,QTextEdit{
color:yellow;
background-color:red;
}
/*匹配QLineEdit控件,但不匹配其子类控件*/
.QLineEdit{
color:yellow;
}
/*匹配所有object name为text的QLineEdit控件*/
QLineEdit#text{
color:yellow;
}
/*匹配QMainWindow内部 所有QLineEdit控件*/
QMainWindow QLineEdit{
color:yellow;
}
/*匹配QMainWindow内部 直接子节点上的 QLineEdit控件*/
QMainWindow > QLineEdit{
color:yellow;
}
/*匹配QLineEdit中具备属性input且值为'text'的控件*/
QLineEdit[input='text']{
color:yellow;
}
/*匹配QMenuBar菜单中的子项*/
QMenuBar::item{
color:yellow;
}
2)引用样式文件-全局方式
app = QApplication(sys.argv)
#全局引用
with open("btn_style.qss", "r") as f:
btn_style = f.read()
app.setStyleSheet(btn_style)
3)引用样式文件-局部引用
button = QPushButton("Click me")
button.setFixedSize(QSize(100,50))
#局部引用
with open("btn_style.qss", "r") as f:
btn_style = f.read()
button.setStyleSheet(btn_style)
button.clicked.connect(say_hello)
效果图: