7

I am trying to get the ids of the objects of my selection. The list should be ordered from my first selected object to the last selected object.

I do not have much experience with using SIGNAL and currently, I am using selectionChanged.connect which prints out any changes in the selection and shows the orders I wish. However, I cannot assign these ids in order to further use them (the id's).

The user should ideally select the objects one by one and if multiple objects are selected in one action, it should throw an error.

Is there any way I could do this?

  • 1
    Just to make sure I understand correctly what you want. If you first are selecting the object with id 5, then the object with id 3 and at last the object with id 10, you want to have the list [5,3,10]? What should happen if you select more objects in one operation? – MortenSickel Feb 24 at 9:27
  • @MortenSickel yes, you understand correctly. Actually, I want the user to select the objects one by one. So if more objects are selected in one operation, it should throw an error. – jugoslaviaa Feb 24 at 9:30
9

Use this script:

selection = []

def selection_changed(selected, deselected, clearAndSelect):
    global selection

    # If the user deselects feature(s), remove ID's from list
    if deselected:
        selection = [ID for ID in selection if ID not in deselected]
        print(f"Selection: {selection}")
    else: 
        # get newly selected IDs
        new_selected = list(set(selected) - set(selection))
        print(new_selected)

        # if multiple objects are selected, deselect them and warn the user
        if len(new_selected) > 1:
            print("Select just one item!")
            iface.activeLayer().deselect(new_selected)
            return

        # if one object is selected, add its ID to list
        selection.extend(new_selected)
        print(f"Selection: {selection}")

iface.activeLayer().selectionChanged.connect(selection_changed)

Note that selectionChanged doesn't work all layers. I mean after running the script, if you select another layer, you should run the script for that layer, too.

enter image description here

|improve this answer|||||
3

I do something similiar in my stripchartplugin at https://github.com/sickel/qgisstripchart/blob/master/stripchart.py

When I initiate, I define an array:

self.selectlines=[]

I set up a signal:

self.iface.mapCanvas().selectionChanged.connect(self.markselected)

and in self.markselected I can do

sels=self.view.layer.selectedFeatures()

where self.view.layer is set elsewhere and is the layer I am working on and compare sels with self.selectlines

For my purposes, the sorting of the lists does not matter, but what you can do is probably to

  1. check the length of sels compared to self.selectlines, if it is more than one longer, thrown an error - if it is shorter, well you have to decide. (see below)

  2. if len(sels) - len(self.selectlines) == 1, check which elements in sels that is not in self.selectlines and append it.

The difficulty comes in if a user does something unexpected - they always will do - e.g. if a user has selected 10 items, deselects everything and reselects 11 other items - you need to be able to handle that.

(the solution will probably be to check if there is more than one item that is in sels that is not in self.selectlines, throw an error if so - but how tho check it is more general Python than QGIS)

|improve this answer|||||

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.