9

I have a plugin with a function (triggered by a button) that selects a specific layer by name, then shows its attribute table. When I close the plugin and open it again, the attribute table pops up twice, and repeating this keeps adding another table popup.

What's wrong?

Code:

def showTable(self):
    for lyrs in QgsMapLayerRegistry.instance().mapLayers().values():
        if lyrs.name() == "TestFeatures":
            lyrTest = lyrs
    self.iface.showAttributeTable(lyrTest)

3 Answers 3

12

You are probably setting a connection between a SIGNAL (button clicked) and a SLOT (your method showTable) every time your plugin is open (run() method?) and you are not disconnecting such SIGNAL/SLOT when your plugin is closed. This leads to a new call to showTable() every time you open your plugin, because there's a new connection calling it.

A couple of solutions for this problem are to:

  • Disconnect your SIGNAL/SLOT when closing the plugin; or (recommended)
  • Set your connection only in the initGui() method of your plugin, this way a new connection won't be set when opening your plugin, but only when initializing QGIS (or reloading the whole plugin).
1
  • How do you get access to the dialog elements (like buttons) within the initGui() method ? In my case, the QDialog object is instantiated when run() (default behavior from Plugin builder) callback is executed. Can you provide an example of a minimal working initGui() method following your advice ? (I know this answer is 7 years old but it feels like this thread is still relevant)
    – Beinje
    Jul 25, 2022 at 13:18
3

The problem can be that you have created your dialog with qt designer and there is already defined slot and you have defined it again in your code. Remove button.accepted.connect from your code.

1

Assuming you've used PluginBuilder, I used a try/catch block to disconnect the signal/slot combo and eliminated the problem on my end. This was done under the run(self): function, where it first checks if it's the first time starting the dialog:

    if self.first_start == True:
        self.first_start = False
        self.dlg = YourPluginDialog()

Then, directly underneath it, once first_start becomes False, I added an else statement to run a try/catch block:

    else:
        try:
            self.dlg.runButton.clicked.disconnect(self.yourFunction)
        except TypeError:
        # Already disconnected
            pass

Note that I did not use the default OK/Cancel buttons to run my function; I simply used a clicked.connect(self.myFunction) in the run(self) method outside of the dialog event loop.

Hope this helps.

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.