Archive for the 'python' Category

pyqt 4与google map结合应用

九 09 2009 Published by under python,工具

最近学习pyqt,在网上搜索到了做Google map的,发现那个使用图片作为显示的,感觉那样很不方便,所以想以HTML显示.运用pyqt4的QWebView显示
第一步申请Google map api key,然后进行开发.
第二步,写个运用Google map api进行解析的工具 GoogleMapsUtil.py.代码如下:

import urllib

GMap_KEY_ID = 'YOUR GOOGLE MAP API KEY'

def getGMapsGEO(qaddr):
     geo_url = 'http://maps.google.com/maps/geo?'+urllib.urlencode({'q':qaddr})+'&output=csv&key='+GMap_KEY_ID
     gdata = urllib.urlopen(geo_url)
     gdataArray = gdata.read().split(',')
     return gdataArray

def getGMapsStaticUrl(Latitudes, Longitudes, zoom=14, width=512, height=512):
     #print "--"+str(Latitudes)+"--"+str(Longitudes)+"--"+str(zoom)
     map_url = 'http://maps.google.com/staticmap?center='+str(Latitudes)+','+str(Longitudes)+'&zoom='+str(zoom)+
         '&size='+str(width)+'x'+str(height)+'&maptype=mobile&key='+GMap_KEY_ID+'&sensor=false'
     return map_url

第三步,用qt designer拉出界面,然后转化为python代码,Ui_GoogleMaps.py 代码如下:

from PyQt4 import QtCore, QtGui

class Ui_DialogGoogleMaps(object):
    def setupUi(self, DialogGoogleMaps):
        DialogGoogleMaps.setObjectName("DialogGoogleMaps")
        DialogGoogleMaps.resize(773, 588)
        self.inputAddress = QtGui.QLineEdit(DialogGoogleMaps)
        self.inputAddress.setGeometry(QtCore.QRect(40, 30, 371, 20))
        self.inputAddress.setObjectName("inputAddress")
        self.labelAddress = QtGui.QLabel(DialogGoogleMaps)
        self.labelAddress.setGeometry(QtCore.QRect(10, 30, 31, 16))
        self.labelAddress.setObjectName("labelAddress")
        self.groupBoxMapCtrl = QtGui.QGroupBox(DialogGoogleMaps)
        self.groupBoxMapCtrl.setGeometry(QtCore.QRect(530, 40, 211, 121))
        self.groupBoxMapCtrl.setObjectName("groupBoxMapCtrl")
        self.ButtonUp = QtGui.QPushButton(self.groupBoxMapCtrl)
        self.ButtonUp.setGeometry(QtCore.QRect(90, 10, 31, 31))
        self.ButtonUp.setObjectName("ButtonUp")
        self.ButtonDown = QtGui.QPushButton(self.groupBoxMapCtrl)
        self.ButtonDown.setGeometry(QtCore.QRect(90, 90, 31, 31))
        self.ButtonDown.setObjectName("ButtonDown")
        self.ButtonLeft = QtGui.QPushButton(self.groupBoxMapCtrl)
        self.ButtonLeft.setGeometry(QtCore.QRect(30, 50, 31, 31))
        self.ButtonLeft.setObjectName("ButtonLeft")
        self.ButtonRight = QtGui.QPushButton(self.groupBoxMapCtrl)
        self.ButtonRight.setGeometry(QtCore.QRect(150, 50, 31, 31))
        self.ButtonRight.setObjectName("ButtonRight")
        self.ButtonZoom = QtGui.QPushButton(self.groupBoxMapCtrl)
        self.ButtonZoom.setGeometry(QtCore.QRect(70, 50, 31, 31))
        self.ButtonZoom.setObjectName("ButtonZoom")
        self.ButtonNarrow = QtGui.QPushButton(self.groupBoxMapCtrl)
        self.ButtonNarrow.setGeometry(QtCore.QRect(110, 50, 31, 31))
        self.ButtonNarrow.setObjectName("ButtonNarrow")
        self.MapView = QtWebKit.QWebView(DialogGoogleMaps)
        self.MapView.setGeometry(QtCore.QRect(10, 60, 512, 512))
        self.MapView.setUrl(QtCore.QUrl("http://maps.google.com/staticmap?center=32.0583650,118.7964680&zoom=14&size=512x512&maptype=mobile&markers=32.0583650,118.7964680&key=ABQIAAAApIB1Ubv-TkAKBJ37W0Hh2RS1AC4DxUbsxJ-9A5H8anlW8PhTrBQW71UJo3SK1Lm1LK_DZxfeCJessA&sensor=false"))
        self.MapView.setObjectName("MapView")
        self.BtnSearch = QtGui.QPushButton(DialogGoogleMaps)
        self.BtnSearch.setGeometry(QtCore.QRect(440, 30, 75, 23))
        self.BtnSearch.setObjectName("BtnSearch")
        self.ListAddress = QtGui.QListWidget(DialogGoogleMaps)
        self.ListAddress.setGeometry(QtCore.QRect(530, 200, 211, 371))
        self.ListAddress.setFrameShape(QtGui.QFrame.StyledPanel)
        self.ListAddress.setObjectName("ListAddress")
        QtGui.QListWidgetItem(self.ListAddress)
        QtGui.QListWidgetItem(self.ListAddress)
        self.label = QtGui.QLabel(DialogGoogleMaps)
        self.label.setGeometry(QtCore.QRect(530, 180, 54, 14))
        self.label.setObjectName("label")

        self.retranslateUi(DialogGoogleMaps)
        QtCore.QMetaObject.connectSlotsByName(DialogGoogleMaps)

    def retranslateUi(self, DialogGoogleMaps):
        DialogGoogleMaps.setWindowTitle(QtGui.QApplication.translate("DialogGoogleMaps", "Google maps应用程序", None, QtGui.QApplication.UnicodeUTF8))
        self.labelAddress.setText(QtGui.QApplication.translate("DialogGoogleMaps", "地址:", None, QtGui.QApplication.UnicodeUTF8))
        self.groupBoxMapCtrl.setTitle(QtGui.QApplication.translate("DialogGoogleMaps", "地图控制", None, QtGui.QApplication.UnicodeUTF8))
        self.ButtonUp.setText(QtGui.QApplication.translate("DialogGoogleMaps", "上", None, QtGui.QApplication.UnicodeUTF8))
        self.ButtonDown.setText(QtGui.QApplication.translate("DialogGoogleMaps", "下", None, QtGui.QApplication.UnicodeUTF8))
        self.ButtonLeft.setText(QtGui.QApplication.translate("DialogGoogleMaps", "左", None, QtGui.QApplication.UnicodeUTF8))
        self.ButtonRight.setText(QtGui.QApplication.translate("DialogGoogleMaps", "右", None, QtGui.QApplication.UnicodeUTF8))
        self.ButtonZoom.setText(QtGui.QApplication.translate("DialogGoogleMaps", "大", None, QtGui.QApplication.UnicodeUTF8))
        self.ButtonNarrow.setText(QtGui.QApplication.translate("DialogGoogleMaps", "小", None, QtGui.QApplication.UnicodeUTF8))
        self.BtnSearch.setText(QtGui.QApplication.translate("DialogGoogleMaps", "搜索", None, QtGui.QApplication.UnicodeUTF8))
        self.ListAddress.setSortingEnabled(False)
        __sortingEnabled = self.ListAddress.isSortingEnabled()
        self.ListAddress.setSortingEnabled(False)
        self.ListAddress.item(0).setText(QtGui.QApplication.translate("DialogGoogleMaps", "结果1", None, QtGui.QApplication.UnicodeUTF8))
        self.ListAddress.item(1).setText(QtGui.QApplication.translate("DialogGoogleMaps", "新建项目", None, QtGui.QApplication.UnicodeUTF8))
        self.ListAddress.setSortingEnabled(__sortingEnabled)
        self.label.setText(QtGui.QApplication.translate("DialogGoogleMaps", "搜索结果:", None, QtGui.QApplication.UnicodeUTF8))

from PyQt4 import QtWebKit

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    DialogGoogleMaps = QtGui.QDialog()
    ui = Ui_DialogGoogleMaps()
    ui.setupUi(DialogGoogleMaps)
    DialogGoogleMaps.show()
    sys.exit(app.exec_())

第四步:写界面的动作插槽,GoogleMapsExec.py,代码如下:

# -*- coding: utf-8 -*-

"""
Module implementing GoogleMapsExec.
"""
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QDialog
from PyQt4.QtCore import pyqtSignature

from Ui_GoogleMaps import Ui_DialogGoogleMaps

import GoogleMapsUtil

class GoogleMapsExec(QDialog, Ui_DialogGoogleMaps):
    """
    Class documentation goes here.
    """
    jindu = 32.058365
    weidu = 118.796468
    zoom = 14
    def __init__(self, parent = None):
        """
        Constructor
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)

    @pyqtSignature("")
    def on_ButtonUp_clicked(self):
        """
        Slot documentation goes here.
        """
        self.jindu =self.jindu-0.01
        GmapUrl = GoogleMapsUtil.getGMapsStaticUrl(self.jindu, self.weidu, self.zoom)
        self.MapView.setUrl(QtCore.QUrl(GmapUrl))

    @pyqtSignature("")
    def on_ButtonDown_clicked(self):
        """
        Slot documentation goes here.
        """
        self.jindu = self.jindu+0.01
        GmapUrl = GoogleMapsUtil.getGMapsStaticUrl(self.jindu, self.weidu, self.zoom)
        self.MapView.setUrl(QtCore.QUrl(GmapUrl))

    @pyqtSignature("")
    def on_ButtonLeft_clicked(self):
        """
        Slot documentation goes here.
        """
        self.weidu = self.weidu-0.01
        GmapUrl = GoogleMapsUtil.getGMapsStaticUrl(self.jindu, self.weidu, self.zoom)
        self.MapView.setUrl(QtCore.QUrl(GmapUrl))

    @pyqtSignature("")
    def on_ButtonRight_clicked(self):
        """
        Slot documentation goes here.
        """
        self.weidu = self.weidu+0.01
        GmapUrl = GoogleMapsUtil.getGMapsStaticUrl(self.jindu, self.weidu, self.zoom)
        self.MapView.setUrl(QtCore.QUrl(GmapUrl))

    @pyqtSignature("")
    def on_ButtonZoom_clicked(self):
        """
        Slot documentation goes here.
        """
        if self.zoom < 18:
             self.zoom = self.zoom+1
        else:
            return
        GmapUrl = GoogleMapsUtil.getGMapsStaticUrl(self.jindu, self.weidu, self.zoom)
        self.MapView.setUrl(QtCore.QUrl(GmapUrl))

    @pyqtSignature("")
    def on_ButtonNarrow_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        if self.zoom > 0:
             self.zoom = self.zoom-1
        else:
            return
        GmapUrl = GoogleMapsUtil.getGMapsStaticUrl(self.jindu, self.weidu, self.zoom)
        self.MapView.setUrl(QtCore.QUrl(GmapUrl))

    @pyqtSignature("")
    def on_BtnSearch_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        qaddr = self.inputAddress.text().toUtf8()
        center = GoogleMapsUtil.getGMapsGEO(qaddr)
        self.jindu = float(center[2])
        self.weidu = float(center[3])
        self.zoom = 14
        GmapUrl = GoogleMapsUtil.getGMapsStaticUrl(self.jindu, self.weidu, self.zoom)
        self.MapView.setUrl(QtCore.QUrl(GmapUrl))
        #QtGui.QListWidgetItem(self.ListAddress)
        #self.ListAddress.item(2).setText(QtGui.QApplication.translate("DialogGoogleMaps", "结果3", None, QtGui.QApplication.UnicodeUTF8))

    @pyqtSignature("QListWidgetItem*")
    def on_ListAddress_itemClicked(self, item):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        pass

    @pyqtSignature("")
    def on_ListAddress_itemSelectionChanged(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        pass

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    DialogGoogleMaps = GoogleMapsExec()
    DialogGoogleMaps.show()
    sys.exit(app.exec_())

第五步:这样你运行一下就可以看到最终的成果了.如图.呵呵:

可以在地址框里输入查询的地址,这个程序还没有完善好.怕自己忘记先记录下来吧.等有时间在加以完善.源代码在我的附件里.呵呵

googlemapsapp_pyqt4.zip

No responses yet

pyqt通过qtwebkit嵌入显示html与js

九 09 2009 Published by under python

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

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *

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

class BrowserScreen(QWebView):
def __init__(self):
QWebView.__init__(self)

self.resize(800, 600)
self.show()
self.setHtml("""
&lt;script&gt;function message() { return "Clicked!"; }&lt;/script&gt;
&lt;h1&gt;QtWebKit + Python sample program&lt;/h1&gt;
&lt;input type="button" value="Click JavaScript!"
onClick="alert('1 ' + message())"/&gt;
&lt;input type="button" value="Click Python!"
onClick="python.alert('1 ' +
python.message())"/&gt;
&lt;br /&gt;
&lt;iframe src="http://www.google.com/"
width="750" height="500"
scrolling="no"
frameborder="0"
align="center"&gt;&lt;/iframe&gt;
""")

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

onClick="python.alert('1 ' +
python.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程式码:

class PythonJS(QObject):
__pyqtSignals__ = ("contentChanged(const QString &amp;)")
@pyqtSignature("QString")
def alert(self, msg):
self.emit(SIGNAL('contentChanged(const QString &amp;)'), msg)

@pyqtSignature("", result="QString")
def message(self):
return "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,程式码如下:

class BrowserScreen(QWebView):
def __init__(self):
QWebView.__init__(self)

self.createTrayIcon()
...
self.trayIcon.show()

def createTrayIcon(self):
self.trayIcon = QSystemTrayIcon(self)
self.trayIcon.setIcon(QIcon("images/trash.svg"))

def showMessage(self, msg):
self.trayIcon.showMessage("This is Python", msg,
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程式列表:

if __name__=='__main__':
import sys

app = QApplication(sys.argv)

browser = BrowserScreen()
pjs = PythonJS()
browser.page().mainFrame().addToJavaScriptWindowObject("python", pjs)

QObject.connect(pjs, SIGNAL("contentChanged(const QString &amp;)"),
browser.showMessage)

sys.exit(app.exec_())

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

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

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

QObject.connect(pjs, SIGNAL("contentChanged(const QString &amp;)"),
browser.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

No responses yet

Eric4的中文设置

九 09 2009 Published by under python,工具

下载了中文包eric4-i18n-zh_CN.GB2312-4.3.6.zip,解压后,安装一闪,在Interface的语言设置里却没有中文选项。不用说没有安装成功.
上 网所了一下资料,手动将i18n目录下的eric4_zh_CN.GB2312.qm和eric4_zh_CN.GB2312.ts拷贝到 C:Python25Libsite-packageseric4i18n,然后在Interface的语言设置里有中文选项了.选中 ->应用->重启.然后就是以中文启动了.下面提供Eric4的中文包下载

eric4-i18n-zh_CN.GB2312-4.3.6.zip

2 responses so far