根据此前的PyQt学习,这里对PyQt的学习过程进行最后的总结
前文链接:由于前文标题名字取了一样的,以下内容按照前后顺序排列
(1)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
(2)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
(3)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
(4)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
(5)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
下面是最后一点内容
(十二)腾讯云函数
后续案例要用到腾讯云函数,这里先了解一下
注册腾讯云后新建一个函数
测试函数默认先不用管
完成
创建一个触发器
创建后这里有个链接
直接访问链接,可以看到已经调用
腾讯云给人使用的免费额度是100万次
(十三)Qt Designer
利用Qt Designer可以快速设计UI界面,比起直接写代码,效率要快速很多,下面记录一下Qt Designer使用过程
(1)Python调用ui文件显示界面
由于在Pycharm中直接配置了了PyQt5,PyQt5是自带Qt Designer工具的
所以直接在Anaconda工具包中搜索designer.exe,然后发送快捷方式到桌面
Qt Designer的快捷方式如下
双击designer.exe打开设计页面,新建空白页面
拖一些控件先做一个测试页面
直接crtl+s保存为ui文件
然后利用Python调用ui文件,Python代码以及显示功能如下
(2)案例展示
为了更好理解上述过程,这里做了一个案例巩固知识
如下图先做一个页面
这里把页面右下角的信号与槽拖出来
假设设计如下的信号与槽接收页面
当点击登录的时候,文本框就会关闭,预览效果如下,但是在设计页面设计信号与槽,功能很受限
(3)控件添加信号与槽
1.这里直接使用上面案例的界面,整体代码如下
"""
动态加载ui文件
"""
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.ui = None
self.user_name = None
self.password = None
self.init_ui()
def init_ui(self):
self.ui = uic.loadUi("D:\\Qt\\QtData\\PyQt\\PyQtLesson\\Qt Designer\\login_test.ui")
# print(self.ui) # ui文件中最顶层的对象
# print(self.ui.__dict__) # 最顶层对象的所有属性(key:value方式显示)
# print(self.ui.label) # 最顶层对象中嵌套的QLabel
# print(self.ui.label.text()) # 最顶层对象中嵌套的QLabel的文本
self.user_name = self.ui.lineEdit # 用户名输入框
self.password = self.ui.lineEdit_2 # 密码输入框
login_btn = self.ui.pushButton # 登录按钮
forget_btn = self.ui.pushButton_2 # 忘记密码按钮
text_browser = self.ui.textBrowser # 文本显示区域
# 给登录按钮被点击绑定槽函数
login_btn.clicked.connect(self.login)
def login(self):
"""实现登录的逻辑"""
print("正在登录。。。。。。")
# 提取用户名,密码
print(self.user_name.text())
print(self.password.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.ui.show()
app.exec_()
2.关键代码分析
<1>__init__函数中声明属性
假设这里把__init__函数中的self.user_name = None等注释,Pycharm解释器会提醒
Instance attribute user_name defined outside __init__
这里的意思就是说,我在def init_ui(self):这个函数中,要给self指向的对象添加user_name这个属性,但是我在__init__函数中又没有进行这个属性的声明,于是要在__init__函数中声明一下
<2>窗口显示代码
这里我们发现窗口显示代码并不是w.show()
这是因为我们最终要显示的界面是ui所用的绘图界面,而不是调用w这个空壳界面
<3>print(self.ui.__dict__)
看看.ui文件有什么属性,如下图蓝色框,红色框是获取登录信息
在这里,我们看到加载后的.ui文件有7个对象属性,正好与在设计.ui文件时控件的数量一致,可见属性的个数正好对应.ui文件中的空间个数,所以想要操作哪个空间,就通过对象.属性的方式从.ui对象中提取即可。当然了不能盲目的提取,这些属性的名字其实就是在.ui文件中的空间的Object name,如下图
(4)点击登录按钮后槽函数的完善
这里完善一下上述的案例
"""
动态加载ui文件
"""
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.ui = None
self.user_name = None
self.password_qwidget = None
self.login_btn = None
self.forget_btn = None
self.text_browser = None
self.init_ui()
def init_ui(self):
self.ui = uic.loadUi("D:\\Qt\\QtData\\PyQt\\PyQtLesson\\Qt Designer\\login_test.ui")
# 提取要操作的控件
self.user_name = self.ui.lineEdit # 用户名输入框
self.password_qwidget = self.ui.lineEdit_2 # 密码输入框
self.login_btn = self.ui.pushButton # 登录按钮
self.forget_btn = self.ui.pushButton_2 # 忘记密码按钮
self.text_browser = self.ui.textBrowser # 文本显示区域
# 给登录按钮被点击绑定槽函数
self.login_btn.clicked.connect(self.login)
def login(self):
"""登录按钮的槽函数"""
user_name = self.user_name.text()
password = self.password_qwidget.text()
if user_name == "admin" and password == "123456":
self.text_browser.setText("欢迎%s" % user_name)
self.text_browser.repaint()
else:
self.text_browser.setText("用户名或密码错误...请重试")
self.text_browser.repaint()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.ui.show()
app.exec_()
这里增加了一个条件判断登录逻辑
展示过程如下
(5)PyQt引入多线程
<1>引入:结合(4)中的案例,加入三行代码
重新运行效果如下
运行过程中,可以很明显的看到,程序是卡顿的
原因如下:
只要是带界面的程序,一般来说程序运行后会用当前线程进行事件的检查、按钮等图形界面的更新操作,如果在执行某个逻辑代码(例如登录)时耗时非常验证,此时就会出现界面卡顿
解决办法如下:
我们一般将界面的显示用主线程来操作,逻辑功能代码或者耗时操作的代码都用另外线程进行处理
这也就是为什么要研究PyQt中的多线程了,因为它能实现多任务,让界面用一个线程更新,让逻辑代码在另外一个线程中,互不影响
<2>PyQt使用多线程
1.使用QT Designer设计如下效果ui文件
2.整体代码如下
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("D:\\Qt\\QtData\\PyQt\\PyQtLesson\\Qt Designer\\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):
self.my_thread = MyThread() # 创建线程
self.my_thread.start() # 开始线程
if __name__ == "__main__":
app = QApplication(sys.argv)
myshow = MyWin()
myshow.ui.show()
app.exec()
3.运行如下
可以看到,单线程的时候,是无法做到同时输入的
只有在线程执行结束后,输入的内容才会显示出来
而多线程情况下,可以同时输入内容
4.关键代码分析
这里的创建线程加self的原因分析
如下图所示,虽然代码中没有调用del,但是def click_2(self):结束后会直接删掉my_thread
这时候引用技术编程0但是线程还活着,程序就不会正常运行
(6)PyQt多线程案例
这里提供了一个案例巩固上述多线程的知识点
该代码和上述代码基本相同,这里不多做介绍
<1>整体代码
import json
import sys
import time
from PyQt5 import uic
from PyQt5.Qt import QApplication, QWidget, QThread
from PyQt5.QtCore import pyqtSignal
class LoginThread(QThread):
# 创建自定义信号
start_login_signal = pyqtSignal(str)
def __init__(self):
super().__init__()
def login_by_requests(self, user_password_json):
# 将json字符串,转换为自定,从而实现传递了用户名以及密码
user_password_json = json.loads(user_password_json)
print(user_password_json.get("user_name"))
print(user_password_json.get("password"))
def run(self):
# 通过whileTrue的方式让子线程一直运行,而不是结束
# 通过这种方式,我们让子线程一直活着,从而有能力接收来自主线程 (UI线程)的任务
while True:
print("子线程正在执行....")
time.sleep(1)
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.ui = None
self.user_name_qwidget = None
self.password_qwidget = None
self.login_btn = None
self.forget_password_btn = None
self.textBrowser = None
self.login_thread = None
self.init_ui()
def init_ui(self):
self.ui = uic.loadUi("D:\\Qt\\QtData\\PyQt\\PyQtLesson\\Qt Designer\\login_test.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)
# 创建一个子线程(注意这里要将Login_thread变量变为对象的属性,如果不是对象属性,而是一个普通的局部变量的话
# 会随着init_ui函数执行结束而被释放此时子线程还没有执行完毕所有会产生问题)
self.login_thread = LoginThread()
# 将要创建的子线程类中的信号进行绑定
self.login_thread.start_login_signal.connect(self.login_thread.login_by_requests)
# 让子线程开始巩工作
self.login_thread.start()
def login(self):
"""登录按钮的槽函数"""
user_name = self.user_name_qwidget.text()
password = self.password_qwidget.text()
# 发送信号,让子线程开始登录
self.login_thread.start_login_signal.emit(json.dumps({"user_name": user_name, "password": password}))
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.ui.show()
app.exec_()
<2>代码运行结果
(7)PyQt链接云函数
<1> 云函数的修改
在(十二)节中,已经介绍了云函数
为了在本小节介绍PyQt链接云函数,这里对之前的云函数做一下修改如下
<2> 本地整体代码
import json
import sys
import time
import requests
from PyQt5 import uic
from PyQt5.Qt import QApplication, QWidget, QThread
from PyQt5.QtCore import pyqtSignal
class LoginThread(QThread):
# 创建自定义信号
start_login_signal = pyqtSignal(str)
def __init__(self, signal):
super().__init__()
self.login_complete_signal = signal
def login_by_requests(self, user_password_json):
# 将json字符串,转换为自定,从而实现传递了用户名以及密码
user_password_json = json.loads(user_password_json)
print(user_password_json.get("user_name"))
print(user_password_json.get("password"))
# 使用requests模块发送请求(POST)
r = requests.post(url = "https://service-ed6mmhrc-1318499709.nj.apigw.tencentcs.com/release/test"
, json = user_password_json())
print("收到腾讯服务器的相应:", r.content.decode())
ret = r.json()
print("这里要发送信号给UI线程.....")
self.login_complete_signal.emit(json.dumps(ret))
def run(self):
# 通过whileTrue的方式让子线程一直运行,而不是结束
# 通过这种方式,我们让子线程一直活着,从而有能力接收来自主线程 (UI线程)的任务
while True:
print("子线程正在执行....")
time.sleep(1)
class MyWindow(QWidget):
# 创建定义信号
login_status_signal = pyqtSignal(str)
def __init__(self):
super().__init__()
self.ui = None
self.user_name_qwidget = None
self.password_qwidget = None
self.login_btn = None
self.forget_password_btn = None
self.textBrowser = None
self.login_thread = None
self.init_ui()
def init_ui(self):
self.ui = uic.loadUi("D:\\Qt\\QtData\\PyQt\\PyQtLesson\\Qt Designer\\login_test.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)
# 创建一个信号,用让子线程登录成功之后向主线程发送
self.login_status_signal.connect(self.login_status)
# 创建一个子线程(注意这里要将Login_thread变量变为对象的属性,如果不是对象属性,而是一个普通的局部变量的话
# 会随着init_ui函数执行结束而被释放此时子线程还没有执行完毕所有会产生问题)
self.login_thread = LoginThread(self.login_status_signal)
# 将要创建的子线程类中的信号进行绑定
self.login_thread.start_login_signal.connect(self.login_thread.login_by_requests)
# 让子线程开始巩工作
self.login_thread.start()
def login(self):
"""登录按钮的槽函数"""
user_name = self.user_name_qwidget.text()
password = self.password_qwidget.text()
# 发送信号,让子线程开始登录
self.login_thread.start_login_signal.emit(json.dumps({"user_name": user_name, "password": password}))
def login_status(self, status):
print("status.....", status)
status_dict = json.loads(status)
self.textBrowser.setText(status_dict.get("errmsg"))
self.textBrowser.repaint()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.ui.show()
app.exec_()
<3> 重要代码解析
本段代码中最重要的是使用requests模块向网站发送请求
<4> 运行结果
可以从运行结果中看出来,已经 收到了腾讯服务器的相应病输出了登录的信息
由于电脑的性能不够,在运行代码的时候报了如下提示,经过查询是正常的
到此,PyQt的基础上手教程到此完整的过了一遍