Search code examples
pythonpyqtsignalssignals-slotspyqtgraph

Cannot connect slot to pqtgraph InfiniteLine signal with connectSlotsByName


I'm using the following code to call a function whenever the infinite line is dragged. It does not call the function.

    import sys
    import pyqtgraph as pg
    from PyQt5.QtCore import pyqtSlot as Slot, Qt, QMetaObject
    
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    
    class MyMainWindow(QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent=parent)
    
            self.setGeometry(300, 300, 400, 300)
            self.setWindowTitle('Hello World')
    
            self.plot_widget = pg.PlotWidget()
            self.plot_item = self.plot_widget.plot([1,0,2], pen='b', name='p0')
            self.vline = pg.InfiniteLine(movable=True, angle=90)
            self.vline.setObjectName('vline')
            self.plot_widget.addItem(self.vline)
            self.setCentralWidget(self.plot_widget)
            
            QMetaObject.connectSlotsByName(self)
            
        @Slot(object)
        def on_vline_sigDragged(self, obj):
            print('dragged')
            
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        ui = MyMainWindow()
        ui.show()
        sys.exit(app.exec_()) 

But when I assign the slot manually via

    self.vline.sigDragged.connect(self.on_vline_sigDragged)

it works fine.

Why is that so?


Solution

  • The connectSlotsByName function searches recursively for matching child objects, but vline isn't a descendant of the main window:

    for child in self.findChildren(QObject):
        print(child, f'name: {child.objectName()!r}')
    
    # output:
    
    <PyQt5.QtWidgets.QLayout object at 0x71a2f40fa320> | NAME: '_layout'
    <pyqtgraph.widgets.PlotWidget.PlotWidget object at 0x71a2f4262050> | NAME: ''
    <PyQt5.QtWidgets.QWidget object at 0x71a2f40fa3b0> | NAME: 'qt_scrollarea_hcontainer'
    <PyQt5.QtWidgets.QScrollBar object at 0x71a2f40fa440> | NAME: ''
    <PyQt5.QtWidgets.QBoxLayout object at 0x71a2f40fa560> | NAME: ''
    <PyQt5.QtWidgets.QWidget object at 0x71a2f40fa5f0> | NAME: 'qt_scrollarea_vcontainer'
    <PyQt5.QtWidgets.QScrollBar object at 0x71a2f40fa680> | NAME: ''
    <PyQt5.QtWidgets.QBoxLayout object at 0x71a2f40fa710> | NAME: ''
    <PyQt5.QtWidgets.QWidget object at 0x71a2f42620e0> | NAME: ''
    <pyqtgraph.GraphicsScene.GraphicsScene.GraphicsScene object at 0x71a2f4262290> | NAME: ''
    <PyQt5.QtCore.QObject object at 0x71a2f40fa7a0> | NAME: ''
    <PyQt5.QtWidgets.QAction object at 0x71a2f4262320> | NAME: ''
    

    So a simple fix would be to explicitly set the parent of the relevant object:

    ...
    self.vline.setObjectName('vline')
    self.vline.setParent(self)