官方文档
# 安装pyside2
pip install pyside2 # 比较新的pyside6 + python3.7+
# 注意导入时
import PySide2
from PySide2.QtCore import QTimer, QDateTime, Qt
from PySide2.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout
from PySide2.QtGui import QIcon, QPixmap, QPicture, QFont, QPalette, QKeyEvent, QMouseEvent
使用方式 同pyqt5 类似
# __author__ = "laufing"
# class_based_qt
# laufing_qt
import sys
import random
from PySide2.QtWidgets import QApplication, QWidget, QDesktopWidget, QLabel, QPushButton, QBoxLayout, QVBoxLayout, QHBoxLayout, QFormLayout, QGridLayout, QStackedLayout
from PySide2.QtCore import QTimer, QDateTime, QDate, QTime, Qt
from PySide2.QtGui import QIcon, QPixmap, QPicture, QPalette, QColor, QFont, QKeyEvent, QMouseEvent
# 定义自己的窗口控件
class MyWidget(QWidget):
def __init__(self):
super().__init__()
# 实例化一个窗口,并居中显示
desk = QDesktopWidget().geometry()
width, height = desk.width(), desk.height()
self.resize(500, 400)
self.move(width//2 - self.width()//2, height//2 - self.height()//2)
self.setWindowTitle("PySide2 应用")
self.setWindowIcon(QIcon("./imgs/dog.jpg"))
# 人物
self.choiceList = ["jack", 'lucy', 'rose']
# 垂直布局
vb = QVBoxLayout()
vb.setContentsMargins(10, 10, 10, 10)
# label标签
self.label = QLabel("欢迎 %s"%self.choiceList[0])
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
# 按钮
self.button = QPushButton("点击我")
self.button.setStyleSheet("backgroundd-color: lightblue;")
# 信号与槽
self.button.clicked.connect(self.magic)
vb.addWidget(self.label)
vb.addWidget(self.button)
# 父控件设置布局
self.setLayout(vb)
def magic(self):
print("点击了按钮...")
self.label.setText(self.label.text().split()[0] + " " + random.choice(self.choiceList))
if __name__ == '__main__':
app = QApplication(sys.argv)
# 实例化我的窗口
window = MyWidget()
window.show()
exit_code = app.exec_()
sys.exit(exit_code)
用于布局、设计界面
,实现布局与代码分离!!
在安装的python环境中Scripts目录下有designer.exe,将其绝对路径配置在pycharm中:
file>setttings>tools>external tools
使用:
Tools>external tools> PySide2Designer 创建一个窗口如下图:
Ctrl + s 保存为xx.ui文件
Ctrl + r 预览
Ctrl + n 新建
Ctrl + o 打开
选中多个子控件或者父控件,进行布局:
Ctrl + 1 水平布局;
Ctrl + 2 垂直布局
Ctrl + 5 Grid布局
Ctrl + 0 解除布局
保存后,产生的ui文件 是xml文件内容
,使用时,第一种方式就是python加载ui文件;第二种方式是转换为py文件。
# 导入类
from PySide2.QtUiTools import QUiLoader # 模块下只有一个类
from PySide2.QtCore import QFile, QObject
from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QLabel
from PySide2.QtWidgets import QMainWindow, QWidget
# 定义自己的类
class MyWindow():
def __init__(self):
# 封装文件对象
qfile = QFile("jack.ui")
# 打开文件 成功则返回True
qfile.open(QFile.ReadOnly) # 只读方式打开
# 读取数据(字节串)
# l = qfile.readLine()
# print("读取的一行数据:", l)
# 关闭文件
qfile.close()
# 加载所有的文件内容,返回父窗口对象
# 子控件 成为父控件的属性
self.win = QUiLoader().load(qfile)
print("加载所有的文件:", self.win, type(self.win), self.win.inherits("QWidget"))
def show(self):
# 信号与槽函数 这里的pushButton是对象的名字
self.win.pushButton.clicked.connect(lambda :print("点击了按钮......"))
self.win.show()
if __name__ == '__main__':
# 程序必须具有基本结构
import sys
app = QApplication(sys.argv)
win = MyWindow()
win.show()
exit_code = app.exec_()
print("退出的状态码:", exit_code)
sys.exit(exit_code)
pycharm:
Ctrl + f 搜索
Ctrl + r 替换
断点 + debugger 可以查看相应变量
另外ui文件也可以转为python文件
,需要使用uic,在python3的安装目录Scripts下有如下工具:
将pyside2-uic.exe的绝对路径配置在pycharm中,方法同designer的配置。
xxxx\pyside2-uic.exe
$FileName$ -o $FileNameWithoutExtension$.py
$FileDir$
然后在ui文件上,右键>External tools > pyside2uic 即可转为py文件。
将Qt ui文件转为python文件
在python的安装目录下的Scripts目录,有如下的文件:
将pyside2-uic.exe 配置到pycharm中即可,方式同designer.exe
Program: python目录/Scripts/pyside2-uic.exe
Arguments: $FileName$ -o $FileNameWithoutExtension$.py
Working directory: $FileDir$
使用Qt designer 实现如下界面
使用qt designer 设计布局
:
首先拖入子控件,并摆放整齐
设计布局,选中相关的控件,右键->布局->选择布局
最后的整体垂直布局,没有红色框线,只需在Form上右键-布局即可。
布局内的控件是一个整体,单个的控件不再支持手动拖拽。
button缩放水平fixed、垂直fixed,水平布局可居中。
单个label 水平布局也居中。
请求头,+按钮,-按钮控件的sizePolicy 水平伸缩分别为4 1 1;两个按钮之间还可以放spacer,并调整宽度。
最后添加spacer,调整控件间距,不要与控件一起选中,然后布局。
伸缩:可选中单个子控件(设置sizePolicy),也可选中整个红线框(layoutStretch-3,2,3,…)综合设置各个子控件的伸缩比例。
碰到的问题, 就是整体没有实现布局,所以窗口缩放时,内容控件不变
,在父控件右键-布局即可
设计好布局,保存文件
使用python 加载ui文件
#
from PySide2.QtUiTools import QUiLoader # 模块下只有一个类
from PySide2.QtCore import QFile, QObject
from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QLabel
from PySide2.QtWidgets import QMainWindow, QWidget
class MyWindow():
def __init__(self):
# 封装文件对象
qfile = QFile("jack.ui")
# 打开文件
qfile.open(QFile.ReadOnly) # 只读方式打开
# 读取数据(字节串)
# l = qfile.readLine()
# print("读取的一行数据:", l)
# 关闭文件
qfile.close()
# 加载所有的文件内容,返回父窗口对象
# 子控件 成为父控件的属性
self.win = QUiLoader().load(qfile)
print("加载所有的文件:", self.win, type(self.win), self.win.inherits("QWidget"))
def show(self):
self.win.clearBtn.clicked.connect(lambda :print("点击了清空......"))
self.win.show()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
win = MyWindow()
win.show()
exit_code = app.exec_()
print("退出的状态码:", exit_code)
sys.exit(exit_code)
将python程序打包为.exe程序,这里使用pyinstaller
打包
安装pyinstaller:
$ pip install pyinstaller
$ pyinstaller --version
$ pyinstaller --help
打包单个python脚本:
# -F 打包成一个可执行文件
# -w windows 平台
# --noconsole 程序运行时没有控制台
# --hidden-import 动态导入 (打包前导入)
# --hidden-import csv --hidden-import pathlib
# --icon=程序打包后的图标,需要是.ico文件
pyinstaller -F -w main.py --noconsole --hidden-import PySide2.QtXml --icon='xxxx.ico'
# 注意 此时的静态文件并不会打包到.exe,如sqlite.db or ui文件等
# 需要手动复制到dist下的相应目录
打包整个项目:
# 简单打包
pyinstaller -F -w --noconsole main.py -p 其他的包(python路径搜索不到)
打包静态文件
if getattr(sys, 'frozen', None):
basedir = sys._MEIPASS
else:
basedir = os.path.dirname(__file__)
# 调用
db_path = os.path.join(basedir, 'data.db')
相关联的单选、多选放入一个容器组,如QGroupBox、QWidget等
Qt Style Sheet 设置GUI 样式
# 按钮为禁用状态时的样式
QPushButton:disabled{
color: cyan;
}
# 鼠标悬浮 且为勾选状态时 的样式
QCheckBox:hover:checked {
color: red;
}
常用属性
# 背景色
background-color:red;
background-image: url(./imgs/dog.jpg)
# 边框
border: 1px solid red;
border: none;
width: 200px;
height: 100px;
font-family: 黑体;
font-weight: bold;
font-style: italic;
font-size: 16px;
margin: 0;
padding: 10px;
可以使用python内置模块threading,也可以使用Qt封装的QThread;
如果子线程处理的任务与Qt相关,则使用QThread
简单使用
# 耗费时间的任务
def task(t):
print("耗费时间的任务")
time.sleep(t)
print("任务结束...")
# 槽函数,内部创建子线程
def myFunc():
print("开启子线程")
thread = Thread(target=task, args=(10,), name="task1")
# 开启子线程,不用等待子线程执行结束
thread.start()
# 按钮绑定槽函数
btn.clicked.connect(myFunc)
子线程完成,发送信号,更新界面,而不是直接更新界面。
在子线程中,更新界面会发生意外错误,如主界面崩溃等
from PySide2.QtCore import QObject, Signal
# 定义自己的类
class MySignal(QObject):
# 类属性是一个信号对象, 并标识传递的数据类型
s1 = Signal(str)
# 具体使用
class Ui_Form(object):
def __init__(self):
super(Ui_Form, self).__init__()
# 实例化信号对象,并绑定槽函数
self.sig = MySignal()
self.sig.s1.connect(self.updateGui)
def updateGui(self, *args, **kwargs):
# 主线程更新
self.pushButton.setText(args[0])
def setupUi(self, Form):
if not Form.objectName():
Form.setObjectName(u"Form")
Form.setEnabled(True)
Form.resize(1153, 614)
self.pushButton = QPushButton(Form)
self.pushButton.setObjectName(u"pushButton")
self.pushButton.setGeometry(QRect(510, 120, 93, 28))
self.pushButton.clicked.connect(self.myFunc)
self.radioButton = QRadioButton(Form)
self.radioButton.setObjectName(u"radioButton")
self.radioButton.setGeometry(QRect(510, 200, 115, 19))
self.retranslateUi(Form)
QMetaObject.connectSlotsByName(Form)
# setupUi
def retranslateUi(self, Form):
Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
self.pushButton.setText(QCoreApplication.translate("Form", u"\u70b9\u51fb", None))
self.radioButton.setText(QCoreApplication.translate("Form", u"RadioButton", None))
# retranslateUi
# 槽函数,内部创建子线程
def myFunc(self):
# 耗费时间的任务
def task(t):
print("耗费时间的任务")
for i in range(10):
print("任务执行中...{}".format(i))
# 发送信号给主线程,更新界面
self.sig.s1.emit("{}".format(i))
time.sleep(1)
print("开启线子程")
thread = Thread(target=task, args=(10,), name="task1")
thread.start()
官网案例