根据此前的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 uicclass MyWindow(QWidget):def __init__(self):super().__init__()self.ui = Noneself.user_name = Noneself.password = Noneself.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 uicclass MyWindow(QWidget):def __init__(self):super().__init__()self.ui = Noneself.user_name = Noneself.password_qwidget = Noneself.login_btn = Noneself.forget_btn = Noneself.text_browser = Noneself.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 timefrom PyQt5 import uic
from PyQt5.Qt import QApplication, QWidget, QThreadclass 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.lineEditbtn1 = self.ui.pushButtonbtn2 = 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 timefrom PyQt5 import uic
from PyQt5.Qt import QApplication, QWidget, QThread
from PyQt5.QtCore import pyqtSignalclass 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 = Noneself.user_name_qwidget = Noneself.password_qwidget = Noneself.login_btn = Noneself.forget_password_btn = Noneself.textBrowser = Noneself.login_thread = Noneself.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 requestsfrom PyQt5 import uic
from PyQt5.Qt import QApplication, QWidget, QThread
from PyQt5.QtCore import pyqtSignalclass LoginThread(QThread):# 创建自定义信号start_login_signal = pyqtSignal(str)def __init__(self, signal):super().__init__()self.login_complete_signal = signaldef 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 = Noneself.user_name_qwidget = Noneself.password_qwidget = Noneself.login_btn = Noneself.forget_password_btn = Noneself.textBrowser = Noneself.login_thread = Noneself.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的基础上手教程到此完整的过了一遍