Обслуживание ресурса для QWebView PyQT5

Как обслуживать ресурс (файлы, такие как html, css, js, шрифты) для приложения для настольного компьютера в QWebView (в PyQT5)?

Что я хочу это:

  1. Если возможно, обработка запрошенного ресурса с помощью движка Webkit PyQT5 по специальной схеме, например, скажем custom://app/jquery.js и возвращая файл.
  2. Если возможно, обработка стандартных HTTP-глаголов (GET, POST, ...) для этой пользовательской схемы.

Если эти 2 невозможны (по крайней мере, невозможны чисто Pythonic способом):

  • Как я могу перехватывать запросы, поступающие от встроенного Webkit, и предоставлять ресурс (html, css, js) на основе шаблона в URL (как, скажем, некоторые регулярные выражения) (?<controller>[^/])/(?<action>[^/]))?

1 ответ

Решение

Вам нужно создать свой собственный подкласс QNetworkAccessManager, который возвращает пользовательский QNetworkReply для желаемого протокола, а затем установить его в качестве диспетчера сетевого доступа для вашей страницы QWebView.

В этой статье показан хороший пример того, как это можно сделать - применительно к PyQt5 это выглядит так:

from PyQt5.QtCore import QUrl, QTimer, QIODevice
from PyQt5.QtWidgets import QApplication
from PyQt5.QtNetwork import (QNetworkAccessManager,
                             QNetworkReply,
                             QNetworkRequest)
from PyQt5.QtWebKitWidgets import QWebView

import sys

class ExampleNetworkAccessManager(QNetworkAccessManager):

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

    def createRequest(self, operation, request, device):
        if request.url().scheme() == 'example':
            return ExampleReply(self, operation, request, device)
        return super().createRequest(operation, request, device)


class ExampleReply(QNetworkReply):

    def __init__(self, parent, operation, request, device):
        super().__init__(parent=parent)
        self.setRequest(request)
        self.setOperation(operation)
        self.setUrl(request.url())
        self.bytes_read = 0
        self.content = b''

        # give webkit time to connect to the finished and readyRead signals
        QTimer.singleShot(200, self.load_content)

    def load_content(self):
        if self.operation() == QNetworkAccessManager.PostOperation:
            # handle operations ...
            pass
        # some dummy content for this example
        self.content = b'''<html>
            <h1>hello world!</h1>
            <p>...</p>
            </html>'''
        self.open(QIODevice.ReadOnly | QIODevice.Unbuffered)
        self.setHeader(QNetworkRequest.ContentLengthHeader, len(self.content))
        self.setHeader(QNetworkRequest.ContentTypeHeader, "text/html")
        self.readyRead.emit()
        self.finished.emit()

    def abort(self):
        pass

    def isSequential(self):
        return True

    def bytesAvailable(self):
        ba = len(self.content) - self.bytes_read + super().bytesAvailable()
        return ba

    def readData(self, size):
        if self.bytes_read >= len(self.content):
            return None
        data = self.content[self.bytes_read:self.bytes_read + size]
        self.bytes_read += len(data)
        return data

    def manager(self):
        return self.parent()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    wv = QWebView()
    enam = ExampleNetworkAccessManager()
    wv.page().setNetworkAccessManager(enam)
    wv.show()
    wv.setUrl(QUrl("example://test.html"))
    app.exec()
Другие вопросы по тегам