版本信息
PyQt6:6.6.1
pyqt6-tools:6.4.2.3.3
PyQt6-WebEngine:6.6.0
pyqt6 官方文档:Reference Guide — PyQt Documentation v6.6.0
1. 知识点:信号与槽函数
在 PyQt 中,信号signal和槽slot是用来处理事件的机制。
信号是一个对象,当它被发射时,会通知所有连接的槽。槽是一个函数,当信号被发射时,它会被调用。
PyQt中常见控件及其对应的信号举例:
QPushButton:clicked()
QCheckBox:stateChanged()
QLineEdit:textChanged()
QSlider:valueChanged()
QTableView:doubleClicked()
(1) 信号只能在QObject的子类中定义,使用pyqtSignal函数可以创建未绑定的信号作为类的属性,信号可以传递多个参数,且可以指定参数类型(标准的python数据类型)。
(2) 与信号关联的槽函数可以实现当信号发射时,做什么事情。信号与槽函数通过connet连接;
(3) 使用emit可以发射信号,触发与信号关联的槽函数。
(4) 定义信号时要注意代码位置,不能在初始化中定义信号,否则会遇到报错PyQt5.QtCore.pyqtSignal‘ object has no attribute ‘connect‘,信号应作为类属性而不是实例属性。
错误示范
class MyObject(QObject):
def __init__(self):
super().__init__()
# 定义信号位置错误!!!
self.show_infoes_signal = pyqtSignal(str)
正确示范
class MyObject(QObject):
show_infoes_signal = pyqtSignal(str)
def __init__(self):
super().__init__()
更多信息参考下方链接
自定义信号signal和槽slot时报错‘PyQt5.QtCore.pyqtSignal‘ object has no attribute ‘connect‘解决方案_pyqt5.qtcore.pyqtsignal' object has no attribute '-CSDN博客
2. 将鼠标点击图上某点时所显示的提示框信息输出到界面PlainTextEdit
1 获取鼠标点击网页元素时,提示框的信息
首先看一下Pyecharts生成的网页内容(右键检查->元素):
由上述信息可知,第一个div的内容即为提示框信息对应的文本内容,可以在HTML文件中增加以下脚本进行确认,结果符合预期。
<script>
document.addEventListener("mousemove", function() {
var web_info = document.getElementsByTagName("div")[0].innerText;
console.log(web_info)
})
</script>
控制台打印结果:
2 插曲(赶时间可跳过这段):mousePressEvent不能用于QWebEngineView对象
PyQt中,QWebEngineView对象可通过“对象名.page()”函数获得QWebEnginePage对象,QWebEnginePage类有一个runJavaScript方法,这个方法可以通过执行JS语句与页面交互,并可以通过回调函数接收执行结果,其语句如下:
QWebEnginePage.runJavaScript('JS语句', 回调函数)
因而,最初的想法是,通过mousePressEvent监控鼠标行为,当发生鼠标点击行为时,通过runJavaScript直接获取网页上所需变量的值,从而获得我想要的信息。然而尝试后发现,始终没有任何输出。
猜想mousePressEvent这部分有问题,通过如下代码验证:首先创建一个QMainWindow,其中有一个QWebEngineView控件,用于显示网页;然后重写mousePressEvent,如果识别到鼠标点击操作,就在控制台打印一个"yes",通过这种方式,看一下鼠标点击在界面不同位置的效果。运行代码后发现,鼠标点击在QWebEngineView控件内部时,控制台始终没有任何打印,因而上述思路不可行。
# 如下代码属于尝试阶段,可运行体验
from PyQt6.QtWidgets import QApplication, QMainWindow
import sys
import cdsn_show
from PyQt6.QtCore import QUrl, QFileInfo
class Ui_CDSN(cdsn_show.Ui_MainWindow, QMainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
url = QUrl("file:" + QFileInfo("cdsn_figure.html").absoluteFilePath())
self.widget_figure.load(url)
self.show()
def mousePressEvent(self, event):
print("yes")
if __name__ == '__main__':
app = QApplication(sys.argv)
my_ui = Ui_CDSN()
sys.exit(app.exec())
3 基于QWebChannel实现PyQt与HTML文件的交互
原理简述:QWebChannel是一种在Web页面和Python代码之间进行通信的机制。它的原理是通过JavaScript和Python之间的桥接,使得Web页面中的JavaScript代码可以调用Python中的代码,并且Python中的代码也可以调用Web页面中的JavaScript代码。
步骤一:下载qwebchannel.js文件
网址:https://github.com/qt/qtwebchannel/tree/dev/examples/webchannel/shared
步骤二:Python部分
(1) Ui界面文件<csdn_show.py>
界面主要包含一个qwebengineview控件widget_figure用于显示网页,一个plaintextedit控件用于显示信息。
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6 import QtWebEngineWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(994, 722)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.widget = QtWidgets.QWidget(parent=self.centralwidget)
self.widget.setGeometry(QtCore.QRect(40, 30, 921, 631))
self.widget.setObjectName("widget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.widget_figure = QtWebEngineWidgets.QWebEngineView(parent=self.widget)
self.widget_figure.setObjectName("widget_figure")
self.verticalLayout_2.addWidget(self.widget_figure)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(parent=self.widget)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
spacerItem = QtWidgets.QSpacerItem(20, 78, QtWidgets.QSizePolicy.Policy.Minimum,
QtWidgets.QSizePolicy.Policy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout.addLayout(self.verticalLayout)
self.plainTextEdit = QtWidgets.QPlainTextEdit(parent=self.widget)
self.plainTextEdit.setObjectName("plainTextEdit")
self.horizontalLayout.addWidget(self.plainTextEdit)
self.verticalLayout_2.addLayout(self.horizontalLayout)
self.verticalLayout_2.setStretch(0, 8)
self.verticalLayout_2.setStretch(1, 3)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 994, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "提示信息"))
(2) Pycharts生成的HTML图
不做展开,请自行准备,参考Pyqt6与Pyecharts交互 -- 持续更新_pyside6 pyqt6 pyecharts-CSDN博客
(3) 程序运行文件<csdn_main.py>
说明:InteractObject部分
1. 创建一个QObject子类,后续会将其注册到QWebChannel对象中(必须是QObject子类)。
2. 定义了一个名为receive_message的槽函数,该槽函数将打印并返回传递给它的数据。
说明:Ui_CSDN部分
1. 创建了一个QWebChannel对象,并将其绑定到QWebEngineView对象上,以便在HTML页面和Python代码之间传递数据。
2. 创建了一个InteractObject对象self.obj,并将这个对象注册到WebChannel中,注册名为interact_object,HTML页面可以通过WebChannel对象调用InteractObject对象的方法和属性,借此传递页面消息给PyQt或获取来自PyQt的信息。
3. 将自定义信号self.obj.mySignal与自定义槽函数updata_plain_text_edit连接起来,以便将接收到的信息显示在PyQt界面上。
import sys
import csdn_show
from PyQt6.QtWebChannel import QWebChannel
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtCore import QUrl, QFileInfo, pyqtSlot, QObject, pyqtSignal
class InteractObject(QObject):
mySignal = pyqtSignal(str)
def __init__(self):
super().__init__()
@pyqtSlot(str, result=str)
def receive_message(self, message):
if isinstance(message, str):
print(f"Received message from html:\n{message}")
self.mySignal.emit(message)
return message
else:
print("no message")
return "no message"
class Ui_CSDN(cdsn_show.Ui_MainWindow, QMainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.channel = QWebChannel()
self.widget_figure.page().setWebChannel(self.channel)
self.obj = InteractObject()
self.channel.registerObject("interact_object", self.obj)
url = QUrl("file:" + QFileInfo("cdsn_figure.html").absoluteFilePath())
self.widget_figure.load(url)
self.show()
self.obj.mySignal.connect(self.updata_plain_text_edit)
@pyqtSlot(str)
def updata_plain_text_edit(self, message):
try:
self.plainTextEdit.setPlainText(message)
except Exception as e:
self.plainTextEdit.setPlainText('No Message')
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = Ui_CSDN()
app.exec()
步骤三:Javascript部分
1. 引入qwebchannel.js文件,文件路径请根据实际情况调整。
2. 实例化QWebChannel(QWebChannel在qwebchannel.js中定义,因而需要先引入.js文件),并在回调函数中,通过channel.objects.bridge获取来自PyQt的共享对象interact_object,代码中的interact_object即为第二步注册时使用的名字,务必与前面注册时一致。
3. 增加鼠标点击事件监听,当发生鼠标点击事件时,将页面值通过interact_object返回给PyQt。
<script type="text/javascript" src="D:/0_study_code/Sites3DFigDisplay/pyecharts-assets-master/assets/qwebchannel.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
//把对象赋值到JS中
var channel = new QWebChannel(window.qt.webChannelTransport, function(channel) {
// Get interact_object
window.interact_object = channel.objects.interact_object;
});
});
document.addEventListener("click", function() {
var web_info = document.getElementsByTagName("div")[0].innerText;
window.interact_object.receive_message(web_info);
})
</script>
pyecharts-html文件最终内容一览
QWebchannel部分研究了好久,感谢博主【天马小Q】的博文,让我豁然开朗,放在下面给大家参考。
参考链接:PyQt5 QWebEngineView中实现Python和JavaScript交互数据传递demo_pyqt5 qwebengineview js-CSDN博客
步骤四:编写函数,每次Pyecharts生成图像后,自动添加上述JS脚本
def add_content(filename):
s_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "pyecharts-assets-master",
"assets", "qwebchannel.js"))
html_js_path = str(js_path).replace("\\", r'/')
add_content = [
'\t\t<script type="text/javascript" ' + f'src="{html_js_path}"></script>\n',
'\t<script>\n',
'\t\tdocument.addEventListener("DOMContentLoaded", function() {\n',
'\t\t\tvar channel = new QWebChannel(window.qt.webChannelTransport, function(channel) {\n',
'\t\t\twindow.interact_object = channel.objects.interact_object;\n',
'\t\t\t});\n',
'\t\t});\n',
'\t\tdocument.addEventListener("click", function() {\n',
'\t\t\tvar web_info = document.getElementsByTagName("div")[0].innerText;\n',
'\t\t\twindow.interact_object.receive_message(web_info);\n',
'\t\t})\n',
'\t</script>\n']
with open(filename, 'r') as file:
html_content = file.readlines()
insert_index = 7
target_content = 'pyecharts-assets-master'
if target_content not in html_content[5]:
insert_index = -1
for i in range(len(html_content)):
if target_content in html_content[i]:
insert_index = i + 1
break
if insert_index == '-1':
print('无法确定内容插入位置')
return False
else:
print('可进行内容插入')
new_html_content = html_content[:insert_index] + add_content + html_content[insert_index:]
with open(filename, 'w') as file:
# 将修改后的HTML内容写回文件
file.writelines(new_html_content)
return True
3. 效果展示
当鼠标点击图上点时,提示框中的信息会同步显示在下方PlainTextEdit框中。
如果出现类似下图的报错,大概率是标黄的路径写的有问题,核对一下。
文章来源:https://www.toymoban.com/news/detail-858397.html
文章来源地址https://www.toymoban.com/news/detail-858397.html
到了这里,关于PyQt6 与 Pyecharts 交互:将鼠标点击 html 页面某点时的提示框信息在 PyQt 界面显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!