pyqt: A correct way to connect multiple signals to the same function in pyqt (QSignalMapper not applicable)

前端 未结 2 1474
感情败类
感情败类 2021-01-03 05:23
  1. I\'ve ready many posts on how to connect multiple signals to the same event handler in python and pyqt. For example, connecting several buttons or comboboxes to the

相关标签:
2条回答
  • 2021-01-03 06:01

    It is simply untrue that an object cannot be deleted because a signal connection holds a reference in a closure. Qt will automatically remove all signal connections when it deletes an object, which will in turn remove the reference to the lambda on the python side.

    But this implies that you cannot always rely on Python alone to delete objects. There are two parts to every PyQt object: the Qt C++ part, and the Python wrapper part. Both parts must be deleted - and sometimes in a specific order (depending on whether Qt or Python currently has ownership of the object). In addition to that, there's also the vagaries of the Python garbage-collector to factor in (especially during the short period when the interpreter is shutting down).

    Anyway, in your specific example, the easy fix is to simply do:

        # wdg = None
        wdg.deleteLater()
    

    This schedules the object for deletion, so a running event-loop is required for it have any effect. In your example, this will also automatically quit the application (because the object is the last window closed).

    To more clearly see what's happening, you can also try this:

        #wdg = None
        wdg.deleteLater()
    
        app.exec_()
    
        # Python part is still alive here...
        print(wdg)
        # but the Qt part has already gone
        print(wdg.objectName())
    

    Output:

    <__main__.Widget object at 0x7fa953688510>
    Traceback (most recent call last):
      File "test.py", line 45, in <module>
        print(wdg.objectName())
    RuntimeError: wrapped C/C++ object of type Widget has been deleted
    deleted
    

    EDIT:

    Here's another debugging example that hopefully makes it even clearer:

        wdg = Widget()
        wdg.show()
    
        wdg.deleteLater()
        print 'wdg.deleteLater called'
    
        del wdg
        print 'del widget executed'
    
        wd2 = Widget()
        wd2.show()
    
        print 'starting event-loop'
        app.exec_()
    

    Output:

    $ python2 test.py
    wdg.deleteLater called
    del widget executed
    starting event-loop
    deleted
    
    0 讨论(0)
  • 2021-01-03 06:12

    in many cases the parameter carried by signal can be catched in another way, e.g. if an objectName is set for the sending object, so QSignalMapper can be used:

        self.signalMapper = QtCore.QSignalMapper(self)
        self.signalMapper.mapped[str].connect(myFunction)  
    
        self.combo.currentIndexChanged.connect(self.signalMapper.map)
        self.signalMapper.setMapping(self.combo, self.combo.objectName())
    
       def myFunction(self, identifier):
             combo = self.findChild(QtGui.QComboBox,identifier)
             index = combo.currentIndex()
             text = combo.currentText()
             data = combo.currentData()
    
    0 讨论(0)
提交回复
热议问题