Aufrufen von PyQGIS-Funktionen von externen Editoren (Linux)

8

Ist es möglich , externen Python Editoren (wie KDevelop) zur Integration mit QGIS, so dass es möglich wäre , zu laufen Funktionen qgis.core, qgis.utilsusw. außerhalb der QGIS Python - Konsole?

Nach den Richtlinien auf der QGIS-Website ( http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/intro.html ) habe ich dies versucht, aber es wird nur 1 und nichts anderes zurückgegeben:

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()

Sowie:

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

Ich verwende openSUSE Tumbleweed, 64-Bit.

GreatEmerald
quelle

Antworten:

8

Ich verwende folgendes Intro für eigenständige Anwendungen:

# 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()

Wenn die App keine grafische Benutzeroberfläche benötigt (z. B. Geoverarbeitung), ersetzen Sie die Auslassungspunkte durch Folgendes:

# 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()

Um mit einem oder mehreren Layern zu arbeiten, müssen Sie sie nicht zur Registrierung der Map-Layer hinzufügen. Verweisen Sie einfach auf ihren Variablennamen (hier layer1).

Wenn Sie eine GUI verwenden, z. B. ein Mapper-Fenster, ist dies eine Python-Klasse, die von QMainWindow abgeleitet ist und normalerweise mit QtDesigner erstellt wird. Die Auslassungspunkte müssen wie im nächsten Beispiel durch Code ersetzt werden:

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

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

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

Um diesen Ansatz ohne GUI zu testen, versuchen Sie diese modifizierte Konsolenversion:

# 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()

Es ist fast das gleiche wie die Konsolenversion (da es eigentlich keine grafischen Objekte gibt), aber beachten Sie, quit()was die Anwendung stoppt.

So starten Sie eine solche App unter Linux:

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

Und auf einem Windows-Computer:

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

Eine sehr einfache Benutzeroberfläche kann folgendermaßen aussehen:

# 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() 

Wie es nach dem Drücken der Taste Geometrie aussieht :

Demo

Beginnend mit diesem einfachen Beispiel möchten Sie möglicherweise das Legenden-Widget, Eigenschaftsdialoge, Ebenendialoge, Auswahl- und Bearbeitungsverhalten usw. implementieren.

Detlev
quelle
Wenn Sie Ihren Code unverändert verwenden, stürzt er nicht mehr ab, führt jedoch dazu, dass das Skript dort für immer im Leerlauf bleibt. Es kann nicht einmal durch Senden von SIGINT gestoppt werden, es muss mit SIGKILL gestoppt werden. Vermisse ich noch etwas
GreatEmerald
Sie können eine eigenständige App MIT oder OHNE GUI ausführen. Wenn Sie eine GUI haben, erhält die GUI das Steuerelement, bis es mit einem quit () endet. Die Initialisierung einer solchen GUI-Klasse würde den # app-spezifischen Code in meinem Beispiel ersetzen. Wenn Sie keine GUI haben, können Sie keine GUI-bezogenen Methoden wie activeLayer () verwenden. Ich bearbeite meine Antwort, um ein Beispiel aufzunehmen.
Detlev
Ich habe das versucht (den ersten Teil kopiert und den GUI-Block anstelle der Eliipsis eingefügt) und diesen Fehler erhalten: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 () sollte nur ein Beispiel sein. Wenn Sie eine GUI mit QtDesigner oder von Grund auf neu erstellt haben, fügen Sie stattdessen diesen Klassennamen ein. Da ich Ihre genaue App-Umgebung nicht kenne, habe ich die Prinzipien gezeigt
Detlev
1
@wondim Bitte werfen Sie einen Blick auf gis.stackexchange.com/questions/40375/…
Detlev