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,一经查实,立即删除!

相关文章

[转]html超链接打开的窗口大小

<a href"#" onclick"javascript:window.open(http://www.baidu.com,,height20,width20,top0,left0,toolbarno,menubarno,scrollbarsno, resizableno,locationno, statusno)">aaaaaaaaaaaaaaa</a> 各项参数 其中yes/no也可使用1/0&#xff1b;p…

读写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…

devexpress gridcontrol 内置导航栏,双击后才修改数据

4、 使用Grid内置导航栏 gridControl1.UseEmbeddedNativgatorTrue 设定内置导航栏按钮其他属性 gridControl1.EmbeddedNavigator 5、 GridView内置方式编辑数据 禁止编辑数据 gridView1.OptionsBehavior.Editable False&#xff0c;默认是True 可编辑。 Gridview内置数据编辑器…

Python自动发送微信消息

一、用Python自动发送微信消息 import itchat# enableCmdQRTrue&#xff0c;允许在cmd命令行显示二维码 # hotReloadTrue&#xff0c;允许短期内可以不需要重复登陆 itchat.auto_login(enableCmdQRTrue,hotReloadTrue)# to_name itchat.search_friends(name"微信好友备注…

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

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

工作中用到的安卓日志相关命令(logcat)

1. 打印安卓日志&#xff0c;在cmd中使用adb shell logcat&#xff1b;在adb shell下直接打logcat2. 如果不想打印占用终端&#xff0c;则加个&号&#xff0c;即logcat &3. 如果想把前面的打印清掉&#xff0c;开始现在的打印&#xff0c;则用logcat -c;logcat4. 如果想…

三、scrapy爬虫框架——scrapy模拟登陆

scrapy模拟登陆 学习目标&#xff1a; 应用 请求对象cookies参数的使用了解 start_requests函数的作用应用 构造并发送post请求 1. 回顾之前的模拟登陆的方法 1.1 requests模块是如何实现模拟登陆的&#xff1f; 直接携带cookies请求页面找url地址&#xff0c;发送post请求…

LeetCode 2295. 替换数组中的元素

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

ssh对等性配置

目的: 让通过ssh在目标机器上执行命令和scp, 不必每次输入密码. 做法: 假设有机器A, 机器B 在A上执行, ssh-keygen, 一路使用默认值, 成功生成: 私钥id_rsa, 公钥id_rsa.pub 把A上生成的公钥id_rsa.pub的内容, 写入机器B的.ssh/authorized_keys文件中, 文件不存在则创建. cat i…

四、scrapy爬虫框架——scrapy管道的使用

scrapy管道的使用 学习目标&#xff1a; 掌握 scrapy管道(pipelines.py)的使用 之前我们在scrapy入门使用一节中学习了管道的基本使用&#xff0c;接下来我们深入的学习scrapy管道的使用 1. pipeline中常用的方法&#xff1a; process_item(self,item,spider): 管道类中必须…

SPOJ COT Count on a tree 主席树

题意&#xff1a; 给\(n(1 \leq n \leq 10^5)\)一棵树&#xff0c;每个点有个权值。 还有\(m(1 \leq m \leq 10^5)\)个询问&#xff1a;\(u \, v \, k\)&#xff0c;查询路径\(u \to v\)上权值第\(k\)小的权值。 分析&#xff1a; 和普通的区间一样&#xff0c;对于树维护到根节…

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…

CUBRID学习笔记 22 插入数据

CREATE TABLE auto_tbl(id INT AUTO_INCREMENT, name VARCHAR);自增长的列可以插入null, 同时一次可以插入多条记录.别的和其他的sql数据库语法基本一样 INSERT INTO auto_tbl VALUES (NULL, AAA); INSERT INTO auto_tbl (id, name) VALUES (NULL, AAA); INSERT INTO auto_tbl …

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;"!#…