Memanggil fungsi PyQGIS dari editor eksternal (Linux)

8

Apakah mungkin untuk mengintegrasikan editor Python eksternal (seperti KDevelop) dengan QGIS, sehingga mungkin untuk menjalankan fungsi di qgis.core, qgis.utilsdll. Di luar QGIS Python Console?

Mengikuti pedoman di situs web QGIS ( http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/intro.html ), saya mencoba ini, tetapi hanya mengembalikan 1 dan tidak ada yang lain:

import sys
sys.path.append('/usr/share/qgis/python')
import qgis.core
import qgis.utils

app = qgis.core.QgsApplication([], True)
qgis.core.QgsApplication.initQgis()
qgis.utils.iface.addVectorLayer("testing.shp", "anewlayer", "ogr") 
aLayer = qgis.utils.iface.activeLayer()
print aLayer.name()

Seperti:

$ LD_LIBRARY_PATH=/usr/lib64/qgis/ python qgis-test.py && echo "OK" || echo "Died"
Died

Saya menjalankan openSUSE Tumbleweed, 64-bit.

GreatEmerald
sumber

Jawaban:

8

Saya menggunakan pengantar berikut untuk aplikasi yang berdiri sendiri:

# the_app.py
import os
import sys

from qgis.core import *
from PyQt4.QtGui import *     

def main():
    QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'], True)
    QgsApplication.initQgis()

    # app specific code
    ...

    QgsApplication.exitQgis()
    sys.exit(result)

if __name__ == '__main__':
    main()

Ketika aplikasi tidak memerlukan GUI (mis. Lakukan beberapa geoproses), ganti elipsis dengan sesuatu seperti itu:

# app specific code (console)
print 'starting test'
layer1 = QgsVectorLayer('LineString', 'anewlayer', 'memory')
print layer.isValid()
QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
print 'layer added to map layer registry'
aLayer = QgsMapLayerRegistry.instance().mapLayersByName('anewlayer')[0]
print aLayer.name()

Untuk bekerja dengan satu atau lebih layer Anda tidak perlu menambahkannya ke map layer registry, cukup rujuk dengan nama variabel mereka (di sini layer1).

Ketika Anda menggunakan GUI, misalnya jendela mapper, ini akan menjadi kelas python yang berasal dari QMainWindow, biasanya dirancang dengan QtDesigner. Ellipsis harus diganti dengan kode seperti pada contoh berikut:

# app specific code (GUI)
app = QApplication(sys.argv)

# create gui window
window = Main()
window.show() 

result = app.exec_()
app.deleteLater()

Untuk menguji pendekatan ini tanpa benar-benar memiliki GUI coba versi konsol yang dimodifikasi ini:

# app specific code (GUI ready)
app = QApplication(sys.argv)

layer1 = QgsVectorLayer('LineString', 'anewlayer', 'memory')
QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
aLayer = QgsMapLayerRegistry.instance().mapLayersByName('anewlayer')[0]
print aLayer.name()

app.qApp.quit()

result = app.exec_()
app.deleteLater()

Ini hampir sama dengan versi konsol (karena sebenarnya tidak ada objek grafis), tetapi anggap quit()yang menghentikan aplikasi.

Untuk memulai aplikasi semacam itu di Linux:

#!/bin/sh
export PYTHONPATH="/usr/share/qgis/python"
export LD_LIBRARY_PATH="/usr/lib64/qgis"
export QGIS_PREFIX="/usr"
python the_app.py

Dan pada mesin Windows:

SET OSGEO4W_ROOT=D:\OSGeo4W64
SET QGISNAME=qgis
SET QGIS=%OSGEO4W_ROOT%\apps\%QGISNAME%
SET QGIS_PREFIX=%QGIS%

CALL %OSGEO4W_ROOT%\bin\o4w_env.bat

SET PATH=%PATH%;%QGIS%\bin
SET PYTHONPATH=%QGIS%\python;%PYTHONPATH%

python the_app.py

GUI yang sangat mendasar mungkin terlihat seperti ini:

# hand-made window with simple toolbar
class Ui_DemoWindow(object):
    def setupUi(self, window):
        window.setWindowTitle('Demo')

        self.centralWidget = QWidget(window)
        self.centralWidget.setFixedSize(640, 480)
        window.setCentralWidget(self.centralWidget)
        window.move(0, 0)

        self.layout = QVBoxLayout()    
        self.layout.setContentsMargins(0, 0, 0, 0)    
        self.centralWidget.setLayout(self.layout)

        self.toolBar = QToolBar(window)
        window.addToolBar(Qt.TopToolBarArea, self.toolBar)

        # quit action
        self.actionQuit = QAction('Quit', window)
        self.actionQuit.setShortcut(QKeySequence.Quit)

        # do something, here call function to create some geometries
        self.actionCreateGeom = QAction('Geometry', window)

        # link action to GUI elements
        self.toolBar.addAction(self.actionQuit)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionCreateGeom)


class Main(QMainWindow, Ui_DemoWindow):

    def __init__(self):    
        QMainWindow.__init__(self)
        self.setupUi(self)

        self.canvas = QgsMapCanvas()
        self.layout.addWidget(self.canvas)

        self.connect(self.actionQuit, SIGNAL('triggered()'), self.quit) 
        self.connect(self.actionCreateGeom, SIGNAL('triggered()'), self.some_geoms) 

    # quick and dirty: create layer with some features, add layer
    # to map canvas, and zoom canvas to full view
    def some_geoms(self):
        layer = QgsVectorLayer('LineString', 'anewlayer', 'memory')
        # add some features
        prov = layer.dataProvider()
        feats = []
        feat = QgsFeature()
        feat.setGeometry(QgsGeometry().fromPolyline([QgsPoint(-1,1), QgsPoint(1, -1)]))
        feats.append(feat)
        prov.addFeatures(feats)
        layer.updateExtents()

        QgsMapLayerRegistry.instance().addMapLayer(layer)
        self.canvas.setLayerSet([QgsMapCanvasLayer(layer)])
        self.canvas.zoomToFullExtent()    

    def quit(self):
        qApp.quit() 

Bagaimana tampilannya setelah menekan tombol Geometri :

demo

Dimulai dengan contoh sederhana ini Anda mungkin ingin menerapkan widget legenda, dialog properti, dialog layer, perilaku seleksi dan pengeditan, dan sebagainya.

Detlev
sumber
Dengan menggunakan kode apa adanya, kode tidak macet lagi, tetapi menghasilkan skrip yang hanya berhenti di sana selamanya. Bahkan tidak dapat dihentikan dengan mengirim SIGINT, harus dihentikan dengan SIGKILL. Apakah saya masih melewatkan sesuatu?
GreatEmerald
Anda dapat menjalankan aplikasi yang berdiri sendiri DENGAN atau TANPA GUI. Ketika Anda memiliki GUI, maka GUI mendapatkan kontrol hingga diakhiri dengan berhenti (). Inisialisasi kelas GUI seperti itu akan menggantikan kode khusus #app dalam contoh saya. Jika Anda tidak memiliki GUI maka Anda tidak dapat menggunakan metode terkait GUI, seperti activeLayer (). Saya mengedit jawaban saya untuk memasukkan contoh.
Detlev
Saya mencoba itu (copy-paste bagian pertama dan memasukkan blok GUI bukan eliipsis), dan mendapat kesalahan ini:Traceback (most recent call last): File "test.py", line 25, in <module> main() File "test.py", line 15, in main window = Main() NameError: global name 'Main' is not defined
GreatEmerald
@GreatEmerald Main () harus menjadi contoh saja. Jika Anda telah membangun GUI dengan QtDesigner atau dari awal kemudian masukkan nama kelas ini sebagai gantinya. Karena saya tidak tahu persis lingkungan aplikasi Anda, saya menunjukkan prinsipnya
Detlev
1
@wondim Silakan lihat di gis.stackexchange.com/questions/40375/…
Detlev