0

Currently, I want to set value for html using runJavaScript.

The following code works:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *


class Widget(QWidget):

    def __init__(self):
        super().__init__()

        lay = QVBoxLayout()
        self.btn = QPushButton('change html value')
        self.browser = QWebEngineView()
        lay.addWidget(self.btn)
        lay.addWidget(self.browser)

        self.setLayout(lay)

        self.browser.setHtml(
            '''
            <html>
                <head>
                    <title>My Page</title>
                </head>
                <body>
                    <h1 id="welcome">Welcome to my page!</h1>
                    <h1 id="value"> 0 </h1>
                </body>
            </html>
            '''
        )

        self.btn.clicked.connect(self.btnClickSlot)

    def btnClickSlot(self, check=False):
        self.browser.page().runJavaScript('document.getElementById("value").innerHTML = "1"')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Widget()
    win.show()
    app.exec_()

The value changes from 0 to 1 after click the change html value button.

But, I don't want to trigger the operation by click. I want to directly change the value.

And the modified code is:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *


class Widget(QWidget):

    def __init__(self):
        super().__init__()

        lay = QVBoxLayout()
        self.btn = QPushButton('change html value')
        self.browser = QWebEngineView()
        lay.addWidget(self.btn)
        lay.addWidget(self.browser)

        self.setLayout(lay)

        self.browser.setHtml(
            '''
            <html>
                <head>
                    <title>My Page</title>
                </head>
                <body>
                    <h1 id="welcome">Welcome to my page!</h1>
                    <h1 id="value"> 0 </h1>
                </body>
            </html>
            '''
        )

        self.browser.page().runJavaScript('document.getElementById("value").innerHTML = "1"')
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Widget()
    win.show()
    app.exec_()

The value don't change as I expect.

How can I directly change the value? Any suggestion is appreciated~~~

Qiang Zhang
  • 820
  • 8
  • 32
  • Connect the `loadFinished` signal to the function that runs the javascript. – musicamante Feb 23 '23 at 16:45
  • Thanks for your suggestion. I understand my `runJavaScript` do not work resulting from that the html do not finish loading. However, I have tested that sleep 10s after `win.show`, and than run `runJavaScript`. But, it still do not work. I think 10s is enough for QWebEngineView loading `html`. – Qiang Zhang Feb 24 '23 at 02:16
  • What do you mean by "sleep 10s"? You're not trying to use `time.sleep`, are you? Because that would be a **terrible** choice: it would completely block the event loop, thus preventing the whole thread to properly process any event (including HTML parsing, processing and displaying). Don't try to do things in your way if you don't understand how they work: the `loadFinished` signal **is** the solution, why don't you use it? – musicamante Feb 24 '23 at 04:21
  • I have tried `loadFinished`, and the `runJavaScript` in `onLoadFinished` works. But whether the `loadFinished` signal is necessary? I hope I can immediately edit the html element value when the html is set, for example: `browse.setHtml(); browse.runJavaScript`. Is it possible? – Qiang Zhang Feb 24 '23 at 07:38
  • No, you can't. Not that easily, in any case, and it would be completely pointless. Why do you need to run that immediately? Just connect the signal to a function that does the modifications. – musicamante Feb 24 '23 at 17:26
  • Moreover, the `runJavaScript` asynchronnous run. For example, `page().runJavaScript("document.getElementById('value').innerHTML", self.store_value)` is used to obtain the element value, and the value is passed to `store_value(self, param)`. But, if I want to obtain 3 element value, in the `store_value`, how can I decide the param belongs to which id? – Qiang Zhang Feb 25 '23 at 03:50
  • You probably need a lambda, but be careful about the *scope*: if you use a for loop, you must ensure that the lambda is properly formatted. For instance: `for id in ():` `page().runJavascript(f"document.getElementById('{_id}').innerHTML", lambda param, id=id: self.store_value(param, id))`. Then just add that argument to the function: `def store_value(self, param, id):`. Note that I used `id` for simplicity, but [`id()`](https://docs.python.org/3/library/functions.html#id) is a builtin python keyword and should not be used as lightly. – musicamante Feb 25 '23 at 04:01

0 Answers0