2016-11-19 4 views
4

У меня есть рабочий скрипт, который использует PyQt-5.5.1, который теперь я хочу подключить к новой версии PyQt (5.7). Адаптация большинства вещей была прекрасной, но я столкнулся с двумя серьезными проблемами: (1) выполнить (смоделированный) mouseclick, (2) получить доступ (скажем: напечатать) исходный код html веб-страницы, который в настоящее время отображается в QWebView или QWebEngineView, соответственно.PyQt5: mouseClick и исходный код в QWebEngineView

Например, я мог бы сделать следующее с помощью QWebView в PyQt-5.5.1:

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

и

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

Я отдаю себе отчет в docs, а также this page о переносе на QWebEngineView но не может преобразовать нотацию C++ в рабочий код Python.

Как я могу адаптировать это к QWebEngineView в PyQt-5.7? Ниже приведен полный рабочий фрагмент для PyQt-5.5.1, который не подходит для новой версии PyQt:

  • для Button1: реакция на щелчок мыши вообще отсутствует.
  • для Button2: AttributeError: 'QWebEnginePage' object has no attribute 'mainFrame', и когда я удаляю мейнфрейм(): TypeError: toHtml(self, Callable[..., None]): not enough arguments.

import sys 
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication 
from PyQt5.QtCore import QRect, Qt, QUrl, QPoint, QEvent 
from PyQt5.QtTest import QTest 
from PyQt5.Qt import PYQT_VERSION_STR

if PYQT_VERSION_STR=='5.5.1': from PyQt5 import QtWebKitWidgets else: from PyQt5 import 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_())

ответ

3

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 страницы, вы будете нужен некоторый условный код, потому что 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) 
+0

Спасибо большое! Это работает безупречно. Однако, реализовав его обратно к моему оригинальному сценарию, возникли два небольших последующих вопроса: (1) Есть ли возможность сделать работу с щелчком для другого коэффициента масштабирования QWebEngineView, то есть 'self.wvTest.setZoomFactor (0.8) '? (2) Как сохранить html-код в строку для дальнейшей обработки, а не распечатать ее? Извините, я вообще не знаком с обратным вызовом. – nostradamus

+0

(1) Это похоже на совершенно отдельный вопрос, который не имеет никакого отношения к переносу. Очевидно, что если вы измените коэффициент масштабирования, положение поля ввода изменится, поэтому вам необходимо соответствующим образом отрегулировать его. (2) Я обновил код примера в своем ответе. – ekhumoro

+0

Как-то (1) не работал для другого 'ZoomFactor', хотя я скорректировал координаты соответственно. Я думал о возможной ошибке, но я должен заглянуть в нее снова. (2): Таким образом, нет возможности напрямую извлечь его ... Хорошо, что будет.:) Большое спасибо за вашу помощь. – nostradamus

Смежные вопросы