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

2024-09-30 05:28:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个python2.7应用程序,它使用PyQt4运行,其中有一个QWebView,它可以与Javascript进行双向通信。在

应用程序是通过QThreadPool,qrunables进行多线程处理的,所以我用信号与ViewController类通信。在

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

当用户在某个时间通过某个不可执行的目录选择一个不可执行的任务时,它就开始执行。在此期间,它通过信号槽回调ViewController->;Javascript,正如预期的那样。问题是,当我调用那些执行evaluateJavaScript的ViewController方法时,会返回一个Javascript错误

undefined line 1: SyntaxError: Parse error

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

当作用域看起来是正确的,而ViewController似乎与QWebView通信正常,那么为什么会发生这种情况呢?Qt C++中的答案可能也会起作用,如果你以前见过这种情况的话!在

我试图简化代码,以达到以下目的:

# 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_())

Tags: thetofromimportselfviewapplicationinit
1条回答
网友
1楼 · 发布于 2024-09-30 05:28:25

你知道,我很喜欢PyQt4,但是在搜索和搜索之后,我相信这实际上是一个bug,并不像设计的那样。在

从那以后,我一直在尝试用WxPython在CEFPython中实现这一点,对于这个特定的目的,它似乎有一个更优雅的实现。在

相关问题 更多 >

    热门问题