当前位置: 首页 > 工具软件 > QtWebKit > 使用案例 >

pyqt通过qtwebkit嵌入显示html与js

郑宜民
2023-12-01

转自: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的模组很容易,只要如此宣告:

1from PyQt4.QtCore import *
2from PyQt4.QtGui import *
3from PyQt4.QtWebKit import *

在这个范例,笔者设想的操作情境为,展示如何透过WebKit显示HTML element与JavaScript,以及透过iframe tag嵌入Google首页,在使用者互动的部份,透过Javascript建立对话框,并试着与Python的程式通讯。于是,我们建立一个class 来专门描绘网页,程式码如下:

1class BrowserScreen(QWebView):
2def __init__(self):
3QWebView.__init__(self)
4 
5self.resize(800, 600)
6self.show()
7self.setHtml("""
8<script>function message() { return "Clicked!"; }</script>
9<h1>QtWebKit + Python sample program</h1>
10<input type="button" value="Click JavaScript!"
11onClick="alert('1 ' + message())"/>
12<input type="button" value="Click Python!"
13onClick="python.alert('1 ' +
14python.message())"/>
15<br />
16<iframe src="http://www.google.com/"
17width="750" height="500"
18scrolling="no"
19frameborder="0"
20align="center"></iframe>
21""")

我们定义的class继承自QtWebKit中的class QWebView,在初始化时,即呼叫resize(), show(), setHTML()等method。此外,与其说上述程式列表为Python程式语言,不如说就是HTML网页原始码。熟悉网页程式设计者,一眼就可发现 我们在两个input button上建立Javascript事件关联,其中一个呼叫alert() method来显示对话框,而另一个则比较特别:

1onClick="python.alert('1 ' +
2python.message())

这边的”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程式码:

1class PythonJS(QObject):
2__pyqtSignals__ = ("contentChanged(const QString &)")
3@pyqtSignature("QString")
4def alert(self, msg):
5self.emit(SIGNAL('contentChanged(const QString &)'), msg)
6 
7@pyqtSignature("", result="QString")
8def message(self):
9return "Click!"

这个名为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,程式码如下:

1class BrowserScreen(QWebView):
2def __init__(self):
3QWebView.__init__(self)
4 
5self.createTrayIcon()
6...
7self.trayIcon.show()
8 
9def createTrayIcon(self):
10self.trayIcon = QSystemTrayIcon(self)
11self.trayIcon.setIcon(QIcon("images/trash.svg"))
12 
13def showMessage(self, msg):
14self.trayIcon.showMessage("This is Python", msg,
15QSystemTrayIcon.MessageIcon(0), 15 * 1000)

BrowserScreen::createTrayIcon() method透过class QSystemTrayIcon要求系统配置system tray,笔者设定了SVG图档(向量绘图,所以不需要考虑显示端的空间尺寸),而BrowserScreen::showMessage() method看似不相关,仅是显示讯息的动作,稍后,我们可透过Qt的Signals-Slots,将QtWebKit中的DOM/JavaScript 事件与此method给予”connect”起来。

最后一个部份,就是画龙点睛了,以下是main程式列表:

1if __name__=='__main__':
2import sys
3 
4app = QApplication(sys.argv)
5 
6browser = BrowserScreen()
7pjs = PythonJS()
8browser.page().mainFrame().addToJavaScriptWindowObject("python", pjs)
9 
10QObject.connect(pjs, SIGNAL("contentChanged(const QString &)"),
11browser.showMessage)
12 
13sys.exit(app.exec_())

重点当然是从前面两个class建立Python物件,也就是”browser”与”pjs”,整个程式最巧妙之处,就在于以下这行:

1browser.page().mainFrame().addToJavaScriptWindowObject(
2"python", pjs)

这也是QtWebKit技术的「火力展示」,原来前面的HTML列表的JavaScript程式的”python”物件,就是甫建立的”pjs”物件,而下一行也充满着惊喜:

1QObject.connect(pjs, SIGNAL("contentChanged(const QString &)"),
2browser.showMessage)

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


 类似资料: