PyQt5 对象的 SEGV_MAPERR

Posted

技术标签:

【中文标题】PyQt5 对象的 SEGV_MAPERR【英文标题】:SEGV_MAPERR for PyQt5 object 【发布时间】:2019-01-08 23:29:43 【问题描述】:

为什么下面的演示代码会生成 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_())

这类似于Issues with PyQt5==5.10 on Ubuntu 18,但带有示例代码。对于示例代码,https://gist.github.com/gioditalia/03c9fd5d793aeccbe065fea45d842431 进行了改编。

【问题讨论】:

【参考方案1】:

问题是poChannel是一个局部变量,在执行init_page后会被删除,所以在第二次迭代中poChannel引用会指向一个错误的内存地址。所以解决方案是将其循环扩展到视图的循环,因此我们利用 Qt 属性并将其作为父级传递给self.webView

poChannel = QtWebChannel.QWebChannel(self.webView)

虽然 PyQt 在the docs 和生成的文件:# 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_())

【讨论】:

以上是关于PyQt5 对象的 SEGV_MAPERR的主要内容,如果未能解决你的问题,请参考以下文章

pyqt5,接收 AttributeError:“QMainWindow”对象没有属性“browseSlot”

我们可以像在处理中那样在 PyQt5 中绘制 3D/2D 对象吗?

Pyqt5 接口 Arduino 伺服 ErrorType“对象没有属性‘ser’”

在 PyQt5 中通过对象#id 设置样式

当连接类型 = Qt.DirectConnection 时,来自线程对象的 PyQt5 信号会导致段错误

PyQt5 视频播放器:转换为面向对象的代码会阻止播放