evaluateJavaScript in PyQt - function is not calle

2019-06-14 14:17发布

问题:

I have a problem with PyQt/its Webview. The code that is bothering me should render a chart, but it doesn't. I am using the Highcharts framework and provide the data for the javascript function that renders the chart via Python. I also check whether the webview is ready because that was a previous error of mine. The code in question looks something like this:

command = ('loadPinch(' + str(random.sample(range(10000), 1000)) +
            ', ' + str(['2009', '01', '01']) + ');')
self.webview.page().mainFrame().evaluateJavaScript("""
        var readyStateCheckInterval = setInterval(function() {
            if(document.readyState === 'complete'){ """ +
                command + """
                clearInterval(readyStateCheckInterval);
            }
        }, 10);""")

loadPinch is a JavaScript function and looks similar to this(which in turn looks similar to a Highcharts example graph):

    function loadPinch(data, date){
    $('#container').highcharts({
        chart: {
            zoomType: 'x',
            spacingRight: 20
        },
        title: {text: 'Twitter Trends'},
        subtitle: {
            text: document.ontouchstart === undefined ?
                'Click and drag in the plot area to zoom in' :
                'Pinch the chart to zoom in'
        },
        xAxis: {
            type: 'datetime',
            maxZoom: 10 * 24 * 3600000,
            title: {text: null}
        },
        yAxis: {
            title: {text: 'Occurence'}
        },
        tooltip: {shared: true},
        legend: {enabled: false},
        plotOptions: {
            area: {
                fillColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1},
                    stops: [
                        [0, Highcharts.getOptions().colors[0]],
                        [1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
                    ]
                },
                lineWidth: 1,
                marker: {enabled: false},
                shadow: false,
                states: {hover: {lineWidth: 1}},
                threshold: null
            }
        },
        series: [{
            type: 'area',
            name: 'Twitter Trend',
            pointInterval: 24 * 3600 * 1000,
            pointStart: Date.UTC(date[0], date[1], date[2]),
            data: data
        }]
    });
};

I might tell you that if I print the command that I am handing evaluateJavaScript to the console instead of executing it and pasting it over to the developer console, it gets executed as expected and renders the chart which leads me to believe that there is some sort of race condition I can't track down.

Does someone have an idea of what could be the problem?

Regards, Carson

NOTE: The problem is still relevant.

回答1:

I eventually found my fix; i thought too much in JS terms.

There is a signal in QT that is emitted when the page is finished loading, called loadFinished(). By binding this signal to a slot of mine which executed the call to evaluateJavascript(command), the chart loaded. It seems like Qts webview has problems to execute Javascript when the page hasn't finished loading yet.

Anyway, this is how the code looks like(simplified):

class something():
    def __init__(self):
        self.webview = QtWebkitWidgets.QWebView()
        self._myBindingFunction()

    def _myBindingFunction(self):
        self.webview.loadFinished.connect(self._plot)

    def _plot(self):
        command = ('loadPinch(' + str(random.sample(range(10000), 1000)) +
                   ', ' + str(['2009', '01', '01']) + ');')
        self.webview.page().mainFrame().evaluateJavaScript(command)

Note how that simplifies the JS code; i do not have to check for the site having loaded, because after the signal is emitted, it has to be ready.

Big shoutout to Pawel Fus though for leading me onto the right track. I was already giving it up.