Python图形界面开发
如果用 Python 语言开发 跨平台 的图形界面的程序,主要有3种选择:
Tkinter
基于Tk的Python库,这是Python官方采用的标准库,优点是作为Python标准库、稳定、发布程序较小,缺点是控件相对较少。
wxPython
基于wxWidgets的Python库,优点是控件比较丰富,缺点是稳定性相对差点、文档少、用户少。
PySide2、PyQt5
基于Qt 的Python库,优点是控件比较丰富、跨平台体验好、文档完善、用户多。
缺点是 库比较大,发布出来的程序比较大。
PySide2 是Qt的 亲儿子 , PyQt5 是Qt还没有亲儿子之前的收的 义子 (Riverbank Computing这个公司开发的)。
安装 PySide2
很简单,直接执行
pip install pyside2
即可下载安装。
这个库比较大,大概有100M左右,大家耐心等待。
有的朋友,网络比较慢,可以指定国内的安装源,下载安装。
比如,使用豆瓣源下载安装:
pip install pyside2 -i https://pypi.douban.com/simple/
建议:如果你的程序要发布给客户使用,建议使用32位的Python解释器,这样打包发布的exe程序可以兼容32位的Windows
安装PyQt5
如果你选择PyQt5,直接执行
conda create -n pyqt5env python=3.6
conda activate pyqt5env
pip install pyqt5 -i https://pypi.tuna.tsinghua.edu.cn/simple
测试程序
import sys
from PyQt5.QtWidgets import QApplication, QWidget
if __name__ == '__main__':
# qt主程序对象 需要创建一个
app = QApplication(sys.argv)
w = QWidget()
# 设置窗口标题
w.setWindowTitle("第一个PyQt")
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
模块介绍
PyQt中有非常多的功能模块,开发中最常用的功能模块主要有三个:
QtCore:包含了核心的非GUI的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime类文件、进程与线程一起使用
QtGui:包含了窗口系统、事件处理、2D图像、基本绘画、字体和文字类
QtWidgets:包含了一些列创建桌面应用的UI元素
可以参考PyQt官网的所有模块,地址:https://www.riverbankcomputing.com/static/Docs/PyQt5/module_index.html#ref-module-index
C++具体实现的API文档,地址:https://doc.qt.io/qt-5/qtwidgets-module.html
用到什么功能就它相关的api或者别人分享的使用心得,这是学习最快的方式
按钮
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
# 设置窗口标题
w.setWindowTitle("第一个PyQt程序")
# 在窗口里面添加控件
btn = QPushButton("按钮")
# 设置按钮的父亲是当前窗口,等于是添加到窗口中显示
btn.setParent(w)
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
文本
纯文本控件名称为 QLabel , 位于 PyQt5.QtWidgets 里面
纯文本控件仅仅作为标识显示而已,类似输入内容前的一段标签提示(账号 、密码)
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
# 设置窗口标题
w.setWindowTitle("第一个PyQt")
# # 下面创建一个Label,然后调用方法指定父类
# label = QLabel("账号: ", w)
# # 设置父对象
# label.setParent(w)
# 下面创建一个Label(纯文本),在创建的时候指定了父对象
label = QLabel("账号: ", w)
# 显示位置与大小 : x, y , w, h
label.setGeometry(200, 200, 30, 30)
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
输入框
输入框的控件名称为 QLineEdit, 位于 PyQt5.QtWidgets 里面
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QLineEdit
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
# 设置窗口标题
w.setWindowTitle("第一个PyQt")
# 纯文本
label = QLabel("账号", w)
label.setGeometry(20, 20, 30, 20)
# 文本框
edit = QLineEdit(w)
edit.setPlaceholderText("请输入账号")
edit.setGeometry(55, 20, 200, 20)
# 在窗口里面添加控件
btn = QPushButton("注册", w)
btn.setGeometry(50, 80, 70, 30)
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
调整窗口大小
import sys
from PyQt5.QtWidgets import QApplication, QWidget
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
# 设置窗口标题
w.setWindowTitle("第一个PyQt")
# 窗口的大小
w.resize(300, 300)
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
窗口显示在屏幕的中间
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
# 设置窗口标题
w.setWindowTitle("第一个PyQt")
# 窗口的大小
w.resize(300, 300)
# 将窗口设置在屏幕的左上角
# w.move(0, 0)
# 调整窗口在屏幕中央显示
center_pointer = QDesktopWidget().availableGeometry().center()
x = center_pointer.x()
y = center_pointer.y()
# w.move(x, y)
# w.move(x-150, y-150)
print(w.frameGeometry())
print(w.frameGeometry().getRect())
print(type(w.frameGeometry().getRect()))
old_x, old_y, width, height = w.frameGeometry().getRect()
w.move(x - width / 2, y - height / 2)
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
设置窗口icon
可以下载icon图标网站:https://www.easyicon.net/
https://www.iconfont.cn/
https://www.aigei.com/s?q=%E7%86%8A%E7%8C%AB&type=icon_7
import sys
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建一个QWidget
w = QWidget()
# 设置标题
w.setWindowTitle("看看我图标帅吗")
# 设置图标
w.setWindowIcon(QIcon('panda.png'))
# 显示QWidget
w.show()
app.exec()
布局
在Qt里面布局分为四个大类 :
QBoxLayout
QGridLayout
QFormLayout
QStackedLayout
一、QBoxLayout
直译为:盒子布局
一般使用它的两个子类QHBoxLayout 和 QVBoxLayout 负责水平和垂直布局
垂直布局示例:
import sys
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget, QPushButton, QGroupBox, QMainWindow
from PyQt5.QtCore import Qt
class MyWindow(QWidget):
def __init__(self):
# 切记一定要调用父类的__init__方法,因为它里面有很多对UI空间的初始化操作
super().__init__()
# 设置大小
self.resize(300, 300)
# 设置标题
self.setWindowTitle("垂直布局")
# 垂直布局
layout = QVBoxLayout()
# 作用是在布局器中增加一个伸缩量,里面的参数表示QSpacerItem的个数,默认值为零
# 会将你放在layout中的空间压缩成默认的大小
# 下面的笔试1:1:1:2
layout.addStretch(1)
# 按钮1
btn1 = QPushButton("按钮1")
# 添加到布局器中
# layout.addWidget(btn1, Qt.AlignmentFlag.AlignTop)
layout.addWidget(btn1)
# 弹簧,写参数就是按照所有弹簧的比例关系 弹。
layout.addStretch(1)
# 按钮2
btn2 = QPushButton("按钮2")
# 添加到布局器
layout.addWidget(btn2)
layout.addStretch(1)
# 按钮3
btn3 = QPushButton("按钮3")
# 添加到布局器
layout.addWidget(btn3)
layout.addStretch(2)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
# 创建一个QWidget子类
w = MyWindow()
w.show()
app.exec()
水平布局
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QGroupBox, QVBoxLayout, QHBoxLayout, QRadioButton
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
# 最外层的垂直布局,包含两部分:爱好和性别
container = QVBoxLayout()
# -----创建第1个组,添加多个组件-----
# hobby 主要是保证他们是一个组。
hobby_box = QGroupBox("爱好")
# v_layout 保证三个爱好是垂直摆放
v_layout = QVBoxLayout()
btn1 = QRadioButton("抽烟")
btn2 = QRadioButton("喝酒")
btn3 = QRadioButton("烫头")
# 添加到v_layout中
v_layout.addWidget(btn1)
v_layout.addWidget(btn2)
v_layout.addWidget(btn3)
# 把v_layout添加到hobby_box中
hobby_box.setLayout(v_layout)
# -----创建第2个组,添加多个组件-----
# 性别组
gender_box = QGroupBox("性别")
# 性别容器
h_layout = QHBoxLayout()
# 性别选项
btn4 = QRadioButton("男")
btn5 = QRadioButton("女")
# 追加到性别容器中
h_layout.addWidget(btn4)
h_layout.addWidget(btn5)
# 添加到 box中
gender_box.setLayout(h_layout)
# 把爱好的内容添加到容器中
container.addWidget(hobby_box)
# 把性别的内容添加到容器中
container.addWidget(gender_box)
# 设置窗口显示的内容是最外层容器
self.setLayout(container)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
QGridLayout 网格布局
网格布局,有的人称之为九宫格布局
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLineEdit, QGridLayout
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("计算器")
# 准备数据
data = {
0: ["7", "8", "9", "+", "("],
1: ["4", "5", "6", "-", ")"],
2: ["1", "2", "3", "*", "<-"],
3: ["0", ".", "=", "/", "C"]
}
# 整体垂直布局
layout = QVBoxLayout()
# 输入框
edit = QLineEdit()
edit.setPlaceholderText("请输入内容")
# 把输入框添加到容器中
layout.addWidget(edit)
# 网格布局
grid = QGridLayout()
# 循环创建追加进去
for line_number, line_data in data.items():
# 此时line_number是第几行,line_data是当前行的数据
for col_number, number in enumerate(line_data):
# 此时col_number是第几列,number是要显示的符号
btn = QPushButton(number)
# grid.addWidget(btn)
# 参数,ui元素,行号(从0开始),列号(从0开始)
grid.addWidget(btn, line_number, col_number)
# 把网格布局追加到容器中
layout.addLayout(grid)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
QFormLayout 表单布局
一般适用于提交数据form表单。比如: 登录,注册类似的场景
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QVBoxLayout, QFormLayout, QLineEdit, QPushButton, QApplication, QWidget
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
# 设定当前Widget的宽高(可以拉伸大小)
# self.resize(300, 200)
# 禁止改变宽高(不可以拉伸)
self.setFixedSize(300, 150)
# 外层容器
container = QVBoxLayout()
# 表单容器
form_layout = QFormLayout()
# 创建1个输入框
edit = QLineEdit()
edit.setPlaceholderText("请输入账号")
form_layout.addRow("账号:", edit)
# 创建另外1个输入框
edit2 = QLineEdit()
edit2.setPlaceholderText("请输入密码")
form_layout.addRow("密码:", edit2)
# 将from_layout添加到垂直布局器中
container.addLayout(form_layout)
# 按钮
login_btn = QPushButton("登录")
login_btn.setFixedSize(100, 30)
# 把按钮添加到容器中,并且指定它的对齐方式
container.addWidget(login_btn, alignment=Qt.AlignRight)
# 设置当前Widget的布局器,从而显示这个布局器中的子控件
self.setLayout(container)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
QStackedLayout 抽屉布局
提供了多页面切换的布局,一次只能看到一个界面。 抽屉布局
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QStackedLayout, QLabel
class Window1(QWidget):
def __init__(self):
super().__init__()
QLabel("我是抽屉1要显示的内容", self)
self.setStyleSheet("background-color:green;")
class Window2(QWidget):
def __init__(self):
super().__init__()
QLabel("我是抽屉2要显示的内容", self)
self.setStyleSheet("background-color:red;")
class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.create_stacked_layout()
self.init_ui()
def create_stacked_layout(self):
# 创建堆叠(抽屉)布局
self.stacked_layout = QStackedLayout()
# 创建单独的Widget
win1 = Window1()
win2 = Window2()
# 将创建的2个Widget添加到抽屉布局器中
self.stacked_layout.addWidget(win1)
self.stacked_layout.addWidget(win2)
def init_ui(self):
# 设置Widget大小以及固定宽高
self.setFixedSize(300, 270)
# 1. 创建整体的布局器
container = QVBoxLayout()
# 2. 创建1个要显示具体内容的子Widget
widget = QWidget()
widget.setLayout(self.stacked_layout)
widget.setStyleSheet("background-color:grey;")
# 3. 创建2个按钮,用来点击进行切换抽屉布局器中的Widget
btn_press1 = QPushButton("抽屉1")
btn_press2 = QPushButton("抽屉2")
# 给按钮添加事件(即点击后要调用的函数)
btn_press1.clicked.connect(self.btn_press1_clicked)
btn_press2.clicked.connect(self.btn_press2_clicked)
# 4. 将需要显示的空间添加到布局器中
container.addWidget(widget)
container.addWidget(btn_press1)
container.addWidget(btn_press2)
# 5. 设置当前要显示的Widget,从而能够显示这个布局器中的控件
self.setLayout(container)
def btn_press1_clicked(self):
# 设置抽屉布局器的当前索引值,即可切换显示哪个Widget
self.stacked_layout.setCurrentIndex(0)
def btn_press2_clicked(self):
# 设置抽屉布局器的当前索引值,即可切换显示哪个Widget
self.stacked_layout.setCurrentIndex(1)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MyWindow()
win.show()
app.exec()
窗口
一、分类
在Qt中,生成窗口有三种方式: QWidget | QMainWindow | QDialog
-
QWidget
控件和窗口的父类 ,自由度高(什么都东西都没有),没有划分菜单、工具栏、状态栏、主窗口 等区域 -
QMainWindow
是 QWidget的子类,包含菜单栏,工具栏,状态栏,标题栏等,中间部分则为主窗口区域 -
QDialog
对话框窗口的基类
QWidget
import sys
from PyQt5.QtWidgets import QWidget, QLabel , QApplication
class mywnd(QWidget):
def __init__(self):
super(mywnd, self).__init__()
self.initUI()
def initUI(self):
label = QLabel("这是文字~~" )
label.setStyleSheet("font-size:30px;color:red")
label.setParent(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = mywnd()
#设置窗口标题
w.setWindowTitle("qwidget")
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
QMainWindow
import sys
from PyQt5.QtWidgets import QMainWindow, QLabel, QApplication
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
label = QLabel("这是文字~~")
label.setStyleSheet("font-size:30px;color:red")
# 调用父类中的menuBar,从而对菜单栏进行操作
menu = self.menuBar()
# 如果是Mac的话,菜单栏不会在Window中显示而是屏幕顶部系统菜单栏位置
# 下面这一行代码使得Mac也按照Windows的那种方式在Window中显示Menu
menu.setNativeMenuBar(False)
file_menu = menu.addMenu("文件")
file_menu.addAction("新建")
file_menu.addAction("打开")
file_menu.addAction("保存")
edit_menu = menu.addMenu("编辑")
edit_menu.addAction("复制")
edit_menu.addAction("粘贴")
edit_menu.addAction("剪切")
# 设置中心内容显示
self.setCentralWidget(label)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
# 设置窗口标题
w.setWindowTitle("我是窗口标题....")
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
QDialog 对话框
不过对话框一般不应该作为主窗口的存在,而是通过点击操作弹出,起到提示作用
import sys
from PyQt5.QtWidgets import QDialog, QPushButton, QApplication
class MyDialog(QDialog):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
ok_btn = QPushButton("确定", self)
ok_btn.setGeometry(50, 50, 100, 30)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyDialog()
# 设置窗口标题
w.setWindowTitle("对话框")
# 展示窗口
w.show()
# 程序进行循环等待状态
app.exec()
信号与槽
一、说明
信号和槽是 Qt的核心内容
- 信号(signal)
其实就是事件(按钮点击 、内容发生改变 、窗口的关闭事件) 或者是 状态 (check选中了, togglebutton 切换。)
当程序触发了某种状态或者发生了某种事件(比如:按钮被点击了, 内容改变等等),那么即可发射出来一个信号。
-
槽( slot)
若想捕获这个信号,然后执行相应的逻辑代码,那么就需要使用到 槽 , 槽实际上是一个函数, 当信号发射出来后,会执行与之绑定的槽函数 -
将信号与槽链接
为了能够实现,当点击某个按钮时执行某个逻辑,需要把具体的信号和具体的槽函数绑定到一起.
操作大体流程如下
对象.信号.connect(槽函数)
需求:
当出现了某一种信号(某一种事件)的时候,我们需要执行一段代码(用函数来包装这份代码。)
解决的办法:
信号和槽
功能:接收信号
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
# 更改当前Widge的宽高
self.resize(500, 300)
# 创建一个按钮
btn = QPushButton("点我点我", self)
# 设置窗口位置、宽高
btn.setGeometry(200, 200, 100, 30)
# 将按钮被点击时触发的信号与我们定义的函数(方法)进行绑定
# 注意:这里没有(),即写函数的名字,而不是名字()
btn.clicked.connect(self.click_my_btn)
def click_my_btn(self, arg):
# 槽函数,点击按钮则调用该函数
# 这里的参数正好是信号发出,传递的参数
print("点击按钮啦~", arg)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
自定义信号
除了接收Qt自带的信号之外,我们也可以自行定义信号,在合适的时机,自行发射信号
自定义信号需要使用到 pyqtSignal来声明信号 ,并且需要在类中的函数之外声明
如果会自定义信号,那么信号和槽基本上也就掌握了。否则永远只会接收别人发射出的信号
import sys
import time
#from PyQt5.QtWidgets import *
#from PyQt5.QtCore import *
from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QScrollArea, QHBoxLayout, QPushButton, QApplication
class MyWindow(QWidget):
# 声明一个信号 只能放在函数的外面,只能放在类属性中
my_signal = pyqtSignal(str)
def __init__(self):
super().__init__()
self.init_ui()
self.msg_history = list() # 用来存放消息
def init_ui(self):
self.resize(500, 200)
# 创建一个整体布局器
container = QVBoxLayout()
# 用来显示检测到漏洞的信息
self.msg = QLabel("")
self.msg.resize(440, 15)
# print(self.msg.frameSize())
self.msg.setWordWrap(True) # 自动换行
self.msg.setAlignment(Qt.AlignTop) # 靠上
# self.msg.setStyleSheet("background-color: yellow; color: black;")
# 创建一个滚动对象
scroll = QScrollArea()
scroll.setWidget(self.msg)
# 创建垂直布局器,用来添加自动滚动条
v_layout = QVBoxLayout()
v_layout.addWidget(scroll)
# 创建水平布局器
h_layout = QHBoxLayout()
btn = QPushButton("开始检测", self)
# 绑定按钮的点击,点击按钮则开始检测
btn.clicked.connect(self.check)
h_layout.addStretch(1) # 伸缩器
h_layout.addWidget(btn)
h_layout.addStretch(1)
# 操作将要显示的控件以及子布局器添加到container
container.addLayout(v_layout)
container.addLayout(h_layout)
# 设置布局器
self.setLayout(container)
# 绑定信号和槽
self.my_signal.connect(self.my_slot)
def my_slot(self, msg):
# 更新内容
print(msg)
self.msg_history.append(msg)
self.msg.setText("<br>".join(self.msg_history))
self.msg.resize(440, self.msg.frameSize().height() + 15)
self.msg.repaint() # 更新内容,如果不更新可能没有显示新内容
def check(self):
for i, ip in enumerate(["192.168.1.%d" % x for x in range(1, 255)]):
msg = "模拟,正在检查 %s 上的漏洞...." % ip
# print(msg)
if i % 5 == 3:
# 表示发射信号 对象.信号.发射(参数)
self.my_signal.emit(msg + "【发现漏洞】")
time.sleep(0.01)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
app.exec()
Qt Designer
一、介绍
纯靠代码来编写界面,效率属实是有点底,今天我们用另外一个辅助设计图形化的软件 QT Designer
- 下载
https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.9/5.9.0/
python代码使用test.ui文件
"""
动态加载ui文件
"""
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5 import uic
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = uic.loadUi("./test.ui")
# 展示窗口
ui.show()
app.exec()
python代码使用test.ui文件中的对象
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.ui = uic.loadUi("./login.ui")
# print(self.ui.__dict__) # 查看ui文件中有哪些控件
# 提取要操作的控件
self.user_name_qwidget = self.ui.lineEdit # 用户名输入框
self.password_qwidget = self.ui.lineEdit_2 # 密码输入框
self.login_btn = self.ui.pushButton # 登录按钮
self.forget_password_btn = self.ui.pushButton_2 # 忘记密码按钮
self.textBrowser = self.ui.textBrowser # 文本显示区域
# 绑定信号与槽函数
self.login_btn.clicked.connect(self.login)
def login(self):
"""登录按钮的槽函数"""
user_name = self.user_name_qwidget.text()
password = self.password_qwidget.text()
if user_name == "admin" and password == "123456":
self.textBrowser.setText("欢迎%s" % user_name)
self.textBrowser.repaint()
else:
self.textBrowser.setText("用户名或密码错误....请重试")
self.textBrowser.repaint()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
# 展示窗口
w.ui.show()
app.exec()
多线程
import sys
import time
from PyQt5 import uic
from PyQt5.Qt import QApplication, QWidget, QThread
class MyThread(QThread):
def __init__(self):
super().__init__()
def run(self):
for i in range(10):
print("是MyThread线程中执行....%d" % (i + 1))
time.sleep(1)
class MyWin(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.ui = uic.loadUi("./thread-1.ui")
# 从ui文件中加载控件
lineedit = self.ui.lineEdit
btn1 = self.ui.pushButton
btn2 = self.ui.pushButton_2
# 给2个按钮绑定槽函数
btn1.clicked.connect(self.click_1) # 绑定槽函数
btn2.clicked.connect(self.click_2) # 绑定槽函数
def click_1(self):
for i in range(10):
print("是UI线程中执行....%d" % (i + 1))
time.sleep(1)
def click_2(self):
# 这里注意不能是局部变量,因为局部变量执行完成会销毁,导致bug
self.my_thread = MyThread() # 创建线程
self.my_thread.start() # 开始线程
if __name__ == "__main__":
app = QApplication(sys.argv)
myshow = MyWin()
myshow.ui.show()
app.exec()
子线程调用可以有两种方式:方式一:在槽函数触发之后子线程start(),每次执行run方法。方式二:主线程中启动子线程的run方法一直死循环,执行的函数写在子线程中, 使用槽函数触发的时候触发子线程中的函数,这样是由子线程来处理。
PySide2安装踩坑指南
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyside2
踩坑
开开心心找了一个案例:
from PySide2.QtWidgets import QApplication, QMainWindow, QPushButton, QPlainTextEdit
app = QApplication([])
window = QMainWindow()
window.resize(500, 400)
window.move(300, 310)
window.setWindowTitle('薪资统计')
textEdit = QPlainTextEdit(window)
textEdit.setPlaceholderText("请输入薪资表")
textEdit.move(10,25)
textEdit.resize(300,350)
button = QPushButton('统计', window)
button.move(380,80)
window.show()
app.exec_()
一运行就报错:
qt.qpa.plugin: Could not load the Qt platform plugin "windows" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: direct2d, minimal, offscreen, windows.
PySide2是QT官方出的Python的QT封装,不过默认安装运行的时候会出现一些小问题,可能是系统里已经安装了其他版本的QT的原因,
可以通过添加环境变量来解决:
import os
envpath = r'D:\anaconda3\Lib\site-packages\PySide2\plugins\platforms'
os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = envpath
这样就能正常运行了!