转自:http://www.vouov.com/2009/09/pyqt%E9%80%9A%E8%BF%87qtwebkit%E5%B5%8C%E5%85%A5%E6%98%BE%E7%A4%BAhtml%E4%B8%8Ejs/
透过Python体验QtWebKit快速开发
转载:http://blog.linux.org.tw/~jserv/archives/002026.html
稍早写过一篇文章[QtWebKit:将Web 2.0技术带入行动通讯的系统设计],谈及Trolltech对于Qt Framework与WebKit的整合,提供独到的设计,不仅可很容易在应用程式中嵌入WebKit所带来的Web 2.0网路服务外,还可作无接缝(seamless)的整合。不过前文并未解说整合细节,这里就带出具体而微的范例,体验QtWebKit的技术突破与先 进的特征,恰好下个月要出席[PycTW2008],那么程式语言选用Python作为练习。
日前Trolltech正式释出Qt 4.4,业已整合QtWebKit,与Qt framework衔接的[PyQt]日前也推出v4.4.2,即可透过Python来释放QtWebKit的威力。 Qt framework一向最为人知的卖点就是”signals-slots”机制,自然在PyQt也少不了,而且还透过[SIP] Python模组,免去了许多语言层面的繁文缛节。首先,要存取PyQt的模组很容易,只要如此宣告:
1 | from PyQt4.QtCore import * |
2 | from PyQt4.QtGui import * |
3 | from PyQt4.QtWebKit import * |
在这个范例,笔者设想的操作情境为,展示如何透过WebKit显示HTML element与JavaScript,以及透过iframe tag嵌入Google首页,在使用者互动的部份,透过Javascript建立对话框,并试着与Python的程式通讯。于是,我们建立一个class 来专门描绘网页,程式码如下:
1 | class BrowserScreen(QWebView): |
我们定义的class继承自QtWebKit中的class QWebView,在初始化时,即呼叫resize(), show(), setHTML()等method。此外,与其说上述程式列表为Python程式语言,不如说就是HTML网页原始码。熟悉网页程式设计者,一眼就可发现 我们在两个input button上建立Javascript事件关联,其中一个呼叫alert() method来显示对话框,而另一个则比较特别:
1 | onClick = "python.alert( '1 ' + |
这边的”python.alert”与”python.message”就使用了PyQt + QtWebKit的专有功能,意思是按下button时,会呼叫python物件的message method,而这个”python”物件可动态在欲嵌入WebKit的Python程式中传入物件,当然,可有颇多变化。笔者这里仅作字串回传显示的动 作,不过即使如此,还是有两项技术细节要思考:
* QtWebKit的class QWebView,其最主要的目标是走访HTML个别element并描绘网页,也就是内部维护着DOM (Document Object Model),包含我们刚刚看见的那两个input button也在其中
* Javascript (或ECMAscript)内部有自己的字串与物件表示,Python也有字串,而Qt framework更有class QString,那么,该如何建立起彼此的关联呢?至少,在笔者设计的情境中,就得考虑字串与物件游走于这三方所需面对的议题
实际上,得面对的问题不只如此,不过QtWebKit + PyQt都帮我们处理掉,所以,笔者只要另行提供Python物件并交予QtWebKit即可。以下是传入到WebKit的物件相关的Python程式码:
1 | class PythonJS(QObject): |
2 | __pyqtSignals__ = ( "contentChanged(const QString &)" ) |
3 | @pyqtSignature ( "QString" ) |
5 | self .emit(SIGNAL( 'contentChanged(const QString &)' ), msg) |
7 | @pyqtSignature (" ", result=" QString") |
这个名为PythonJS的class,继承自class QObject。透过PyQt,我们宣告一个自订的signal: “contentChanged(const QString &)”,这不需要额外的moc compiler即可有对应的metadata关联。刚刚在class BrowserScreen的HTML程式列表中,所提及的”python.alert” method就定义于此,笔者依据Qt的Signals-Slot机制,去emit出”contentChanged(const QString &)”这个signal,并将alert() method后方的字串(const QString &型态)一并传出,也可见到PyQt中宣告msg参数型态为”QString”。同样,PythonJS::message method也是如此,依据上方的执行顺序来看,会先呼叫PythonJS::message()在将传回的QString字串透过QtWebKit内部 的转换,变成JavaScript的字串并作物件的合成动作(即”‘python’ + python.message()”陈述),并将得到的JavaScript字串传递给QtWebKit外部的Python物件,呼叫 PythonJS::alert() method,当然,这时候要将JavaScript字串转变成Pthon可处理的QString字串。
撰写了以上两个class,程式几乎完成了,只要将两者整合起来即可,为了增加视觉上的比较效果,笔者透过Qt 4.4提供的System Tray (在X11/FreeDesktop的术语为”Notification Area”)来作讯息显示的动作。所以修改了class BrowserScreen,追加两个method,程式码如下:
1 | class BrowserScreen(QWebView): |
9 | def createTrayIcon( self ): |
10 | self .trayIcon = QSystemTrayIcon( self ) |
11 | self .trayIcon.setIcon(QIcon( "images/trash.svg" )) |
13 | def showMessage( self , msg): |
14 | self .trayIcon.showMessage( "This is Python" , msg, |
15 | QSystemTrayIcon.MessageIcon( 0 ), 15 * 1000 ) |
BrowserScreen::createTrayIcon() method透过class QSystemTrayIcon要求系统配置system tray,笔者设定了SVG图档(向量绘图,所以不需要考虑显示端的空间尺寸),而BrowserScreen::showMessage() method看似不相关,仅是显示讯息的动作,稍后,我们可透过Qt的Signals-Slots,将QtWebKit中的DOM/JavaScript 事件与此method给予”connect”起来。
最后一个部份,就是画龙点睛了,以下是main程式列表:
1 | if __name__ = = '__main__' : |
4 | app = QApplication(sys.argv) |
6 | browser = BrowserScreen() |
8 | browser.page().mainFrame().addToJavaScriptWindowObject( "python" , pjs) |
10 | QObject.connect(pjs, SIGNAL( "contentChanged(const QString &)" ), |
重点当然是从前面两个class建立Python物件,也就是”browser”与”pjs”,整个程式最巧妙之处,就在于以下这行:
1 | browser.page().mainFrame().addToJavaScriptWindowObject( |
这也是QtWebKit技术的「火力展示」,原来前面的HTML列表的JavaScript程式的”python”物件,就是甫建立的”pjs”物件,而下一行也充满着惊喜:
1 | QObject.connect(pjs, SIGNAL( "contentChanged(const QString &)" ), |
class PythonJS所生的物件”pjs”里头的signal “contentChanged”被连结(connect)到class BrowserScreen所生的物件”browser”里头的slot “showMessage”,原本只是平淡无奇的PyQt叙述,但因为”pjs “物件被传入QtWebKit,WebKit所描绘的网页(范例即Google首页)有完整的DOM/JavaScript,依据之前的HTML程式列 表,已建立这两者的关联,如今,再将PyQt的事件一举打通。是此,Python/PyQt – QtWebKit – DOM/JavaScript的关联就建立了,咱们来体验看看,以下是操作时的图例:
在system tray多了一个绿色、类似资源回收桶的图样,而主画面就如预期,就是QtWebKit。是的,写UI就是这么简单,只要HTML tag加上iframe,顿时有声有色,为了要证明这不是纸老虎,咱们按一下左方的”Click Javascript!” input button,会得到下方萤幕输出:
这就是Javascript里头呼叫alert() method,展示了QtWebKit的基本能力,最后我们看看刚刚张罗许久的展示,当按下”Click Python!” input button后…
注意到system tray下方弹跳出黄色对话讯息,别小看这个,这可是历经Python/PyQt – QtWebKit – DOM/JavaScript等部份,显示于我们眼前的。我们也可发现,QtWebKit要与桌面整合并产生有效的互动,只需要上述这一些程式码即可,透 过Python体验QtWebKit快速开发,看来很棒呢。
取得上述程式码加上SVG图档: [pyqtwebkit-sample.tar.bz2],因为Qt framework与PyQt都以GNU GPL授权发行,本范例也是如此。
由jserv发表于May 21, 2008 10:01 PM