Как шаг за шагом загрузить javascript с помощью QWebEngineView и qtwebchannel.js? - PullRequest
0 голосов
/ 05 февраля 2019

Я настраиваюсь как фреймворк, который использует python в backend и html / css / js для frontend.Моя проблема возникла во время загрузки QWebEngineView.

Я ищу в Интернете, как установить связь между python и javascript с QWebEngineView, и, наконец, я попытался использовать QtWebChannel.Поэтому я все настроил, и все работало хорошо с обменом между python и javascript, но появилась следующая проблема:

  • Первое: я не могу загрузить файлы javascript напрямую в html с тегами <script>
  • Второе: javascript загружен случайным образом, я пытался загрузить javascript из python с помощью my_view.page().runJavascript(my_js), но он работает одна попытка на две.Так что иногда jQuery загружается в конце, поэтому другая часть кода не работает.

base.html:

<!DOCTYPE html>
<html lang="en">
    <p id="log"></p>
    <script src="qrc:///qtwebchannel/qwebchannel.js"></script>
    <script>
        window.onerror = function (error, url, line) {
            console.error("ERROR: " + error.toString());
            console.error("LINE: " + line.toString());
         };
        function load_app(){
            new QWebChannel(qt.webChannelTransport, function (channel) {
                window.app = channel.objects.app;
                app.load_javascript(function(ret){
                    console.error("load javascript: " + ret)
                });
            });
         }
        load_app();
        console.error("app loaded")
    </script>
    {{ application_html_content | safe }}
</html>

Другая часть HTML:

{% extends 'base.html' %}

{% block content %}
    <div class="row">
        {% for user_id, user in user_dict.items() %}
            <div id="{{ user_id }}" class="col s12 m6">
                <div class="card blue-grey darken-1">
                    <div class="card-content white-text">
                        <span class="card-title">Visit Card</span>
                        <p>{{ user.name }}</p>
                    </div>
                    <div class="card-action">
                        <button id="btn_del_{{ user_id }}" class="btn blue waves-effect waves-light" onclick="delete_user({{ user_id }})">Delete</button>
                        <button class="btn blue waves-effect waves-light" onclick="detail_user({{ user_id }})">Detail</button>
                    </div>
                </div>
            </div>
        {% endfor %}
    </div>
{% endblock %}

{% block javascript %}
    <script>
        $(document).ready(function() {
           app.request_result.connect(function (result) {
                if ("delete" in result) {
                    user_id = result.delete;
                    var element = document.getElementById(user_id);
                    element.parentNode.removeChild(element)
                }
            });
            console.error("ready");
        });

        function delete_user(user_id) {
            document.getElementById("btn_del_" + user_id).innerHTML = "Waiting ...";
            app.request('DemoHtml:Default:delete', user_id);
        }
        function detail_user(user_id) {
            app.path('detail_user', {"user_id": user_id});
        }
    </script>
{% endblock %}

функция load_javascript:

JQUERY = "vendor/Resources/js/jquery.js"
MATERIALIZE = "vendor/Resources/css/materialize/js/materialize.js"

@pyqtSlot(result=str)
def load_javascript(self):
    with open(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.MATERIALIZE), "r") as m_stream:
        materialize_content = m_stream.read()
    with open(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.JQUERY), "r") as j_stream:
        jquery_content = j_stream.read()
    self.template_view.view.page().runJavaScript(jquery_content)
    self.template_view.view.page().runJavaScript(materialize_content)
    return "ok"

Как вы можете видеть, обычно я должен видеть в журнале ошибку:

  • Сначала: «загрузить javascript: ok»
  • Второе: «приложение загружено»

, но один раз один два, это наоборот:

  • js: приложение загружено
  • js: ОШИБКА: Uncaught ReferenceError: $ не определено
  • js: LINE: 67
  • js: Uncaught ReferenceError: $ не определено
  • js: загрузить javascript: ok

Любая помощь для этого?

Заранее спасибо!

1 Ответ

0 голосов
/ 07 февраля 2019

Я решил свою проблему, спасибо @ekhumoro за попытку помочь мне, я нашел ответ в этой теме:

Как ждать загрузки другого JS для продолжения операции? : https://stackoverflow.com/a/8618519/8293533

Чтобы заставить его работать, я изменяю свой JavaScript следующим образом: я назвал этот файл app.js

function set_app() {
    try{
        new QWebChannel(qt.webChannelTransport, function (channel) {
            window.app_channel = channel.objects.app;
        });
    } catch (e) {
        console.error("setting_app error: " + e)
    }
}

set_app();

function request(route, args) {
    let interval = 10;
    window.setTimeout(function () {
        if (window["app_channel"]) {
            app_channel.request(route, args)
        } else {
            try {
                set_app();
            }
            catch(error) {
                console.error("app load error: " + error)
            }
            window.setTimeout(arguments.callee, interval);
        }
    }, interval)
}

function path(route, args) {
    let interval = 10;
    window.setTimeout(function () {
        if (window["app_channel"]) {
            app_channel.path(route, args)
        } else {
            try {
                set_app();
            }
            catch(error) {
                console.error("app load error: " + error)
            }
            window.setTimeout(arguments.callee, interval);
        }
    }, interval)
}

function request_result(callback) {
    let interval = 10;
    window.setTimeout(function () {
        if (window["app_channel"]) {
            app_channel.request_result.connect(callback)
        } else {
            try {
                set_app();
            }
            catch(error) {
                console.error("app load error: " + error)
            }
            window.setTimeout(arguments.callee, interval);
        }
    }, interval)
}

Я стираю свой код load_javascript в python, потому что янашел способ вызывать js с помощью тегов <script> и qrc:/// path.

Теперь моя HTML-голова выглядит так:

<!DOCTYPE html>
<html lang="en">
    <p id="log"></p>
    <script src="qrc:///qwebchannel.js"></script>
    <script src="qrc:///app.js"></script>
    <script src="qrc:///jquery.js"></script>
    {{ application_html_content | safe }}
    <script src="qrc:///materialize.min.js"></script>
</html>

Для использования qrc:///xxx.js я использовал QResourceи .qrc, .rcc файлы.Это пример моего кода для тех, кто хочет:

class ApplicationContainer:

    SRC_QRC_PATH = "src/*Bundle/Resources/qrc/*.qrc"
    SRC_RCC_PATH = "src/*Bundle/Resources/qrc/*.rcc"
    VENDOR_QRC_PATH = "vendor/*Bundle/Resources/qrc/*.qrc"
    VENDOR_RCC_PATH = "vendor/*Bundle/Resources/qrc/*.rcc"

    def __init__(self):
        self.__pyqt_application = QApplication(sys.argv)
        self.__pyqt_resources = QResource()
        self.set_rcc_files()

    @property
    def application(self):
        return self.__pyqt_application

    @application.setter
    def application(self, new_app: QApplication):
        self.__pyqt_application = new_app

    def set_rcc_files(self):
        qrc_files = glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.SRC_QRC_PATH))
        qrc_files += glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.VENDOR_QRC_PATH))
        for qrc in qrc_files:
            subprocess.call(["rcc", "-binary", qrc, "-o", qrc[:-3] + "rcc"])

        rcc_files = glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.SRC_RCC_PATH))
        rcc_files += glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.VENDOR_RCC_PATH))

        for rcc in rcc_files:
            self.__pyqt_resources.registerResource(rcc)

Как видите, я использую команду rcc, а не pyrcc5

Чтобы закончить, это мой .qrc file:

<!DOCTYPE RCC>
<RCC version="1.0">
    <qresource>
        <file alias="jquery.js">../js/jquery.js</file>
        <file alias="app.js">../js/app.js</file>
        <file alias="qwebchannel.js">../js/qwebchannel.js</file>
        <file alias="materialize.js">../css/materialize/js/materialize.js</file>
        <file alias="materialize.css">../css/materialize/css/materialize.css</file>
    </qresource>
</RCC>

Я знаю, что может быть много улучшений и оптимизаций в коде JavaScript и коде Python.Но это работает так!

Спасибо и надеюсь, я тоже кому-нибудь помогу.

...