Nano Hash - криптовалюты, майнинг, программирование

PyQt5 извлекает значения формы с помощью runJavaScript

У меня есть файл form.html, и я запускаю его с помощью PyQt5 QWebEngineView. Я хочу получить значения формы после нажатия кнопки «Отправить». Я перепробовал множество решений, но идеального не нашел. Например: я нашел этот, но он работает на URL Change.

Я просто ищу решение, которое работает при нажатии кнопки «Отправить».

Вот мой код, который я использовал по приведенной выше ссылке, но я не получаю никакого значения, возвращаемого из формы:

import os
import sys
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget
from PyQt5.QtCore import QUrl, QEventLoop
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor

class WebPage(QWebEngineView):
    def __init__(self):
        QWebEngineView.__init__(self)
        filepath = os.path.abspath(os.path.join(os.path.dirname(__file__), 'form.html'))
        self.load(QUrl.fromLocalFile(filepath))
        self.loadFinished.connect(self._on_load_finished)

    def _on_load_finished(self):
        self.page().runJavaScript("document.getElementById('num1').value", self.store_value)

    def store_value(self, param):
        self.value = param
        print("Param: " +str(param))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    web = WebPage()
    web.show()
    sys.exit(app.exec_())

HTML:

<html>
    <body>
        <form>
            Number 1:<input type="text" id="num1">
            <br>
            Number 2:<input type="text" id="num2">
            <br>
            <input type="submit" id="sub1">
        </form>
    </body>
</html>

Ответы:


1

Основываясь на стратегии, которую я использовал в моем старом ответе, решение состоит в том, чтобы внедрить QObject через QWebChannel и в нем сделайте привязку к событию нажатия кнопки, чтобы обновить слот. В этом случае я использую Jinja2, чтобы упростить написание сценария.

import os
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannel
from jinja2 import Template


class Element(QtCore.QObject):
    def __init__(self, name, parent=None):
        super(Element, self).__init__(parent)
        self._name = name

    @property
    def name(self):
        return self._name

    def script(self):
        raise NotImplementedError


class FormObject(Element):
    numbersChanged = QtCore.pyqtSignal(str, str)

    def script(self):
        _script = r"""
        var btn = document.getElementById('sub1');
        btn.addEventListener("click", function(event){
            var number1 = document.getElementById('num1');
            var number2 = document.getElementById('num2');
            {{name}}.update(number1.value , number2.value);
        });
        """
        return Template(_script).render(name=self.name)

    @QtCore.pyqtSlot(str, str)
    def update(self, number1, number2):
        self.numbersChanged.emit(number1, number2)


class WebEnginePage(QtWebEngineWidgets.QWebEnginePage):
    def __init__(self, *args, **kwargs):
        super(WebEnginePage, self).__init__(*args, **kwargs)
        self.loadFinished.connect(self.onLoadFinished)
        self._objects = []

    def add_object(self, obj):
        self._objects.append(obj)

    @QtCore.pyqtSlot(bool)
    def onLoadFinished(self, ok):
        if ok:
            self.load_qwebchannel()
            self.load_objects()

    def load_qwebchannel(self):
        file = QtCore.QFile(":/qtwebchannel/qwebchannel.js")
        if file.open(QtCore.QIODevice.ReadOnly):
            content = file.readAll()
            file.close()
            self.runJavaScript(content.data().decode())
        if self.webChannel() is None:
            channel = QtWebChannel.QWebChannel(self)
            self.setWebChannel(channel)

    def load_objects(self):
        if self.webChannel() is not None:
            objects = {obj.name: obj for obj in self._objects}
            self.webChannel().registerObjects(objects)
            _script = r"""
            {% for obj in objects %}
            var {{obj}};
            {% endfor %}
            new QWebChannel(qt.webChannelTransport, function (channel) {
            {% for obj in objects %}
                {{obj}} = channel.objects.{{obj}};
            {% endfor %}
            }); 
            """
            self.runJavaScript(Template(_script).render(objects=objects.keys()))
            for obj in self._objects:
                if isinstance(obj, Element):
                    self.runJavaScript(obj.script())


class WebPage(QtWebEngineWidgets.QWebEngineView):
    def __init__(self, parent=None):
        super().__init__(parent)

        page = WebEnginePage(self)
        self.setPage(page)

        formobject = FormObject("formobject", self)
        formobject.numbersChanged.connect(self.on_numbersChanged)
        page.add_object(formobject)

        filepath = os.path.abspath(
            os.path.join(os.path.dirname(__file__), "form.html")
        )
        self.load(QtCore.QUrl.fromLocalFile(filepath))

    @QtCore.pyqtSlot(str, str)
    def on_numbersChanged(self, number1, number2):
        print(number1, number2)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    web = WebPage()
    web.show()
    sys.exit(app.exec_())
02.05.2019
  • Спасибо за помощь. Это решение работает отлично. Но у меня много страниц формы (15-20), и поскольку здесь все жестко закодировано, мне трудно редактировать код для следующих страниц. Вместо отправки у меня есть следующая кнопка, которая откроет form2.html, затем form3.html и так далее... Все формы имеют разное количество и тип переменных. Есть ли способ получить значения из всех форм? 02.05.2019
  • Просто чтобы было понятнее: у меня есть 7 форм, в каждой из которых есть кнопка «Далее», а в последней форме есть кнопка «Отправить». Все формы имеют кнопку «Добавить», с помощью которой я могу создать подчиненную форму, которая является копией основной формы. Нажимаю ли я следующую кнопку, кнопку «Добавить» или кнопку «Отправить»... текущие значения в форме должны быть получены с помощью переменных python. Кроме того, есть кнопка «Назад», нажав которую, я могу перейти к предыдущей форме, отредактировать значение и нажать «Далее» (в этом случае переменные должны быть перезаписаны). 02.05.2019
  • Примечание. Все формы представляют собой отдельные HTML-файлы, которые я загружаю через javascript внутри HTML-файла (а не через Python). Я хорошо разбираюсь в Python и HTML, но новичок в концепциях QWebEngineView. Было бы здорово, если бы вы могли предложить что-то, если не полное решение. 02.05.2019
  • @Enzy Мой ответ зависит от того, что вы предлагаете в своем вопросе, я мог бы попытаться обобщить, но для обобщения вам нужна дополнительная информация, которую вы не предоставили в своем вопросе, а в комментариях, поэтому я рекомендую вам опубликовать новый вопрос, указывающий обобщение, предоставляющее минимальный воспроизводимый пример, и мы можем вам помочь :-) 02.05.2019
  • Да, конечно. Я думал, что смогу самостоятельно обобщить решение этой задачи для дальнейших форм, чтобы улучшить себя в этой области. Но я мало что мог сделать. Тогда я опубликую новый вопрос. 02.05.2019
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..