3

I want to call PyQGIS API from my standalone Python script, outside QGIS environment. I can not, as 'iface' is not available. I have done necessary import / initialization :

from qgis.core import * 
from qgis.gui import *

    # supply path to where is your qgis installed 
QgsApplication.setPrefixPath("/path/to/qgis/installation", True)

# load providers 
QgsApplication.initQgis()

But I canot call, addVectorLayer(), QgsMapVectorLayer(), QgsMapVectorRegistry.instance()

I have marathon through the internet for searching to access iface variable to access PYQGIS API, but got no answer. In developer cookbook assumes Python console inside QGIS environment.

Can I do this?


My Main Purpose to Develope " Desktop Standalone Application "

A Mainwindow with a QGSCanvas : for displaying Map Mainwindow must have support of menu, on menu actions different windo/GUI will be launched Map should should be interactive: read and writing with map, zoom,pan etc, creating feature: polygon, line etc

In my mainwindow QTwidget object promoted to QGSMapCanvas have been used. On which i want to display map, perform query, add layers etc

QT as Front end Design and PyQGIS as displaying,querying map.

import sys,os
from qgis.core import *
from qgis.gui import *
from PyQt5.QtCore import *
from PyQt5 import QtGui, QtWidgets, uic
from PyQt5.QtGui import *




# Environment variable QGISHOME must be set to the install directory
# before running the application
qgis_prefix = os.getenv("QGISHOME")

class Ui(QtWidgets.QMainWindow):
    def __init__(self):
        super(Ui, self).__init__()
        uic.loadUi('MainMenu.ui', self)
        self.setWindowTitle("Standalone Desktop Application")
        self.show() 


        self._mks=None
        self._mkb=None
        self._mkw=None
        self._mka=None

        # Find & connect Menu1
        self.item1 = self.findChild(QtWidgets.QAction, 'menuItem1')
        self.item1.triggered.connect(self.showGUI1) # Remember to pass the definition/method, not the return value!

        # Find & connect  Menu2
        self.item2 = self.findChild(QtWidgets.QAction, 'menuItem2')
        self.item2.triggered.connect(self.showGUI2) # Remember to pass the definition/method, not the return value!

        # Find & connect Menu3
        self.item3 = self.findChild(QtWidgets.QAction, 'menuItem3')
        self.item3.triggered.connect(self.showGUI3) # Remember to pass the definition/method, not the return value!



        # Find & connect Menu4
        self.item4 = self.findChild(QtWidgets.QAction, 'menuItem4')
        self.item4.triggered.connect(self.showGUI4) # Remember to pass the definition/method, not the return value!      


        # Find canvas object
        self.canvas = self.findChild(QgsMapCanvas, 'canvas')
        self.canvas.enableAntiAliasing(True) 

        # Load A Test Vector layer and display in canvas
        self.loadGISLayer()

    def showGUI1(self):
        # This is executed when the menu item is pressed
        print(' GUI 1 To be Launched')
        self._mks=showUI1()
        self._mks.show()

    def showGUI2(self):
        # This is executed when the menu item is pressed
        print(' GUI 2 To be Launched')
        self._mkb=showUI2()
        self._mkb.show()

    def showGUI3(self):
        # This is executed when the menu item is pressed
        print(' GUI 3 To be Launched')
        self._mkw=showUI3()
        self._mkw.show()

    def showGUI4(self):
        # This is executed when the menu item is pressed
        print('  GUI 4 To be Launched')
        self._mka=showUI4()
        self._mka.show()



# Class for UI1
class showUI1(QtWidgets.QMainWindow):

    def __init__(self):
        super(showUI1, self).__init__()
        uic.loadUi('UI1.ui', self)


# Class for UI2
class showUI2(QtWidgets.QMainWindow):

    def __init__(self):
        super(showUI2, self).__init__()
        uic.loadUi('UI2.ui', self)

# Class for UI3
class showUI3(QtWidgets.QMainWindow):

    def __init__(self):
        super(showUI3, self).__init__()
        uic.loadUi('UI3.ui', self)           


# Class for UI4
class showUI4(QtWidgets.QMainWindow):

    def __init__(self):
        super(showUI4, self).__init__()
        uic.loadUi('UI4.ui', self)           



app = QtWidgets.QApplication(sys.argv)
QgsApplication.setPrefixPath(qgis_prefix)
QgsApplication.initQgis()

print(qgis_prefix)
print("------------------------------------------------")
print(QgsApplication.showSettings())

window = Ui()
app.exec_()

//////////////////////////////////////////////////////////////////////////////

Setting

@

ECHO OFF 

set OSGEO4W_ROOT=C:\Program Files\QGIS 3.8
set QGISHOME=C:\Program Files\QGIS 3.8\apps\qgis\
rem set PATH=%OSGEO4W_ROOT%\bin;%PATH% 
rem set PATH=%PATH%;%OSGEO4W_ROOT%\apps\qgis\bin

@echo off 
call "%OSGEO4W_ROOT%\bin\o4w_env.bat" 
call "%OSGEO4W_ROOT%\bin\qt5_env.bat" 
call "%OSGEO4W_ROOT%\bin\py3_env.bat" 
@echo off 
path %OSGEO4W_ROOT%\apps\qgis\bin;%OSGEO4W_ROOT%\apps\grass\grass76\lib;%OSGEO4W_ROOT%\apps\grass\grass76\bin;%PATH%
set QGIS_PREFIX_PATH=%OSGEO4W_ROOT:\=/%/apps/qgis
set GDAL_FILENAME_IS_UTF8=YES
rem Set VSI cache to be used as buffer, see #6448
set VSI_CACHE=TRUE
set VSI_CACHE_SIZE=1000000
set QT_PLUGIN_PATH=%OSGEO4W_ROOT%\apps\qgis\qtplugins;%OSGEO4W_ROOT%\apps\qt5\plugins
set PYTHONPATH=%OSGEO4W_ROOT%\apps\qgis\python;%PYTHONPATH%
rem "%PYTHONHOME%\python" %*

cd /d %~dp0

start cmd

///////////////////////////////////////////////////////////////////////////////

Versions:

Windows 10 Pro
QGIS 3.8 ZANZIBAR  ( & corressponding PyQGIS version)
UI Developed with QT Designer (bundeled with QGIS)
Python Version: 3.7.0, QT Version: 5.11.2

/////////////////////////////////////////////////////////////////////////////////

  • Welcome to GIS:SE @KrisanuRoy! Are you using QGIS 3.x? If so, you can import iface using from qgis.utils import iface. Also, could you please edit your question to include some of the sources you looked at? There are batch files available which lets you set the relevant paths accordingly which are useful before running standalone scripts. – Joseph Nov 1 '19 at 11:24
  • @Joseph from qgis.utils import iface was available in QGIS 2 too. But in his case, he is outside of QGIS, so there is no access to iface. And it seems logical to me, because iface represent the main QGIS dialog app. – etrimaille Nov 2 '19 at 17:24
  • In an standalone application there is no iface, because it represents big parts of the QGIS-GUI and you don't have that in a standalone application, see API: QgsInterface. If you want interactivity with the map canvas you can use QActions, those specific to MapCanves are part of the pyqgis-API, i think. – Andreas Müller Nov 5 '19 at 10:36
  • You may read this, it shows the use of mapcanvas and tools. – Andreas Müller Nov 5 '19 at 10:47
2

I'm not the QGIS Standalone application expert, but it seems logical to me that you can't access the iface variable, because it represents the QGIS Dialog, but your are in a standalone application, without the QGIS DIalog by definition.

Side note, in your question, you are referring to QgsMapVectorLayer and QgsMapVectorRegistry which doesn't exist. I guess you are talking about QgsVectorLayer. The QgsMapLayerRegistry has been removed since QGIS 3: https://gis.stackexchange.com/a/244467/24505 If you are still using QGIS 2, I suggest you to update to QGIS 3.4 which the LTR version.

So to add a layer, you can use addMapLayer from QgsProject: https://qgis.org/pyqgis/master/core/QgsProject.html?highlight=project#qgis.core.QgsProject.addMapLayer

Here is a example of a dialog showing a point.

#!/usr/bin/env python3

from qgis.core import (
    QgsApplication, QgsVectorLayer, QgsProject, QgsFeature, QgsGeometry)
from qgis.gui import QgsMapCanvas, QgsLayerTreeMapCanvasBridge
from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout


class MyDialog(QDialog):

    def __init__(self, parent):
        QDialog.__init__(self)
        self.parent = parent
        self.setLayout(QVBoxLayout())

        project = QgsProject()
        canvas = QgsMapCanvas()
        bridge = QgsLayerTreeMapCanvasBridge(
            project.layerTreeRoot(),
            canvas
        )
        bridge.setCanvasLayers()
        self.layout().addWidget(canvas)

        layer = QgsVectorLayer(
            'Point?'
            'crs=epsg:4326&'
            'field=id:integer&field=name:string(20)&index=yes',
            'layer', 'memory')

        feature = QgsFeature()
        feature.setGeometry(QgsGeometry.fromWkt('POINT(10 10)'))
        feature.setAttributes([1, 'Point'])
        layer.startEditing()
        layer.addFeature(feature)
        layer.commitChanges()
        layer.updateExtents()
        project.addMapLayer(layer)
        canvas.zoomToFullExtent()
        self.exec_()


if __name__ == '__main__':
    QgsApplication.setPrefixPath('/application/path/to/adapt', True)
    application = QgsApplication([], True)
    application.initQgis()
    dialog = MyDialog(application)
    application.exitQgis()

The bridge makes the link between your QgsProject and your QgsMapCanvas. So you when you add a layer in project, it displayed in the map canvas.

  • I shall post detailed code, environment setting path and version of software used. Thank you very much – Krisanu Roy Nov 3 '19 at 6:19
  • Does it answer your initial question? If yes, can you vote for the answer? If no, can you elaborate what is missing? Are you indeed on QGIS 2 pr something else? – etrimaille Nov 3 '19 at 11:31
  • My Main Purpose to Develope " Desktop Standalone Application " A Mainwindow with a QGSCanvas : for displaying Map Mainwindow must have support of menu, on menu actions different windo/GUI will be launched Map should should be interactive: read and writing with map, zoom,pan etc, creating feature: polygon, line etc In my mainwindow QTwidget object promoted to QGSMapCanvas have been used. On which i want to display map, perform query, add layers etc QT as Front end Design and PyQGIS as displaying,querying map. – Krisanu Roy Nov 5 '19 at 5:44
  • Detailed Question posted . – Krisanu Roy Nov 5 '19 at 5:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.