Почему следующий демонстрационный код создает SEGV_MAPERR? Как можно это исправить?
Подсказка: после удаления строки с пометкой "# Ref1" ошибки не выдается. Это нелегко сделать в рабочем коде, от которого абстрагируется проблема.
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebChannel
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.webView = QtWebEngineWidgets.QWebEngineView(self.centralwidget)
self.webView.setHtml("")
self.gridLayout.addWidget(self.webView, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
page = self.webView.page() # REF1
for i in range(2):
self.init_page()
def init_page(self):
class EditObject(QtCore.QObject):
@QtCore.pyqtSlot(str)
def edit(self, s):
print("test")
editObject = EditObject(self.webView.page())
poChannel = self.webView.page().webChannel()
print(1)
if poChannel is None:
poChannel = QtWebChannel.QWebChannel()
self.webView.page().setWebChannel(poChannel)
print(2)
objects = poChannel.registeredObjects()
print(objects)
poChannel.registerObject("editObject", editObject)
self.webView.setHtml("")
from PyQt5 import QtWebEngineWidgets
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Это похоже на Проблемы с PyQt5 == 5.10 в Ubuntu 18, но с примером кода. Для примера кода адаптирован https://gist.github.com/gioditalia/03c9fd5d793aeccbe065fea45d842431.
Проблема в том, что poChannel
- это локальная переменная, которая будет удалена после выполнения init_page, поэтому во второй итерации ссылка на poChannel
будет указывать на неправильный адрес памяти. Таким образом, решение состоит в том, чтобы расширить его цикл до цикла представления, поэтому мы используем свойство Qt и передаем его в качестве родителя для self.webView
.
poChannel = QtWebChannel.QWebChannel(self.webView)
Хотя, как указывает PyQt в документации и сгенерированном файле: # WARNING! All changes made in this file will be lost!
# WARNING! All changes made in this file will be lost!
, не удобно модифицировать класс, сгенерированный .ui, вместо этого вы должны создать другой класс, который наследует от соответствующего виджета и использовать интерфейс, предоставленный Qt Designer.
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets, QtWebChannel
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.webView = QtWebEngineWidgets.QWebEngineView(self.centralwidget)
self.gridLayout.addWidget(self.webView, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
class EditObject(QtCore.QObject):
@QtCore.pyqtSlot(str)
def edit(self, s):
print("test")
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
for i in range(2):
self.init_page()
def init_page(self):
editObject = EditObject(self.webView.page())
poChannel = self.webView.page().webChannel()
if poChannel is None:
poChannel = QtWebChannel.QWebChannel(self)
self.webView.page().setWebChannel(poChannel)
objects = poChannel.registeredObjects()
poChannel.registerObject("editObject", editObject)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())