Date: 2014-11-30 21:09
Summary: 本文記錄了使用Python進行QGIS二次開發(fā)的過程按摘,以及過程中遇到的問題。由于內(nèi)容較多,將文章分成2個部分。這是第一部分弥锄。
使用Python進行QGIS二次開發(fā)1
最近在做QGIS二次開發(fā),支持C++和Python蟆沫。綜合各種原因籽暇,考慮選擇使用Python語言。在開發(fā)過程中遇到不少坑饭庞,費了不少勁戒悠,也總結(jié)了很多經(jīng)驗教訓。在此以一些代碼為例舟山,簡單分享一下QGIS二次開發(fā)過程中的種種問題绸狐。注意:本人開發(fā)的是獨立程序,而不是QGIS插件捏顺。
主要內(nèi)容
1. 環(huán)境配置
QGIS最新版本到了2.6六孵,但是其官方文檔還停留在2.2纬黎。抱著好奇的心態(tài)先裝了一下2.6熟悉了一番幅骄,準備進行開發(fā)時候遇到了第一個坑,2.6中帶的Python啟動報錯本今,缺少模塊拆座!沒辦法,看到文檔是2.2版本冠息,就想著按著文檔來吧挪凑,于是又裝了2.2。但是事實證明這次出bug的地方是另一處(后面會詳細介紹)逛艰。還好中間有個2.4的版本躏碳,再有bug的話真是考慮換平臺了。幸虧這個2.4版本能用散怖。
網(wǎng)上講環(huán)境配置大多數(shù)是用C++開發(fā)菇绵,python開發(fā)的比較少肄渗。Python開發(fā)環(huán)境的搭建主要是一些包所在的路徑要寫到環(huán)境變量中才能找到。這里遇到的困難就是環(huán)境變量中的路徑該怎么寫咬最?QGIS在2.x之后加入了不少內(nèi)容翎嫡,路徑和以前的已經(jīng)完全不一樣了,最可惡的是官方文檔中竟然都有錯誤的永乌。就像下圖中惑申,左側(cè)是官方文檔給出的路徑,右側(cè)是實際的路徑翅雏,完全匹配不上叭ν铡!M浮碗脊!
只好自己摸索著前進了。最終配置好的環(huán)境如下:
操作系統(tǒng):Win7 64位sp1 virtual box虛擬機
-
環(huán)境變量設(shè)置:
QGISDIR=D:/Program Files (x86)/QGIS Chugiak
QGIS_PREFIX=%QGISDIR%/apps/qgis
PATH=%QGISDIR%/bin;%QGISDIR%/apps/qgis/bin;(后面是原內(nèi)容)
PYTHONPATH=%QGISDIR%/apps/Python27/Lib/site-packages;%QGISDIR%/apps/qgis
GDAL_DATA=%QGISDIR%/share/gdal (QGIS在加載數(shù)據(jù)集的時候橄妆,需要找GDAL中的配置文件衙伶,所以需要這個) 開發(fā)環(huán)境:Pycharm 3.4
代碼管理:github
環(huán)境配好以后打開命令行,輸入python啟動python解釋器害碾,然后輸入:
>>> import PyQt4.QtCore
>>> import PyQt4.QtGui
>>> import qgis.core
>>> import qgis.gui
>>>
如果沒有錯誤的話矢劲,就說明環(huán)境配置OK。
2. 使用Qt界面
這部分主要就是PyQt的使用了慌随。關(guān)于PyQt國內(nèi)外也有很多教程可以參考.PyQt的使用和Qt的使用類似芬沉,只是某些地方不一樣。有一本書Rapid GUI Programming with Python and Qt就是專門講這個的阁猜,感興趣的可以在網(wǎng)上搜一下丸逸。這篇帖子是一個很好的介紹Python開發(fā)QGIS的資料,不過實用的版本都比較老了剃袍,我也是從這里開始的黄刚。下面對其中的一些關(guān)鍵點進行解釋。
2.1 使用Qt Designer來設(shè)計界面
Qt Designer是開發(fā)Qt程序的圖形界面民效°疚可以通過拖拽直接在上面放置Widget進行界面設(shè)計,很方便畏邢。最后會得到ui文件和qrc文件业扒。
2.2 編譯ui和rc文件
設(shè)計完成之后要在PyQt里面用起來的話,還需要一個編譯的過程舒萎。使用下面的命令進行編譯:
pyuic4 -o filename_gui.py filename.ui
purcc4 -o filename_rc.py filename.qrc
需要注意的是程储,-o參數(shù)指定的是輸出文件,filename所使用的文件名一定要是一樣的,并且后綴_gui和_rc一定要加章鲤,因為_gui文件的最后會import加后綴_rc的文件致板。否則就會找不到。
2.3 QGIS應(yīng)用開發(fā)
這里以ShapeViewer為例咏窿,主窗口代碼如下:
class ShapeViewer(QMainWindow, Ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
# Required by Qt4 to initialize the UI
self.setupUi(self)
# Set the title for the app
self.setWindowTitle("ShapeViewer")
# Create the map canvas
self.canvas = QgsMapCanvas()
self.canvas.show()
self.canvas.setCanvasColor(QColor(255,255,255))
self.canvas.enableAntiAliasing(True)
# Lay our widgets out in the main window using a
# vertical box layout
self.layout = QVBoxLayout(self.frame)
self.layout.addWidget(self.canvas)
# layout is set - open a layer
# Add an OGR layer to the map
file = QFileDialog.getOpenFileName(self,
"Open Shapefile", ".", "Shapefiles (*.shp)")
fileInfo = QFileInfo(file)
# Add the layer
layer = QgsVectorLayer(file, fileInfo.fileName(), "ogr")
if not layer.isValid():
return
# Add layer to the registry
QgsMapLayerRegistry.instance().addMapLayer(layer);
# Set extent to the extent of our layer
self.canvas.setExtent(layer.extent())
# Set up the map canvas layer set
cl = QgsMapCanvasLayer(layer)
layers = [cl]
self.canvas.setLayerSet(layers)
下面做一些簡要的解釋:
- 首先調(diào)用setupUi斟或,這是Qt中固定的模式
- 新建QgsMapCanvas對象,并調(diào)用show使其顯示集嵌,設(shè)置背景顏色為白色(默認是黑色的)萝挤,并且開啟抗鋸齒效果
- 使用QVBoxLayout來進行縱向的布局
- 打開一個shp文件作為矢量圖層,使用的是gdal里面提供的ogr
- QgsMapLayerRegistry相當于是一個圖層管理器根欧,所有的圖層都要加到里面去
- 使用setExtent函數(shù)來設(shè)置MapCanvas的可視范圍
- 使用setLayerSet來給MapCanvas設(shè)置進行渲染的圖層
入口函數(shù)和啟動Qt程序的代碼如下:
def main(argv):
# create Qt application
app = QApplication(argv)
# Initialize qgis libraries
QgsApplication.setPrefixPath(qgis_prefix, True)
QgsApplication.initQgis()
# create main window
wnd = ShapeViewer()
# Move the app window to upper left
wnd.move(100,100)
wnd.show()
# run!
retval = app.exec_()
# exit
QgsApplication.exitQgis()
sys.exit(retval)
if __name__ == "__main__":
main(sys.argv)
解釋幾點:
- 要注意QGIS的使用方法怜珍。設(shè)置prefix,進行初始化凤粗,最后在程序退出之前QGIS也要退出酥泛。
- qgis_prefix變量一定要設(shè)置正確。因為QGIS和以前版本組織文件的方法已經(jīng)不同了嫌拣,本人試了幾次柔袁,該變量的值就是前面設(shè)置的QGIS_PREFIX環(huán)境變量的值,可以直接取出來用异逐。
有幾點需要注意:
- QgsMapLayerRegistry的作用相當于是一個圖層管理器捶索,并且提供了添加和刪除的接口;QgsMapCanvas中的LayerSet是用來進行渲染的圖層的集合灰瞻,在動態(tài)添加和刪除圖層的時候要注意這兩者的區(qū)別和使用方法腥例。
- QGIS2.2地圖控件中有bug:程序啟動之后必須先失去一下焦點,然后才能顯示出地圖內(nèi)容酝润,這是已知的一個bug(http://gis.stackexchange.com/questions/87841/why-qgsmapcanvas-only-appear-after-lost-focus?rq=1)燎竖,所以避開了2.2的版本。畢竟是開源軟件要销,可以理解构回。