【问题标题】:PyQt5: mouseClick and source-code in QWebEngineViewPyQt5:鼠标单击和 QWebEngineView 中的源代码
【发布时间】:2017-04-03 10:22:21
【问题描述】:

我有一个使用 PyQt-5.5.1 的工作脚本,我现在想将其移植到新的 PyQt 版本 (5.7)。调整大部分内容都很好,但我遇到了两个主要问题:(1)执行(模拟)鼠标点击,(2)访问(比如说:打印)当前显示的网页的 html 源代码分别是 QWebView 或 QWebEngineView。

例如,我可以在 PyQt-5.5.1 中使用 QWebView 执行以下操作:

QTest.mouseClick(self.wvTest, Qt.LeftButton, QPoint(x, y))

frame = self.wvTest.page().mainFrame()
print(frame.toHtml().encode('utf-8'))

我知道 docsthis page 关于移植到 QWebEngineView 但无法将 C++ 表示法转换为工作 Python 代码。

我怎样才能使它适应 PyQt-5.7 中的 QWebEngineView?以下是 PyQt-5.5.1 的完整工作 sn-p,对于新的 PyQt 版本失败:

  • 对于 Button1:完全没有鼠标点击反应。
  • 对于 Button2:AttributeError: 'QWebEnginePage' object has no attribute 'mainFrame',当我删除大型机()时:TypeError: toHtml(self, Callable[..., None]): not enough arguments

导入系统
从 PyQt5.QtWidgets 导入 QWidget、QPushButton、QApplication
从 PyQt5.QtCore 导入 QRect、Qt、QUrl、QPoint、QEvent
从 PyQt5.QtTest 导入 QTest
从 PyQt5.Qt 导入 PYQT_VERSION_STR

如果 PYQT_VERSION_STR=='5.5.1':从 PyQt5 导入 QtWebKitWidgets 否则:从 PyQt5 导入 QtWebEngineWidgets

class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.button1 = QPushButton('Button1', self) self.button1.clicked.connect(self.buttonOne) self.button1.setGeometry(QRect(10, 10, 90, 20)) self.button2 = QPushButton('Button2', self) self.button2.clicked.connect(self.buttonTwo) self.button2.setGeometry(QRect(110, 10, 90, 20)) if PYQT_VERSION_STR=='5.5.1': self.wvTest = QtWebKitWidgets.QWebView(self) else: self.wvTest = QtWebEngineWidgets.QWebEngineView(self) self.wvTest.setGeometry(QRect(10, 40, 430, 550)) self.wvTest.setUrl(QUrl('http://www.startpage.com')) self.wvTest.setObjectName('wvTest') self.setGeometry(300, 300, 450, 600) self.setWindowTitle('WebView minimalistic') self.show() def buttonOne(self): qp = QPoint(38, 314) QTest.mouseClick(self.wvTest, Qt.LeftButton, pos=qp) # or: QTest.mouseMove(self.wvTest, pos=self.qp) print('Button1 pressed.') def buttonTwo(self): frame = self.wvTest.page().mainFrame() print(frame.toHtml().encode('utf-8')) if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())

【问题讨论】:

    标签: python pyqt5 qtwebkit qtwebengine qtestlib


    【解决方案1】:

    QWebEngineView 类不是QWebView 的直接替代品。正如porting guide 所表明的那样,许多API 已经发生了根本性的变化,一些主要功能完全缺失。除非您的浏览器实现非常非常简单,否则这可能会导致无法编写兼容层。编写一个单独的测试套件很可能更容易(除非您不介意编写大量条件代码)。

    首先,您需要为QTBUG-43602 实施解决方法。 QWebEngineView 的当前设计意味着内部 QOpenGLWidget 处理鼠标事件,因此每当加载页面时,您的代码都需要获得对它的新引用:

    class Example(QWidget):
        ...
    
        def initUI(self):
            ...    
            self._glwidget = None
    
            if PYQT_VERSION_STR=='5.5.1':
                self.wvTest = QtWebKitWidgets.QWebView(self)
            else:
                self.wvTest = QtWebEngineWidgets.QWebEngineView(self)
                self.wvTest.installEventFilter(self)
            ...
    
        def eventFilter(self, source, event):
            if (event.type() == QEvent.ChildAdded and
                source is self.wvTest and
                event.child().isWidgetType()):
                self._glwidget = event.child()
                self._glwidget.installEventFilter(self)
            elif (event.type() == QEvent.MouseButtonPress and
                  source is self._glwidget):
                print('web-view mouse-press:', event.pos())
            return super().eventFilter(source, event)
    
        def buttonOne(self):
            qp = QPoint(38, 314)
            widget = self._glwidget or self.wvTest
            QTest.mouseClick(widget, Qt.LeftButton, pos=qp)
    

    为了访问页面的 html,您需要一些条件代码,因为 Web 引擎 API 是异步工作的,并且需要回调。此外,网络引擎中没有用于处理框架的内置 API(您需要为此使用 javascript),所以一切都需要通过网页:

        def buttonTwo(self):
            if PYQT_VERSION_STR=='5.5.1':
                print(self.wvTest.page().toHtml())
            else:
                self.wvTest.page().toHtml(self.processHtml)
    
        def processHtml(self, html):
            print(html)
        
    

    【讨论】:

    • 非常感谢!这完美无缺。但是,通过将其实现回我的原始脚本,出现了两个小的后续问题:(1) 是否有可能使点击适用于 QWebEngineView 的不同缩放因子,即self.wvTest.setZoomFactor(0.8)? (2) 如何将 html 代码保存为字符串以供进一步处理而不是打印?抱歉,我根本不熟悉回调的东西。
    • (1) 这似乎是一个完全独立的问题,与移植无关。显然如果你改变缩放系数,输入字段的位置会改变,所以你需要相应地调整它。 (2) 我已经更新了答案中的示例代码。
    • 不知何故,(1)不适用于不同的ZoomFactor,尽管我相应地调整了坐标。我正在考虑一个可能的错误,但我必须再次调查它。 (2):所以,没有办法直接提取出来……好吧,这样就行了。 :) 非常感谢您的帮助。
    • @nostradamus。 (1) 我用QPoint(30, 270) 试了一下,效果很好。 (2) 是的,它是异步的,与其他几个 API 一样(例如 runJavaScript)。
    • 如果你在加载的网页上右击,你会得到另一个新的_glwidget,你需要删除elif部分中的source is self._glwidget检查以使其仍然有效
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-15
    • 1970-01-01
    • 2019-10-26
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多