[GIS] Accessing iface PyQGIS API from Standalone Python script (outside QGIS environment)

pyqgis

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

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

Best Answer

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.

Related Question