PyQt5 高级界面控制(多线程、网页交互、调用JavaScript)

文章目录

    • 1. 多线程
      • 1.1 QTimer
      • 1.2 QThread
        • 界面卡住例子
        • 分离UI和工作线程
      • 1.3 事件处理
    • 2. 网页交互
        • 显示本地 html
        • 显示 html 代码
        • 调用 JavaScript
        • JavaScript 调用 PyQt代码

learn from 《PyQt5 快速开发与实战》
https://doc.qt.io/qtforpython/index.html
https://www.riverbankcomputing.com/static/Docs/PyQt5

1. 多线程

1.1 QTimer

  • 周期性的发出timeout信号
# _*_ coding: utf-8 _*_
# @Time : 2022/5/29 23:42
# @Author : Michael
# @File : qtimer_demo.py
# @desc :from PyQt5.QtCore import QTimer, QDateTime
from PyQt5.QtWidgets import QWidget, QListWidget, QLabel, QPushButton, QGridLayout, QApplicationclass QtimerDemo(QWidget):def __init__(self):super(QtimerDemo, self).__init__()self.setWindowTitle("QTimer Demo")self.listFile = QListWidget()self.label = QLabel('显示当前时间')self.startBtn = QPushButton('开始')self.stopBtn = QPushButton('停止')layout = QGridLayout()self.timer = QTimer()self.timer.timeout.connect(self.showTime)layout.addWidget(self.label, 0, 0, 1, 2)layout.addWidget(self.startBtn, 1, 0, 1, 2)layout.addWidget(self.stopBtn, 2, 0, 1, 2)self.startBtn.clicked.connect(self.startTimer)self.stopBtn.clicked.connect(self.stopTimer)self.setLayout(layout)def startTimer(self):self.timer.start(1000) # 每隔1秒触发一次self.startBtn.setEnabled(False)self.stopBtn.setEnabled(True)def stopTimer(self):self.timer.stop()self.startBtn.setEnabled(True)self.stopBtn.setEnabled(False)def showTime(self):time = QDateTime().currentDateTime()timedisplay = time.toString('yyyy-MM-dd hh:mm:ss')self.label.setText(timedisplay)
if __name__ == '__main__':import sysapp = QApplication(sys.argv)win = QtimerDemo()win.show()sys.exit(app.exec_())

在这里插入图片描述

一次性定时器

# _*_ coding: utf-8 _*_
# @Time : 2022/5/29 23:56
# @Author : Michael
# @File : qtimer_demo2.py
# @desc :
import sysfrom PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QApplication, QLabelif __name__ == '__main__':app = QApplication(sys.argv)label = QLabel('<font color=red size=40>Hello World, 3秒后会消失</font>')label.setWindowFlags(Qt.SplashScreen | Qt.FramelessWindowHint) # 无边框窗口label.show()QTimer.singleShot(3000, app.quit) # 一次性定时器,可模仿程序启动画面sys.exit(app.exec_())

在这里插入图片描述

1.2 QThread

创建QThread 的子类,覆写 QThread.run(),调用 线程的start() 函数后,会自动调用 run()

# _*_ coding: utf-8 _*_
# @Time : 2022/5/30 0:14
# @Author : Michael
# @File : qthread1.py
# @desc :
# -*- coding: utf-8 -*-import sysfrom PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QListWidget, QPushButton, QGridLayout, QApplicationclass MainWidget(QWidget):def __init__(self, parent=None):super(MainWidget, self).__init__(parent)self.setWindowTitle("QThread 例子")self.thread = Worker()self.listFile = QListWidget()self.btnStart = QPushButton('开始')layout = QGridLayout(self)layout.addWidget(self.listFile, 0, 0, 1, 2)layout.addWidget(self.btnStart, 1, 1)self.btnStart.clicked.connect(self.slotStart)self.thread.sinOut.connect(self.slotAdd)def slotAdd(self, file_inf):self.listFile.addItem(file_inf)def slotStart(self):self.btnStart.setEnabled(False)self.thread.start()class Worker(QThread):sinOut = pyqtSignal(str)def __init__(self, parent=None):super(Worker, self).__init__(parent)self.working = Trueself.num = 0def __del__(self):self.working = Falseself.wait()def run(self):while self.working:file_str = 'File index {0}'.format(self.num)self.num += 1# 发出信号self.sinOut.emit(file_str)# 线程休眠2秒self.sleep(2)if __name__ == "__main__":app = QApplication(sys.argv)demo = MainWidget()demo.show()sys.exit(app.exec_())

在这里插入图片描述

界面卡住例子

# _*_ coding: utf-8 _*_
# @Time : 2022/5/30 0:25
# @Author : Michael
# @File : thread_stuck.py
# @desc :
import sysfrom PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLCDNumber, QPushButtonglobal sec
sec = 0def setTime():global secsec += 1# LED显示数字+1lcdNumber.display(sec)def work():# 计时器每秒计数timer.start(1000)for i in range(2000000000):passtimer.stop()if __name__ == "__main__":app = QApplication(sys.argv)win = QWidget()win.resize(300, 120)# 垂直布局类QVBoxLayoutlayout = QVBoxLayout(win)# 加个显示屏lcdNumber = QLCDNumber()layout.addWidget(lcdNumber)button = QPushButton("测试")layout.addWidget(button)timer = QTimer()# 每次计时结束,触发setTimetimer.timeout.connect(setTime)button.clicked.connect(work)win.show()sys.exit(app.exec_())

模拟下载,并计时
在这里插入图片描述
可以看到程序卡住了,计时器也没有走起来

PyQt 中所有的窗口都是在 UI 主线程中,这个线程中执行耗时的操作会阻塞 UI 线程,耗时的操作需要 开启新的线程 去执行

分离UI和工作线程

# _*_ coding: utf-8 _*_
# @Time : 2022/5/30 0:37
# @Author : Michael
# @File : threadsplit_ui_work.py
# @desc :
import sysfrom PyQt5.QtCore import QTimer, QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLCDNumber, QPushButtonglobal sec
sec = 0class WorkThread(QThread):trigger = pyqtSignal()def __int__(self):super(WorkThread, self).__init__()def run(self):for i in range(2000000000):pass# 循环完毕后发出信号self.trigger.emit()def countTime():global secsec += 1# LED显示数字+1lcdNumber.display(sec)def work():# 计时器每秒计数timer.start(1000)# 计时开始workThread.start()# 当获得循环完毕的信号时,停止计数workThread.trigger.connect(timeStop)def timeStop():timer.stop()print("运行结束用时", lcdNumber.value())global secsec = 0if __name__ == "__main__":app = QApplication(sys.argv)win = QWidget()win.resize(300, 120)# 垂直布局类QVBoxLayoutlayout = QVBoxLayout(win)# 加个显示屏lcdNumber = QLCDNumber()layout.addWidget(lcdNumber)button = QPushButton("测试")layout.addWidget(button)timer = QTimer()workThread = WorkThread()button.clicked.connect(work)# 每次计时结束,触发 countTimetimer.timeout.connect(countTime)win.show()sys.exit(app.exec_())

在这里插入图片描述

1.3 事件处理

  • 可以使用 QApplication.processEvents() 刷新页面,给人感觉不卡顿

上面卡住的例子中添加一句就可以不卡了

def work():# 计时器每秒计数timer.start(1000)for i in range(2000000000):QApplication.processEvents() # 添加这句刷新页面passtimer.stop()

2. 网页交互

pyqt5 使用 QWebEngineView 控件来展示 HTML ,其使用的 Chromium 内核

# _*_ coding: utf-8 _*_
# @Time : 2022/5/30 0:53
# @Author : Michael
# @File : web_load.py
# @desc :
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QMainWindow, QApplicationclass MainWin(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("load url")self.setGeometry(300, 300, 1000, 600)self.browser = QWebEngineView()self.browser.load(QUrl("https://michael.blog.csdn.net/"))self.setCentralWidget(self.browser)if __name__ == '__main__':import sysapp = QApplication(sys.argv)win = MainWin()win.show()sys.exit(app.exec_())

在这里插入图片描述

显示本地 html

url = QUrl("D:/gitcode/Python_learning/qt/ch5/index.html")
self.browser.load(url)

在这里插入图片描述

显示 html 代码

html = """<!DOCTYPE html><html><head><meta charset="UTF-8"><title></title></head><body><h1>Hello michael</h1><h1>Hello PyQt5 from setHtml</h1></body></html>"""
self.browser.setHtml(html)

调用 JavaScript

# _*_ coding: utf-8 _*_
# @Time : 2022/5/31 23:44
# @Author : Michael
# @File : webjs01.py
# @desc :
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt5.QtWebEngineWidgets import QWebEngineView
import sys# 创建一个 application实例
app = QApplication(sys.argv)
win = QWidget()
win.setWindowTitle('Web页面中的JavaScript与 QWebEngineView交互例子')# 创建一个垂直布局器
layout = QVBoxLayout()
win.setLayout(layout)# 创建一个 QWebEngineView 对象
view = QWebEngineView()
view.setHtml('''<html><head><title>A Demo Page</title><script language="javascript">// Completes the full-name control and// shows the submit buttonfunction completeAndReturnName() {var fname = document.getElementById('fname').value;var lname = document.getElementById('lname').value;var full = fname + ' ' + lname;document.getElementById('fullname').value = full;document.getElementById('submit-btn').style.display = 'block';return full;}</script></head><body><form><label for="fname">First name:</label><input type="text" name="fname" id="fname"></input><br /><label for="lname">Last name:</label><input type="text" name="lname" id="lname"></input><br /><label for="fullname">Full name:</label><input disabled type="text" name="fullname" id="fullname"></input><br /><input style="display: none;" type="submit" id="submit-btn"></input></form></body></html>
''')# 创建一个按钮去调用 JavaScript代码
button = QPushButton('设置全名')def js_callback(result):print(result)def complete_name():view.page().runJavaScript('completeAndReturnName();', js_callback)# QWebEngineView 对象的 page()方法返回一个 QWebEnginePage 对象# QWebEnginePage 对象的 异步 runJavaScript()方法可以执行 JavaScript代码# 需要回调函数来处理结果# 按钮连接 'complete_name'槽,当点击按钮是会触发信号
button.clicked.connect(complete_name)# 把QWebView和button加载到layout布局中
layout.addWidget(view)
layout.addWidget(button)# 显示窗口和运行app
win.show()
sys.exit(app.exec_())

在这里插入图片描述

JavaScript 调用 PyQt代码

  • PyQt 可以与加载的 Web 页面进行双向的数据交互
from PyQt5.QtCore import pyqtPropertyclass MySharedObject(QWidget):def __init__(self):super(MySharedObject, self).__init__()def _getStrValue(self):#return '100'def _setStrValue(self, str):#print('获得页面参数 :%s' % str)QMessageBox.information(self, "Information", '获得页面参数 :%s' % str)# 需要定义对外暴露的方法strValue = pyqtProperty(str, fget=_getStrValue, fset=_setStrValue)
  • 首先,使用QWebEngineView对象加载 Web页面后,就可以获得页面中表单输入数据,在 Web 页面中通过 JavaScript 代码收集用户提交的数据
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWebChannel import QWebChannelchannel = QWebChannel()
myObj = MySharedObject()
channel.registerObject("bridge", myObj)
view.page().setWebChannel(channel)
  • 然后,在 Web 页面中,JavaScript 通过桥连接方式传递数据给PyQt
  • 最后,PyQt 接收到页面传递的数据,经过业务处理后,还可以把处理过的数据返给Web页面

html 需要引入 <script src="qwebchannel.js"></script>

<html>
<head><title>A Demo Page</title><meta charset="UTF-8"><script src="qwebchannel.js"></script><script>document.addEventListener("DOMContentLoaded", function () {new QWebChannel(qt.webChannelTransport, function (channel) {window.bridge = channel.objects.bridge;alert('bridge=' + bridge + '\n从pyqt传来的参数=' + window.bridge.strValue);});});function onShowMsgBox() {if (window.bridge) {var fname = document.getElementById('fname').value;window.bridge.strValue = fname;}}</script>
</head><body>
<form><label for="姓名">user name:</label><input type="text" name="fname" id="fname"></input><br/><input type="button" value="传递参数到pyqt" onclick="onShowMsgBox()"><input type="reset" value='重置'/>
</form>
</body>
</html>

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/470968.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读写Excel 用 xlsxwriter,openpyxl 更灵活

一、xlsxwriter的使用&#xff1a; # import xlwt # # workbook xlwt.Workbook() # sheet0 workbook.add_sheet(sheet0) # for i in range(0,300): # sheet0.write(0,i,i) # workbook.save(number.xls)# 以上代码运行会报错&#xff0c;因为xlwt不支持超过256列的表格im…

LeetCode 2293. 极大极小游戏

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 nums &#xff0c;其长度是 2 的幂。 对 nums 执行下述算法&#xff1a; 设 n 等于 nums 的长度&#xff0c;如果 n 1 &#xff0c;终止 算法过程。否则&#xff0c;创建 一个新的整数数组 newNums &#x…

LeetCode 2294. 划分数组使最大差为 K

文章目录1. 题目2. 解题1. 题目 给你一个整数数组 nums 和一个整数 k 。你可以将 nums 划分成一个或多个 子序列 &#xff0c;使 nums 中的每个元素都 恰好 出现在一个子序列中。 在满足每个子序列中最大值和最小值之间的差值最多为 k 的前提下&#xff0c;返回需要划分的 最…

LeetCode 2295. 替换数组中的元素

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的数组 nums &#xff0c;它包含 n 个 互不相同 的正整数。请你对这个数组执行 m 个操作&#xff0c;在第 i 个操作中&#xff0c;你需要将数字 operations[i][0] 替换成 operations[i][1] 。 题目保证在第 i 个操作中&a…

LeetCode 2296. 设计一个文本编辑器(双栈)

文章目录1. 题目2. 解题1. 题目 请你设计一个带光标的文本编辑器&#xff0c;它可以实现以下功能&#xff1a; 添加&#xff1a;在光标所在处添加文本。删除&#xff1a;在光标所在处删除文本&#xff08;模拟键盘的删除键&#xff09;。移动&#xff1a;将光标往左或者往右移…

五、scrapy爬虫框架——logging 模块的使用

logging 模块的使用 1、scrapy settings中设置LOG_LEVEL“WARNING”settings中设置LOG_FILE"./a.log"#设置日志保存的位置&#xff0c;设置会后终端不会显示日志内容import logging,实例化logger的方式在任何文件中使用logger输出内容 2、普通项目中 import logg…

PyQt5 布局管理(水平、垂直、网格、表单、嵌套、QSplitter)

文章目录1. 布局管理2. 使用绝对位置布局3. QBoxLayoutaddStretch() 添加可伸缩控件4. QGridLayout5. QFormLayout6. 嵌套布局7. QSplitter 布局learn from 《PyQt5 快速开发与实战》 https://doc.qt.io/qtforpython/index.html https://www.riverbankcomputing.com/static/Doc…

一、Java 面向对象高级——Object类、常用API

day01【Object类、常用API】 主要内容 Object类Date类DateFormat类Calendar类System类StringBuilder类包装类 教学目标 -[ ] 能够说出Object类的特点 -[ ] 能够重写Object类的toString方法 -[ ] 能够重写Object类的equals方法 -[ ] 能够使用日期类输出当前日期 -[ ] 能够使…

FineUI(专业版)v3.0.0 发布,手机、平板和桌面全支持!

FineUI&#xff08;专业版&#xff09;v3.0.0 已经正式发布&#xff0c;全面支持手机、平板和桌面&#xff01;自 2008 年 4 月发布第一个版本&#xff0c;我们持续更新了 126 个版本&#xff0c;拥有 16000 多位注册用户&#xff0c;1300 多位捐赠会员&#xff0c;200 多位网友…

二、Java 面向对象高级——Collection、泛型

day02【Collection、泛型】 主要内容 Collection集合迭代器增强for泛型 教学目标 能够说出集合与数组的区别 说出Collection集合的常用功能 能够使用迭代器对集合进行取元素 能够说出集合的使用细节 能够使用集合存储自定义类型 能够使用foreach循环遍历集合 能够使用泛型定…

LeetCode 2299. 强密码检验器 II

文章目录1. 题目2. 解题1. 题目 如果一个密码满足以下所有条件&#xff0c;我们称它是一个 强 密码&#xff1a; 它有至少 8 个字符。至少包含 一个小写英文 字母。至少包含 一个大写英文 字母。至少包含 一个数字 。至少包含 一个特殊字符 。特殊字符为&#xff1a;"!#…

LeetCode 2300. 咒语和药水的成功对数(二分查找)

文章目录1. 题目2. 解题1. 题目 给你两个正整数数组 spells 和 potions &#xff0c;长度分别为 n 和 m &#xff0c;其中 spells[i] 表示第 i 个咒语的能量强度&#xff0c;potions[j] 表示第 j 瓶药水的能量强度。 同时给你一个整数 success 。一个咒语和药水的能量强度 相…

三、Java 面向对象高级——数据结构、List、Set、Collection

day03 【List、Set、数据结构、Collections】 主要内容 数据结构List集合Set集合Collections 教学目标 能够说出List集合特点 能够说出常见的数据结构 能够说出数组结构特点 能够说出栈结构特点 能够说出队列结构特点 能够说出单向链表结构特点 能够说出Set集合的特点 能够说…

Centos Cacti 0.8.8g

Centos Cacti 0.8.8g 一、Cacti简介1. cacti是用php语言实现的一个软件&#xff0c;它的主要功能是用snmp服务获取数据&#xff0c;然后用rrdtool储存和更新数据&#xff0c;当用户需要查看数据的时候用rrdtool生成图表呈现给用户。因此snmp和rrdtool是cacti的关键。Snmp关系着…

LeetCode 2301. 替换字符后匹配(字典)

文章目录1. 题目2. 解题1. 题目 给你两个字符串 s 和 sub 。同时给你一个二维字符数组 mappings &#xff0c;其中 mappings[i] [oldi, newi] 表示你可以替换 sub 中任意数目的 oldi 字符&#xff0c;替换成 newi 。sub 中每个字符 不能 被替换超过一次。 如果使用 mappings…

一、Web服务器——Tomcat Servlet学习笔记

今日内容 web相关概念回顾web服务器软件&#xff1a;TomcatServlet入门学习 一、web相关概念回顾 软件架构 C/S&#xff1a;客户端/服务器端B/S&#xff1a;浏览器/服务器端 资源分类 静态资源&#xff1a;所有用户访问后&#xff0c;得到的结果都是一样的&#xff0c;称为静态…

LeetCode 2302. 统计得分小于 K 的子数组数目(前缀和+二分查找)

文章目录1. 题目2. 解题1. 题目 一个数组的 分数 定义为数组之和 乘以 数组的长度。 比方说&#xff0c;[1, 2, 3, 4, 5] 的分数为 (1 2 3 4 5) * 5 75 。 给你一个正整数数组 nums 和一个整数 k &#xff0c;请你返回 nums 中分数 严格小于 k 的 非空整数子数组数目。 …

LeetCode 2303. 计算应缴税款总额

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的二维整数数组 brackets &#xff0c;其中 brackets[i] [upperi, percenti] &#xff0c;表示第 i 个税级的上限是 upperi &#xff0c;征收的税率为 percenti 。税级按上限 从低到高排序&#xff08;在满足 0 < i &…

一、Java Web——JDBC快速入门(详解)

今日内容 1. JDBC基本概念 2. 快速入门 3. 对JDBC中各个接口和类详解JDBC&#xff1a; 概念&#xff1a;Java DataBase Connectivity Java 数据库连接&#xff0c; Java语言操作数据库 * JDBC本质&#xff1a;其实是官方&#xff08;sun公司&#xff09;定义的一套操作所有关系…

LeetCode 2304. 网格中的最小路径代价(动态规划)

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数矩阵 grid &#xff0c;矩阵大小为 m x n &#xff0c;由从 0 到 m * n - 1 的不同整数组成。 你可以在此矩阵中&#xff0c;从一个单元格移动到 下一行 的任何其他单元格。如果你位于单元格 (x, y) &#xff0c;且…