I am currently trying to add logic to a custom form to key out a habitat code. This is for work using UK Habitat Classification. It is based on a 5 level hierarchical code to produce a Primary Code. Each level filters the options for the next layer.

What I have so far (I stopped at level 3):

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

Prime = None
L1Field = None
L2LField = None
L2CField = None
L3LField = None
L3CField = None

def formOpen(dialog,layerid,featureid):
    global Prime
    Prime = dialog.findChild(QLineEdit,"PRIME_COD")
    global L1Field
    L1Field = dialog.findChild(QComboBox,"L1")
    L1Field.currentIndexChanged.connect( L1Changed )
    global L2LField
    L2LField = dialog.findChild(QComboBox,"L2_LABEL")
    global L2CField
    L2CField = dialog.findChild(QLineEdit,"L2_CODE")
    L2LField.currentIndexChanged.connect( L2Changed )
    global L3LField
    L3LField = dialog.findChild(QComboBox,"L3_LABEL")
    global L3CField
    L3CField = dialog.findChild(QLineEdit,"L3_CODE")
    L3LField.currentIndexChanged.connect( L3Changed )

def L1Changed( value ):
    if L1Field.currentText() == 'Terrestrial':
        L2LField.addItems(["","Cropland","Grassland","Heathland and shrub","Sparsely vegetated land","Urban","Wetland","Woodland and forest"])
    elif L1Field.currentText() == 'Freshwater':
        L2LField.addItems(["Rivers and lakes"])
    elif L1Field.currentText() == 'Marine':
        L2LField.addItems(["Marine inlets and transitional waters"])

def L2Changed( value ):
    if L2LField.currentText() == 'Grassland':
        L2CField.setText( 'g' )
        L3LField.addItems(["","Acid grassland","Calcareous grassland","Neutral grassland","Modified grassland"])
    elif L2LField.currentText() == 'Woodland and forest':
        L2CField.setText( 'w' )
        L3LField.addItems(["","Broadleaved mixed and yew woodland","Coniferous woodland"])
    elif L2LField.currentText() == 'Heathland and shrub':
        L2CField.setText( 'h' )
        L3LField.addItems(["","Dwarf shrub heath","Hedgerows","Dense scrub"])
    elif L2LField.currentText() == 'Wetland':
        L2CField.setText( 'f' )
        L3LField.addItems(["","Bog","Fen marsh and swamp"])
    elif L2LField.currentText() == 'Cropland':
        L2CField.setText( 'c' )
        L3LField.addItems(["Arable and horticulture"])
    elif L2LField.currentText() == 'Urban':
        L2CField.setText( 'u' )
        L3LField.addItems(["Built-up areas and gardens"])
    elif L2LField.currentText() == 'Sparsely vegetated land':
        L2CField.setText( 's' )
        L3LField.addItems(["","Inland rock","Supralittoral Rock","Supralittoral Sediment"])
    elif L2LField.currentText() == 'Rivers and lakes':
        L2CField.setText( 'r' )
        L3LField.addItems(["","Standing open water and canals","Rivers and streams"])
    elif L2LField.currentText() == 'Marine inlets and transitional waters':
        L2CField.setText( 't' )
        L3LField.addItems(["","Littoral Rock","Littoral Sediment"])
        L2CField.setText( '' )

def L3Changed (value):
    if L3LField.currentText() == 'Acid grassland':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Calcareous grassland':
        L3CField.setText( '2' )
    elif L3LField.currentText() == 'Neutral grassland':
        L3CField.setText( '3' )
    elif L3LField.currentText() == 'Modified grassland':
        L3CField.setText( '4' )
    elif L3LField.currentText() == 'Broadleaved mixed and yew woodland':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Coniferous woodland':
        L3CField.setText( '2' )
    elif L3LField.currentText() == 'Dwarf shrub heath':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Hedgerows':
        L3CField.setText( '2' )
    elif L3LField.currentText() == 'Dense scrub':
        L3CField.setText( '3' )
    elif L3LField.currentText() == 'Bog':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Fen marsh and swamp':
        L3CField.setText( '2' )
    elif L3LField.currentText() == 'Arable and horticulture':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Built-up areas and gardens':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Inland rock':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Supralittoral Rock':
        L3CField.setText( '2' )
    elif L3LField.currentText() == 'Supralittoral Sediment':
        L3CField.setText( '3' )
    elif L3LField.currentText() == 'Standing open water and canals':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Rivers and streams':
        L3CField.setText( '2' )
    elif L3LField.currentText() == 'Littoral Rock':
        L3CField.setText( '1' )
    elif L3LField.currentText() == 'Littoral Sediment':
        L3CField.setText( '2' )
        L3CField.setText( '' )

I have made a simple form in Qt Designer to test this. Form

My code works but I feel is cumbersome and could be greatly simplified but I lack the knowledge how. I would like to reference a table with the values to simplify things. I think it needs to be a table rather than lists as the Label field value sets the Code value and the previous level Label controls the drill down function on the Label QComboBox.


Any help or recommendations to improve would be welcome.

N.B. I have not yet written the code to populate the Primary Field but this will be a concatenation of the L0CFields triggered on index change of any of these fields, I just haven't worked out how yet...

  • What data format is the table in? Are you wanting to know how to connect and query against it?
    – artwork21
    Apr 10, 2019 at 12:15
  • It can be in any format that will work, CSV or DBF is easiest for me. I have looked at panda but not sure if it is right for this application. I need to know how to connect/reference a table so I can bring the values over to populate QComboBoxes and QTextEdit fields live based on values defined in other fields.
    – P Dreyer
    Apr 11, 2019 at 11:54

1 Answer 1


To connect to a .csv using pyqgis you may use this method:

table = QgsVectorLayer('C:/Temp/Book1.csv', "table", "ogr")

To cursor through the records and columns use this method:

for record in table.getFeatures():
    print('L3_LABLE = {}, 'L3CODE = {}'.format(record['L3_LABLE'], record['L3_CODE']))
  • Thank you, I'm still not quite there with it yet but that's no doubt down to my total inexperience with scripting. I will plug away at it when I have time. Does the QgsVectorLayer address have to be absolute or can it be relative to the project file?
    – P Dreyer
    Apr 11, 2019 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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