1

私は変更されたを使用するプロジェクトに取り組んでいます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 の落とし穴については既に読んでおり、ページの読み込みが終了したときに呼び出されるメソッドを使用して、そのオブジェクトを変更済みQtWebKit.QWebFrameの属性として保存しています。つまり、すべてがうまくいきました。QWebViewsetframeafterloadfinishedQWebView

機能的で最小限の例を次に示します (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

私のプロジェクトは、何も変更していないかのように正しく動作するはずですが、これらの変更ではうまくいきません。私は何を間違っていますか?sについて何か不足していQWebFrameますか?

4

1 に答える 1

2

まず第一に、あなたの例は最小限ではありません.ファイル「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) は既に削除されています。」エラーは発生しません。

于 2014-11-08T01:32:33.983 に答える