python - 错误 : Internal C++ object (PySide. QtWebKit.QWebFrame) 已删除;但我将其保存为属性以避免这个问题

标签 python pyside qwebview qwebkit qwebpage

我正在开发一个使用修改后的QWebView的项目。我收到此错误:

Traceback (most recent call last):
  File "/home/jorge/coders/universal-scraper/src/customwebview.py", line 63, in mouseMoveEvent            
    hittestresult = self.currentframe.hitTestContent(event.pos())
RuntimeError: Internal C++ object (PySide.QtWebKit.QWebFrame) already deleted.

我读过 PySide pitfalls已经,并且我已经使用 setframeafterloadfinished 方法将该 QtWebKit.QWebFrame 对象保存为修改后的 QWebView 的属性,该方法页面加载完成时调用,在我修改的 QWebView 上需要的一些重大更改发生后引发的问题,在此之前,一切都很顺利。

功能和最小示例在这里(只需确保在运行测试之前将文件 webelementinfo.py 放在与此代码相同的目录中):

#!/usr/bin/env python2
# coding: utf-8
#                        VENI, SANCTE SPIRITUS

from PySide.QtWebKit import QWebView
from PySide import QtCore, QtGui
try:
    from . import webelementinfo
except ValueError:
    import webelementinfo


class CustomQWebView(QWebView):

    def __init__(self, *args, **kwargs):
        """ Init the custom class
        """
        super(CustomQWebView, self).__init__(*args, **kwargs)
        self.colors = {0: QtGui.QColor(255, 165, 0, 127),
                       1: QtGui.QColor(135, 206, 235, 127),
                       2: QtGui.QColor(135, 235, 164, 127),
                       3: QtGui.QColor(235, 135, 206, 127),
                       4: QtGui.QColor(235, 164, 135, 127)}
        self.color = None
        self.currentframe = None
        self.element = None
        self.loadFinished.connect(self.setframeafterloadfinished)
        self.selectCommentsArea()

    @QtCore.Slot()
    def selectCommentsArea(self):
        """ For selecting the comment area
        """
        self.setup_rectcolor_area(0)

    @QtCore.Slot(QtGui.QMouseEvent)
    def mouseMoveEvent(self, event):
        super(CustomQWebView, self).mouseMoveEvent(event)

        if self.drawrects:
            if self.currentframe:
                hittestresult = self.currentframe.hitTestContent(event.pos())
                element = webelementinfo.WebElement(
                    hittestresult, self.color, self)
                if not self.element:
                    self.element = element
                elif self.element != element:
                    self.element = element

                # FIXME: self.update should draw rects from WebElements too.
                self.update()

    @QtCore.Slot(QtGui.QPaintEvent)
    def paintEvent(self, event):
        # draw the content first
        super(CustomQWebView, self).paintEvent(event)

        if self.drawrects:
            # then the rectangle
            if self.element:
                self.element.update()

    def setframeafterloadfinished(self):
        self.currentframe = self.page().mainFrame()

    def setup_rectcolor_area(self, forarea):
        """Called when we want to select certain area of a web site

        This method set-up the painter to a giving color so web elements are
        drawn with a rect on top. Also activates the flag to allow painting
        inside CustomQWebView.

        :param int forarea: For which area we are going to set the painter\\
        valid values are: 0 for Comments area, 1 for comment box, 2 for\\
        commentator's user name, 3 for comment date and time, 4 for\\
        commentary text.
        """
        self.drawrects = True
        self.color = self.colors[forarea]

        # defines what we are looking to select
        self.selecttype = forarea

if __name__ == "__main__":
    app = QtGui.QApplication([])
    mainwn = QtGui.QMainWindow()
    mainwn.resize(800, 696)
    centralwidget = QtGui.QWidget(mainwn)
    centralwidget.resize(800, 600)
    gridlayout = QtGui.QGridLayout(centralwidget)
    web = CustomQWebView(parent=centralwidget)
    gridlayout.addWidget(web, 0, 0, 1)
    web.setUrl(QtCore.QUrl("http://duckduckgo.com"))
    mainwn.show()

    app.exec_()

这是另一个文件,其中包含我编写并开始使用的新类 WebElement 的定义:

#!/usr/bin/env python2
# coding: utf-8
#                        VENI, SANCTE SPIRITUS

from PySide.QtWebKit import QWebElement, QWebHitTestResult
from PySide import QtGui
from PySide import QtCore


class WebElement(QtCore.QObject):

    """ Holds information of webelements
    """

    def __eq__(self, other):
        if isinstance(other, WebElement):
            return (self.web_element == other.web_element and
                    self.getrect() == other.getrect())
        else:
            raise ValueError("Not same objects")

    def __ne__(self, other):
        if isinstance(other, WebElement):
            return (self.web_element != other.web_element and
                    self.getrect() != other.getrect())
        else:
            raise ValueError("Not same objects")

    def __init__(self, hittestresult, color, parent=None):
        super(WebElement, self).__init__(parent)

        if (not isinstance(hittestresult, QWebHitTestResult) and
                not isinstance(hittestresult, QWebElement)):
            raise ValueError(
                "Argument passed for 'hittestresult' is not"
                " QtWebkit.QWenHitTestResult or QtWebkit.QWebElement instance"
            )
        if not isinstance(color, QtGui.QColor):
            raise ValueError(
                "Argument passed for 'color' is not QtGui.QColor instance"
            )

        try:
            self.frame = hittestresult.frame()
        except AttributeError:
            self.frame = hittestresult.webFrame()

        self.frame_scroll_x = self.frame.scrollPosition().x()
        self.frame_scroll_y = self.frame.scrollPosition().y()

        try:
            rect = hittestresult.boundingRect()
        except AttributeError:
            rect = hittestresult.geometry()

        self.element_rect_x = rect.x()
        self.element_rect_y = rect.y()
        self.element_rect_w = rect.width()
        self.element_rect_h = rect.height()

        try:
            self.web_element = hittestresult.element()
        except AttributeError:
            self.web_element = hittestresult

        self.color = color
        self.color_darker = color.darker()
        self.color_darker.setAlpha(255)
        self.pen = QtGui.QPen(self.color_darker)
        self.pen.setWidth(2)
        #self.painter = QtGui.QPainter(self.parent)
        self.painter = QtGui.QPainter()
        self.painter.setPen(self.pen)

    def update(self):
        """ draw the rect for this element in the CustomQWebView
        """
        rect = self.getrect()
        rectf = QtCore.QRectF(rect)
        self.painter.fillRect(rectf, self.color)
        self.painter.drawRect(rectf)

    def getrect(self):
        """ Return the rect for this WebElement
        """
        self.frame_scroll_x = self.frame.scrollPosition().x()
        self.frame_scroll_y = self.frame.scrollPosition().y()
        rect = QtCore.QRect()
        rect.setRect(self.element_rect_x - self.frame_scroll_x,
                     self.element_rect_y - self.frame_scroll_y,
                     self.element_rect_w, self.element_rect_h)
        return rect

我的项目应该可以正常工作,就好像我没有更改任何内容一样,但是,经过这些更改后,情况却并非如此。我究竟做错了什么?我是否缺少有关 QWebFrame 的信息?

最佳答案

首先,您的示例不是最小:文件“webelementinfo.py”不相关(以及您的类的许多其他部分),导致问题的是 QWebHitTestResult.frame()方法。足以发生错误的代码如下:

@QtCore.Slot(QtGui.QMouseEvent)
def mouseMoveEvent(self, event):
    if self.currentframe:
        hittestresult = self.currentframe.hitTestContent(event.pos())
        hittestresult.frame() # <- will cause the crash on next mouseMoveEvent

正如 ekhumoro 所指出的这看起来像是 PySide 中的一个错误,与对象所有权相关。您需要避免调用 frame() 方法 - 看起来它在您的代码中并不是真正重要的。将 WebElement 的构造函数更改为:

def __init__(self, frame, hittestresult, color, parent=None):

然后:

#try:
#    self.frame = hittestresult.frame()     <-- DO NOT CALL THIS
#except AttributeError:
#    self.frame = hittestresult.webFrame()

self.frame = frame

并显式传递帧:

hittestresult = self.currentframe.hitTestContent(event.pos())

element = webelementinfo.WebElement(
    self.currentframe, 
    hittestresult,
    self.color,
    self)

通过这些修复,“内部 C++ 对象 (PySide.QtWebKit.QWebFrame) 已被删除。”不会发生错误。

关于python - 错误 : Internal C++ object (PySide. QtWebKit.QWebFrame) 已删除;但我将其保存为属性以避免这个问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26726878/

相关文章:

python - 让 python tcp 服务器在发送后发送和接收消息?

python - 为什么分配给一个空列表而不是一个空元组是有效的?

python - 如何为绘制的对象(例如drawLine)制作透明背景?

c++ - Qt Webview 谷歌地图缓存

css - 将自定义样式表应用于 QWebView

python - PI 的位数不同

python - 如何执行这样的pandas聚合: drop nan and concatenate to the first?

python - 打印按钮工具栏 PySide Python

python - 如何使用 PySide 加载图像联系表?

python - QWebKit linkClicked 信号从不触发