2013年6月9日 星期日

以 html5 撰寫 單機(離線)程式,以 pyside 與 qwebkit 為例。

    現在 html5 蔚為潮流,而 html5 也將觸手伸向單機程式。新的 html5 技術可以使用 ApplicationCache 來達成。而 XULRunner 又是令一個技術,讓你可以用寫網頁的方式來寫單機程式。用 pyside 加上 qwebkit 也可以達到類似的應用。事實上,pyside 加上 qwebkit 的作法不過是作個客製化瀏覽器而已。

    先看個簡單的範例。


#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
import os.path
from PySide import QtGui, QtCore, QtWebKit


class WebviewDemo(QtGui.QWidget):

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

        self.initUI()
        self.initEvent()
        self.initJavascriptEnv()

        self.web.page().mainFrame().javaScriptWindowObjectCleared.connect(
                self.initJavascriptEnv)

        path = os.path.dirname(__file__)
        self.web.load(QtCore.QUrl('file:///%s/demo.html' % path))

    def initUI(self):

        self.web = QtWebKit.QWebView()

        self.code_input_label = QtGui.QLabel("Code input: ")
        self.code_input = QtGui.QLineEdit()
        self.output_window = QtGui.QTextEdit()

        grid = QtGui.QGridLayout()

        grid.addWidget(self.web, 0, 0, 14, 10)
        grid.addWidget(self.code_input_label, 14, 0, 1, 1)
        grid.addWidget(self.code_input, 14, 1, 1, 9)
        grid.addWidget(self.output_window, 15, 0, 1, 10)

        self.setLayout(grid)

        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('WebviewDemo')
        self.show()

    def initEvent(self):
        self.code_input.returnPressed.connect(self.evalJavascript)

    @QtCore.Slot(result=str)
    def evalJavascript(self):
        ''' When user input javascript code in code_input and press enter,
        it will call the function.
        '''
        code = self.code_input.text()
        page = self.web.page()
        frame = page.currentFrame()
        # run javascript code and get result.
        result =frame.evaluateJavaScript(code)
        self.output_window.append(str(result) + '\n')

    def initJavascriptEnv(self):
        page = self.web.page()
        frame = page.mainFrame()
        # Add self object into javascript runtime.
        # So the "self" object  in javascript means the "self" instance in python.
        # Note: the "self"" objeect is maybe invalid after loading new url.
        # So check
        frame.addToJavaScriptWindowObject("self", self)

    # Any function which want to be called by javascript, it need to be wrapped by QtCore.Slot.
    # If You use C++ and Qt, you also need Q_INVOKABLE macro.
    @QtCore.Slot(result=str)
    def sayHello(self):
        print 'you call python function.'
        return 'hello'

    @QtCore.Slot(result=str)
    def submit(self):
        print 'sss'
        page = self.web.page()
        frame = page.currentFrame()
        user_input = frame.findFirstElement("#fullname").evaluateJavaScript("this.value")
        QtGui.QMessageBox.warning(self, "Qt Message Box", user_input)
        return ''




def main():
    app = QtGui.QApplication(sys.argv)
    widget =  WebviewDemo()
    widget.show()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

    從上面範例可以看到,如果你想在 python 裡執行 javascript code 很簡單。只要簡單的呼叫 evaluateJavaScript 函數即可。然而,想要從 javascript 呼叫 python 的函數麻煩一些。首先,你要先呼叫 addToJavaScriptWindowObject 來建立一個 javascript 的物件,那個物件是對應到一個 QObject。之後你就可以用那個 javascript 來呼叫該 QObject 的 slot 方法(只有 slot 方法可以被 javascript 呼叫,一般的 function 不行)。

沒有留言:

張貼留言