Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Connecting signal to slot from custom widget

Connecting signal to slot from custom widget

Scheduled Pinned Locked Moved Unsolved Qt for Python
8 Posts 2 Posters 1.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    MicVak
    wrote on last edited by
    #1

    I am trying to connect a signal to a slot when data is entered into a custom widget class:

    class LineTabWidget(QWidget):
        lineDataUpdated = pyqtSignal(dict)
    
        def checkAndEmitAllData(self):
            if (self.node1XInput.text() and self.node1YInput.text() and self.node1ZInput.text() and
                self.node2XInput.text() and self.node2YInput.text() and self.node2ZInput.text() and
                self.elementLengthInput.text()):
    
                # Prepare the data
                lineData = {
                    'line_name': self.tabName,
                    'start_pos': {'x': self.node1XInput.text(), 'y': self.node1YInput.text(), 'z': self.node1ZInput.text()},
                    'end_pos': {'x': self.node2XInput.text(), 'y': self.node2YInput.text(), 'z': self.node2ZInput.text()},
                    'element_length': self.elementLengthInput.text()
                }
                
                # Save comprehensive line data
                self.saveLineData(lineData)
    
                # Emit the signal with all data
                self.emitLineData(lineData)
                print(f"Signal emitted and data saved {lineData}")
    

    The data (dictionary) should be emitted to a controller which connects it to a slot:

    class GUIController:
        """Controller class for the GUI. Connects signals to slots and handles the application logic."""
    
            self.gui.linetabwidget.lineDataUpdated.connect(self.handleLineDataUpdated)
    
    
    
    
        def handleLineDataUpdated(self, lineData):
            print(f'Line data handled: {lineData}')
            start_pos = (float(lineData['start_pos']['x']), float(lineData['start_pos']['y']), float(lineData['start_pos']['z']))
            end_pos = (float(lineData['end_pos']['x']), float(lineData['end_pos']['y']), float(lineData['end_pos']['z']))
            element_length = float(lineData['element_length'])
            print(start_pos, end_pos, element_length)
            # Call the method in MainGUI
            self.gui.lineVTK(lineData['line_name'], start_pos, end_pos, element_length)
    

    This approach has been working for other widgets like my custom Treeview, etc, with QActions and such.. I do get print statements that the signal is emitted with the dictionary in it, but it does not seem like handleLineDataUpdated is initiated when the signal is emitted (it is not connected to the slot)..

    Anyone know why?

    1 Reply Last reply
    0
    • M Offline
      M Offline
      MicVak
      wrote on last edited by
      #2

      I forgot the function for emitting the data:

      def emitLineData(self, lineData):
          self.lineDataUpdated.emit(lineData)
      
      JonBJ 1 Reply Last reply
      0
      • M MicVak

        I forgot the function for emitting the data:

        def emitLineData(self, lineData):
            self.lineDataUpdated.emit(lineData)
        
        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #3

        @MicVak
        I'm staring at this. In the self.lineDataUpdated.emit(lineData) how is the self.lineDataUpdated the same instance as the self.gui.linetabwidget.lineDataUpdated which has the connect(self.handleLineDataUpdated) connection?

        1 Reply Last reply
        0
        • M Offline
          M Offline
          MicVak
          wrote on last edited by
          #4

          The LineTabWidget is initiated in another part of the code, the MainGUI class (main window).

          class MainGUI(QMainWindow):
          
                  self.linetabwidget = LineTabWidget()
          

          Thus referred to gui.linetabwidget in the controller class. This should establish a connection between the lineDataUpdated signal of the LineTabWidget instance (self.gui.linetabwidget.lineDataUpdated) and the method (self.handleLineDataUpdated) designed to handle the data when the signal is emitted.

          JonBJ 1 Reply Last reply
          0
          • M Offline
            M Offline
            MicVak
            wrote on last edited by MicVak
            #5

            This is a working example:

            class GUIController:
                """Controller class for the GUI. Connects signals to slots and handles the application logic."""
                def __init__(self, gui):
                    self.gui = gui
                    # Connect signals to slots
            
                    # Opening tabs in console from Treeview
            
                    self.gui.treeview.openElementCB31InterfaceRequested.connect(self.openGUIElementCB31Tab)
            
                def openGUIElementCB31Tab(self):
                    self.gui.openElementCB31Tab()
            

            and my custom Treeview class:

            class MyTreeView(QTreeView):
                """This class defines a custom tree view widget used in the MainGUI class that emits signals to the controller."""
            
               openElementCB31InterfaceRequested = pyqtSignal()  # Define signal for opening element CB31 interface tab in console
            
                def __init__(self, parent=None):
                    super(MyTreeView, self).__init__(parent)
            
                def onItemDoubleClicked(self, index):
                    item = self.model().itemFromIndex(index)
                    if item:
                        itemName = item.text()
                        # Use .startswith() to check if the item name starts with "Line"
                        if itemName.startswith('Line'):
                            self.openLineInterfaceRequested.emit()
                        # Use .startswith() to check if the item name starts with "CB31"
                        elif itemName.startswith('CB31'):
                            self.openElementCB31InterfaceRequested.emit()
            

            and my MainGUI class:

            class MainGUI(QMainWindow):
                """This class controls the main window of the application.
                   It contains the main layout and widgets."""
            
                    # Setup custom TreeView
                    self.treeview = MyTreeView()
            
                def openElementCB31Tab(self):
            
            1 Reply Last reply
            0
            • M MicVak

              The LineTabWidget is initiated in another part of the code, the MainGUI class (main window).

              class MainGUI(QMainWindow):
              
                      self.linetabwidget = LineTabWidget()
              

              Thus referred to gui.linetabwidget in the controller class. This should establish a connection between the lineDataUpdated signal of the LineTabWidget instance (self.gui.linetabwidget.lineDataUpdated) and the method (self.handleLineDataUpdated) designed to handle the data when the signal is emitted.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #6

              @MicVak said in Connecting signal to slot from custom widget:

              self.linetabwidget = LineTabWidget()

              This creates a new one and I don't see how that is the same as "Thus referred to gui.linetabwidget in the controller class". You may be right but you not have not shown a minimal example which demonstrates this.

              If you have created a connection, you know the signal is fired and (it appears) the slot is not called then it seems to me the first thing to verify is that you are sure of the instances involved for signal and slot. Do a quick setObjectName(const QString &name) on both objects to make sure, at least for me?

              If you want to rule out for sure anything about passing the dict parameter then temporarily remove this parameter from the signal and the slot. Because you are claiming the signal is emitted but the slot is not called, aren't you?

              M 1 Reply Last reply
              0
              • JonBJ JonB

                @MicVak said in Connecting signal to slot from custom widget:

                self.linetabwidget = LineTabWidget()

                This creates a new one and I don't see how that is the same as "Thus referred to gui.linetabwidget in the controller class". You may be right but you not have not shown a minimal example which demonstrates this.

                If you have created a connection, you know the signal is fired and (it appears) the slot is not called then it seems to me the first thing to verify is that you are sure of the instances involved for signal and slot. Do a quick setObjectName(const QString &name) on both objects to make sure, at least for me?

                If you want to rule out for sure anything about passing the dict parameter then temporarily remove this parameter from the signal and the slot. Because you are claiming the signal is emitted but the slot is not called, aren't you?

                M Offline
                M Offline
                MicVak
                wrote on last edited by
                #7

                @JonB

                I set:

                class GUIController:
                    """Controller class for the GUI. Connects signals to slots and handles the application logic."""
                    def __init__(self, gui):
                        self.gui = gui
                        print(f"LineTabWidget instance name: {self.gui.linetabwidget.objectName()}")
                

                and:

                class LineTabWidget(QWidget):
                    lineDataUpdated = pyqtSignal(dict)
                
                    def __init__(self, parent=None, tabName=""):
                        super(LineTabWidget, self).__init__(parent)
                        self.setObjectName("lineTabWidget")
                

                which prints:

                LineTabWidget instance name: lineTabWidget

                I also removed the dict from the signal and added a new slot for handleLineDataUpdated that should only print if it recived signal. Nothing.

                Atleast, when input is given to the LineTabWidget in the GUI i get:

                Signal emitted and data saved {'line_name': 'Line 1 Model 1', 'start_pos': {'x': '0', 'y': '0', 'z': '0'}, 'end_pos': {'x': '20', 'y': '0', 'z': '0'}, 'element_length': '2'}

                from

                        # Emit the signal with all data
                        self.emitLineData(lineData)
                        print(f"Signal emitted and data saved {lineData}")
                
                JonBJ 1 Reply Last reply
                0
                • M MicVak

                  @JonB

                  I set:

                  class GUIController:
                      """Controller class for the GUI. Connects signals to slots and handles the application logic."""
                      def __init__(self, gui):
                          self.gui = gui
                          print(f"LineTabWidget instance name: {self.gui.linetabwidget.objectName()}")
                  

                  and:

                  class LineTabWidget(QWidget):
                      lineDataUpdated = pyqtSignal(dict)
                  
                      def __init__(self, parent=None, tabName=""):
                          super(LineTabWidget, self).__init__(parent)
                          self.setObjectName("lineTabWidget")
                  

                  which prints:

                  LineTabWidget instance name: lineTabWidget

                  I also removed the dict from the signal and added a new slot for handleLineDataUpdated that should only print if it recived signal. Nothing.

                  Atleast, when input is given to the LineTabWidget in the GUI i get:

                  Signal emitted and data saved {'line_name': 'Line 1 Model 1', 'start_pos': {'x': '0', 'y': '0', 'z': '0'}, 'end_pos': {'x': '20', 'y': '0', 'z': '0'}, 'element_length': '2'}

                  from

                          # Emit the signal with all data
                          self.emitLineData(lineData)
                          print(f"Signal emitted and data saved {lineData}")
                  
                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #8

                  @MicVak said in Connecting signal to slot from custom widget:

                  LineTabWidget instance name: lineTabWidget

                  Since you have put code in the constructor to always set the name of any LineTabWidget created to be lineTabWidget this tells us nothing.

                  If you wish to post a minimal example of reproducible problem I will try it. "Minimal" means I can just copy & paste a box of lines and it runs. No external .uis or anything like that. The fewest lines possible which exhibits the behaviour. If it's hundreds of lines then someone else may choose to look at it.

                  BTW: I think it will make no difference, and is not relevant here, but just in case mark the slot with the @pyqtSlot attribute to make sure that is not an issue.

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved