Python 初始evaluateJavaScript()调用后出现PyQt4 QWebview错误

Python 初始evaluateJavaScript()调用后出现PyQt4 QWebview错误,python,qt,pyqt,pyqt4,qwebview,Python,Qt,Pyqt,Pyqt4,Qwebview,我有一个运行PyQt4的Python 2.7应用程序,其中有一个QWebView,它与Javascript之间有双向通信 该应用程序是通过QThreadPool、QRunnables进行多线程处理的,因此我正在使用信号与ViewController类通信 当我运行应用程序时,QWebView会加载带有外部JS和CSS的HTML。我能够通过主程序线程和ViewController类与Javascript函数交互 一旦用户选择了一个目录并且满足了某些条件,它就开始一次一个地循环执行一个不可命名的任务

我有一个运行PyQt4的Python 2.7应用程序,其中有一个QWebView,它与Javascript之间有双向通信

该应用程序是通过QThreadPool、QRunnables进行多线程处理的,因此我正在使用信号与ViewController类通信

当我运行应用程序时,QWebView会加载带有外部JS和CSS的HTML。我能够通过主程序线程和ViewController类与Javascript函数交互

一旦用户选择了一个目录并且满足了某些条件,它就开始一次一个地循环执行一个不可命名的任务。在此期间,它通过信号槽调用ViewController->Javascript,正如预期的那样。问题是当我调用那些执行evaluateJavaScript的ViewController方法时,返回了一个Javascript错误

未定义的第1行:语法错误:分析错误

我反复尝试了很多错误,但似乎不明白evaluateJavaScript为什么不能在这些实例中运行。我尝试过发送简单的Javascript调用,从不接受任何参数的测试函数(认为这可能是一些奇怪的编码问题)到只发送诸如
Application.main.evaluateJavaScript(“alert('foo')”)
,它们通常在线程之外工作。我唯一能想到的另一件事是,可能需要在线程中再次调用
self.main.addToJavaScriptWindowObject('view',self.view)
,但我在Application.main上运行了一个dir(),它似乎已经附加了evaluateJavaScript方法

当范围看起来是正确的,并且ViewController与QWebView的通信似乎很好时,您有没有想过为什么会发生这种情况?Qt C++中的答案可能也会起作用,如果你以前见过这种情况的话!p> 出于示例目的,我尝试简化代码:

# coding: utf8
import subprocess as sp

import os.path, os, sys, time, datetime
from os.path import basename
import glob

import random
import string

from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.QtCore import QObject, pyqtSlot, QThreadPool, QRunnable, pyqtSignal
from PyQt4.QtGui import QApplication, QFileDialog
from PyQt4.QtWebKit import QWebView
from ImportController import *


class Browser(QtGui.QMainWindow):

    def __init__(self):

        QtGui.QMainWindow.__init__(self)
        self.resize(800,500)
        self.centralwidget = QtGui.QWidget(self)

        self.mainLayout = QtGui.QHBoxLayout(self.centralwidget)
        self.mainLayout.setSpacing(0)
        self.mainLayout.setMargin(0)

        self.frame = QtGui.QFrame(self.centralwidget)

        self.gridLayout = QtGui.QVBoxLayout(self.frame)
        self.gridLayout.setMargin(0)
        self.gridLayout.setSpacing(0)

        self.html = QtWebKit.QWebView()

        # for javascript errors
        errors = WebPage()
        self.html.setPage(errors)

        self.main = self.html.page().mainFrame()
        self.gridLayout.addWidget(self.html)
        self.mainLayout.addWidget(self.frame)
        self.setCentralWidget(self.centralwidget)

        path = os.getcwd()

        if self.checkNetworkAvailability() and self.checkApiAvailbility():
            self.default_url = "file://"+path+"/View/mainView.html"
        else:
            self.default_url = "file://"+path+"/View/errorView.html"

        # load the html view
        self.openView()

        # controller class that sends and receives to/from javascript
        self.view = ViewController()
        self.main.addToJavaScriptWindowObject('view', self.view)

        # on gui load finish
        self.html.loadFinished.connect(self.on_loadFinished)

    # to javascript

    def selectDirectory(self):
        # This evaluates the directory we've selected to make sure it fits the criteria, then parses the XML files
        pass


    def evaluateDirectory(self, directory):

        if not directory:
            return False

        if os.path.isdir(directory):
            return True
        else:
            return False

    @QtCore.pyqtSlot()
    def on_loadFinished(self):

        # open directory select dialog
        self.selectDirectory()

    def openView(self):

        self.html.load(QtCore.QUrl(self.default_url))
        self.html.show()

    def checkNetworkAvailability(self):
        #TODO: make sure we can reach the outside world before trying anything else
        return True

    def checkApiAvailbility(self):
        #TODO: make sure the API server is alive and responding
        return True


class WebPage(QtWebKit.QWebPage):
    def javaScriptConsoleMessage(self, msg, line, source):
        print '%s line %d: %s' % (source, line, msg)

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

    @pyqtSlot()
    def did_load(self):
        print "View Loaded."

    @pyqtSlot()
    def selectDirectoryDialog(self):
        # FROM JAVASCRIPT: in case they need to re-open the file dialog
        Application.selectDirectory()

    def prepareImportView(self, displayPath):
        # TO JAVASCRIPT: XML directory parsed okay, so let's show the main
        Application.main.evaluateJavaScript("prepareImportView('{0}');".format(displayPath))

    def generalMessageToView(self, target, message):
        # TO JAVASCRIPT: Send a general message to a specific widget target
        Application.main.evaluateJavaScript("receiveMessageFromController('{0}', '{1}')".format(target, message))


    @pyqtSlot()
    def startProductImport(self):
        # FROM JAVASCRIPT: Trigger the product import loop, QThreads
        print "### view.startProductImport"
        position = 1
        count = len(Application.data.products)

        importTasks = ProductImportQueue(Application.data.products)
        importTasks.start()

    @pyqtSlot(str)
    def updateProductView(self, data):
        # TO JAVASCRIPT: Send product information to view
        print "### updateProductView "
        Application.main.evaluateJavaScript('updateProductView("{0}");'.format(QtCore.QString(data)) )


class WorkerSignals(QObject):
    ''' Declares the signals that will be broadcast to their connected view methods '''
    productResult = pyqtSignal(str)

class ProductImporterTask(QRunnable):
    ''' This is where the import process will be fired for each loop iteration '''
    def __init__(self, product):
        super(ProductImporterTask, self).__init__()

        self.product = product
        self.count = ""
        self.position = ""
        self.signals = WorkerSignals()

    def run(self):
        print "### ProductImporterTask worker {0}/{1}".format(self.position, self.count)

        # Normally we'd create a dict here, but I'm trying to just send a string for testing purposes
        self.signals.productResult.emit(data)

        return

class ProductImportQueue(QObject):
    ''' The synchronous threadpool that is going to one by one run the import threads '''
    def __init__(self, products):
        super(ProductImportQueue, self).__init__()

        self.products = products
        self.pool = QThreadPool()
        self.pool.setMaxThreadCount(1)

    def process_result(self, product):
        return

    def start(self):
        ''' Call the product import worker from here, and format it in a predictable way '''

        count = len(self.products)
        position = 1
        for product in self.products:

            worker = ProductImporterTask("test")

            worker.signals.productResult.connect(Application.view.updateProductView, QtCore.Qt.DirectConnection)
            self.pool.start(worker)
            position = position + 1

        self.pool.waitForDone()




if __name__ == "__main__":

    app = QtGui.QApplication(sys.argv)
    Application = Browser()
    Application.raise_()
    Application.show()
    Application.activateWindow()
    sys.exit(app.exec_())

你知道,我喜欢PyQt4,但在搜索了又搜索之后,我相信这实际上是一个bug,而不是设计的那样


此后,我继续前进,并尝试使用WxPython在CEFPython中实现这一点,对于这一特定目的,它似乎有一个更优雅的实现。

你知道,我喜欢PyQt4,但在搜索和搜索之后,我相信这实际上是一个bug,而不是设计出来的

此后,我继续前进,并尝试使用WxPython在CEFPython中实现这一点,对于这一特定目的,WxPython似乎有一个更优雅的实现