赞
踩
根据此前的PyQt学习,这里对PyQt的学习过程进行最后的总结
前文链接:由于前文标题名字取了一样的,以下内容按照前后顺序排列
(1)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
(2)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
(3)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
(4)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
(5)PyQt上手教程(一)_机械刘怀洋的博客-CSDN博客
下面是最后一点内容
后续案例要用到腾讯云函数,这里先了解一下
注册腾讯云后新建一个函数
测试函数默认先不用管
完成
创建一个触发器
创建后这里有个链接
直接访问链接,可以看到已经调用
腾讯云给人使用的免费额度是100万次
利用Qt Designer可以快速设计UI界面,比起直接写代码,效率要快速很多,下面记录一下Qt Designer使用过程
由于在Pycharm中直接配置了了PyQt5,PyQt5是自带Qt Designer工具的
所以直接在Anaconda工具包中搜索designer.exe,然后发送快捷方式到桌面
Qt Designer的快捷方式如下
双击designer.exe打开设计页面,新建空白页面
拖一些控件先做一个测试页面
直接crtl+s保存为ui文件
然后利用Python调用ui文件,Python代码以及显示功能如下
为了更好理解上述过程,这里做了一个案例巩固知识
如下图先做一个页面
这里把页面右下角的信号与槽拖出来
假设设计如下的信号与槽接收页面
当点击登录的时候,文本框就会关闭,预览效果如下,但是在设计页面设计信号与槽,功能很受限
- """
- 动态加载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_()
<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这个空壳界面
看看.ui文件有什么属性,如下图蓝色框,红色框是获取登录信息
在这里,我们看到加载后的.ui文件有7个对象属性,正好与在设计.ui文件时控件的数量一致,可见属性的个数正好对应.ui文件中的空间个数,所以想要操作哪个空间,就通过对象.属性的方式从.ui对象中提取即可。当然了不能盲目的提取,这些属性的名字其实就是在.ui文件中的空间的Object name,如下图
这里完善一下上述的案例
- """
- 动态加载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_()
这里增加了一个条件判断登录逻辑
展示过程如下
重新运行效果如下
运行过程中,可以很明显的看到,程序是卡顿的
原因如下:
只要是带界面的程序,一般来说程序运行后会用当前线程进行事件的检查、按钮等图形界面的更新操作,如果在执行某个逻辑代码(例如登录)时耗时非常验证,此时就会出现界面卡顿
解决办法如下:
我们一般将界面的显示用主线程来操作,逻辑功能代码或者耗时操作的代码都用另外线程进行处理
这也就是为什么要研究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但是线程还活着,程序就不会正常运行
这里提供了一个案例巩固上述多线程的知识点
该代码和上述代码基本相同,这里不多做介绍
- 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_()
在(十二)节中,已经介绍了云函数
为了在本小节介绍PyQt链接云函数,这里对之前的云函数做一下修改如下
- 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_()
本段代码中最重要的是使用requests模块向网站发送请求
可以从运行结果中看出来,已经 收到了腾讯服务器的相应病输出了登录的信息
由于电脑的性能不够,在运行代码的时候报了如下提示,经过查询是正常的
到此,PyQt的基础上手教程到此完整的过了一遍
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。