5

I am redesigning my years old form for collecting data in ornithologic field surveys because I finally want to update my tablet for field work from QGIS 2.8 to QGIS 3.10. One attribute contains a short name (token) of the species, which has to be chosen from a list with about 160 possible values (I use a value relation so that I see the full name of the species in the list). As scrolling through such a long list is annoying and error-prone I want to write a python script, that adds the most used values at the top of the list in the dropdown box, divided from the following complete list by a separator. So in the vast majority of cases, I don't have to scroll down, but just expand the dropdown box and tap on one of the then visible items.

And I want the script to preselect the single most used value in the list, so that in quite some cases, I don't have to change the species at all.

The experience that I gathered when writing the first version of this script ( How to store attribute values from a custom form into shapefile? ) nearly faded away but with some searching and reading I managed to write a code for python 3, which does nearly what I want (see code at the end of this posting). The only remaining problem is, that the preselection of the most used value does not work (lines 56 to 58 in code).

Surprisingly (for me) it works, when I add an empty QMessageBox just before the command for selecting the value (see line 57 in the code: QMessageBox().exec_()). After closing the Message Box, The value is selected as I want it.

Do you know a way to make my dropdown box work as intended without the annoying MessageBox?

I am developing the form on my desktop computer with QGIS 3.10 under Windows 10 64 Bit

# -*- coding: utf-8 -*-
from qgis.PyQt.QtWidgets import QDialog, QComboBox, QMessageBox
from qgis.core import QgsFeature
def FormOpen(dialog, layer, feature):
 global SpeciesField, SpeciesDictionary
 global CurrentFeature
########################################################
# Set the desired number of "most used" species at the
# top of the list
 MostUsedListMax = 28
########################################################
 CurrentLayer = layer
 MyDialog = dialog
 CurrentFeature = QgsFeature( feature )
 SpeciesField = MyDialog.findChild( QComboBox , 'ART_KURZ' )
 SpeciesField.setMaxVisibleItems( MostUsedListMax )
# Initialization of objects on first run
 if not 'SpeciesDictionary' in globals():
 InitializeData()
# Reset all counter fields to zero 
 for d in SpeciesDictionary:
 SpeciesDictionary[ d ] = ( 0 , SpeciesDictionary[ d ][1] )
# Count the occurences of each species' token in the layer
 features = CurrentLayer.getFeatures()
 for f in features:
 SpeciesDictionary[ f.attribute('ART_KURZ') ] = ( SpeciesDictionary[ f.attribute('ART_KURZ') ][0] + 1 , SpeciesDictionary[ f.attribute('ART_KURZ') ][1] )
# Make a list of the most used tokens
 k = 0
 MostUsedList = []
 for item in sorted(SpeciesDictionary.items(), key=lambda item: item[1][0] , reverse=True ):
 if item[1][0] > 0:
 MostUsedList.append( ( item[1][1] , item[0] ))
 k += 1
 if k >= MostUsedListMax :
 break
# Insert the items of the "most used" list in alphabetical order
# at the top of the list in the combobox 
 for m in sorted( MostUsedList , reverse=True ):
 SpeciesField.insertItem( 0 , m[0] , m[1] )
# Insert a separator
 SpeciesField.insertSeparator( len( MostUsedList ) )
# If feature is new, set species token to most used value
 if CurrentFeature.attribute("ART_KURZ") is None:
 QMessageBox().exec_()
 SpeciesField.setCurrentText( MostUsedList[0][0] )
def InitializeData():
 global SpeciesField, SpeciesDictionary
# Create a dictionary for all species
# Structure of each item in the dictionary
# 'Species name token': ( 'Counter' , 'Species name complete' )
 SpeciesDictionary = {}
 for i in range( 0 , SpeciesField.count() ):
 SpeciesField.setCurrentIndex( i )
 SpeciesDictionary[ SpeciesField.currentData() ] = ( 0 , SpeciesField.currentText() )
Kadir Şahbaz
78.6k57 gold badges260 silver badges407 bronze badges
asked Apr 25, 2020 at 15:35
3
  • I tested the script in QGIS 3.10.1 under Windows 10 64 Bit, it worked. What is the full version of QGIS (3.10.**) ? Maybe it's a bug Commented Jun 7, 2020 at 4:01
  • I am using QGIS 3.10.6 Commented Jun 7, 2020 at 14:46
  • Does the script also work on your computer, if you outcomment the line "QMessageBox().exec_()" ? In this case it works here, only the preselection of the most used value does not. Commented Jun 7, 2020 at 14:47

1 Answer 1

5
+50

QGIS can use NULL values as field values. Python has no concept of NULL. Therefore, for ART_KURZ which has NULL value in QGIS, the following two lines return different results.

  • CurrentFeature.attribute("ART_KURZ") is None returns False. Because NULL is a different object.

  • not CurrentFeature.attribute("ART_KURZ") returns True.

In other words, NULL is None is False, not NULL is True in PyQGIS.

Use that way:

try:
 if not CurrentFeature.attribute("ART_KURZ") and len( MostUsedList ) > 0:
 SpeciesField.setCurrentText( MostUsedList[0][0] )
except KeyError as e:
 pass

DEMO:

enter image description here


NOTE:

== compares the values of the objects. But is compares the references (identity) of the objects (as held in memory).

  • NULL == None is True, because both have the same value.
  • NULL is None is False, because both have different objects in the memory.
  • Also NULL is None equals id(NULL) == id(None).
answered Jun 8, 2020 at 12:35
5
  • First let me thank you for your time!! :-)Yes, the Commented Jun 8, 2020 at 21:52
  • Yes, the most used species are inserted on top of the list - this part is fine. But Iwant the script to preselect the single most used species and this only works with the activated message box. I uploaded a zip-file with my test qgs.file and test data. If you want to, you can download the data under: dropbox.com/s/slihakbyd4p98ow/stackexchange.zip?dl=0 Thanks! Commented Jun 8, 2020 at 21:55
  • Sounds very good. I will try this this evening!!! Commented Jun 10, 2020 at 9:47
  • I had high hopes, that your hint might solve my problem, but the problem persists. :-( Without the message box, the preselection of the most used species does not work - instead the Dropdown box just shows the first value from the species list preloaded by QGIS ( "Abspielen Klangattrappe (AbspKl)" )! :-( Commented Jun 10, 2020 at 21:44
  • @oekoplaner I've added more explanation about NULL and None. Commented May 2, 2021 at 10:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.