SEGV_MAPERR для объекта PyQt5

1

Почему следующий демонстрационный код создает 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.

Теги:
pyqt5
pyqt
segmentation-fault
qobject

1 ответ

0
Лучший ответ

Проблема в том, что 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_())

Ещё вопросы

Сообщество Overcoder
Наверх
Меню