Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Convert SIGNAL to new Signal Format
Forum Updated to NodeBB v4.3 + New Features

Convert SIGNAL to new Signal Format

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 3 Posters 1.3k Views 2 Watching
  • 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
    mjs513
    wrote on 29 Apr 2023, 23:56 last edited by
    #1

    I am attempting to convert an application from PyQT4 and PyQt5 and I don't program much in Python or PyQT4 - know just enough to be dangerous. Alot of the errors I was able to already figure out but the more I look at Signal the more confused I get.

    Anyways. I have 3 specific uses of SIGNAL in the PyQT4 app:

    1. self.connect(self.serialPortEdit, SIGNAL("returnPressed()"), self.connectButton, SIGNAL("clicked()"))
    2. self.connect(self.serWorker, SIGNAL("new_data(PyQt_PyObject)"), self.newData)
    3. self.emit(SIGNAL("new_data(PyQt_PyObject)"), reading)

    Any help would be appreciated.

    Thanks
    Mike

    1 Reply Last reply
    0
    • M mjs513
      30 Apr 2023, 19:39

      @JonB
      Think I found the problem. Doing a search for serial worker I found that its actually a qthread class:

      class SerialWorker(QThread):
      
        def __init__(self, parent = None, ser = None):
          QThread.__init__(self, parent)
          self.exiting = False
          self.ser = ser
              
        def run(self):
          print ("sampling start..")
          self.acc_file = open(acc_file_name, 'w')
          self.magn_file = open(magn_file_name, 'w')
          count = 100
          in_values = 9
          reading = [0.0 for i in range(in_values)]
          # read data for calibration    
          while not self.exiting:
            # determine word size
            temp = 'b'
            self.ser.write(temp.encode())
            self.ser.write(chr(count))
            for j in range(count):
              for i in range(in_values):
                if word == 4:
                  reading[i] = unpack('hh', self.ser.read(4))[0]
                if word == 2:
                  reading[i] = unpack('h', self.ser.read(2))[0]            
              self.ser.read(2) # consumes remaining '\r\n'
              if reading[8] == 0:
                reading[6] = 1
                reading[7] = 1
                reading[8] = 1      
              # prepare readings to store on file
              acc_readings_line = "%d %d %d\r\n" % (reading[0], reading[1], reading[2])
              self.acc_file.write(acc_readings_line)
              magn_readings_line = "%d %d %d\r\n" % (reading[6], reading[7], reading[8])
              self.magn_file.write(magn_readings_line)
            # every count times we pass some data to the GUI
            #self.emit(SIGNAL("new_data(PyQt_PyObject)"), reading)
            self.new_data.emit(reading)
            print ("."),
          # closing acc and magn files
          self.acc_file.close()
          self.magn_file.close()
          return 
        
        def __del__(self):
          self.exiting = True
          self.wait()
          print( "SerialWorker exits..")
      

      I have been looking at
      https://www.pythontutorial.net/pyqt/pyqt-qthread/
      and
      https://www.pythonguis.com/tutorials/transmitting-extra-data-qt-signals/

      any suggestions or better way

      J Offline
      J Offline
      JonB
      wrote on 30 Apr 2023, 20:03 last edited by
      #9

      @mjs513 said in Convert SIGNAL to new Signal Format:

        #self.emit(SIGNAL("new_data(PyQt_PyObject)"), reading)
        self.new_data.emit(reading)
      

      Just as you have this for emitting the signal so for item #2 you need

      # self.connect(self.serWorker, SIGNAL("new_data(PyQt_PyObject)"), self.newData)
      self.serWorker.new_data.connect(self.newData)
      
      M 1 Reply Last reply 1 May 2023, 01:29
      0
      • J Offline
        J Offline
        jeremy_k
        wrote on 30 Apr 2023, 02:47 last edited by
        #2

        For reference: https://www.riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html#connecting-disconnecting-and-emitting-signals

        The syntax for connecting a signal is object.signalName.connect(slot). There are two alternatives mentioned in the Connecting Signals Using Keyword Arguments section.

        For the first example, it would be:
        self.serialPortEdit.returnPressed.connect(self.connectButton.clicked)

        Emit a signal via object.signalName.emit(args...). For example:
        self.new_data.emit(reading)

        Asking a question about code? http://eel.is/iso-c++/testcase/

        M 1 Reply Last reply 30 Apr 2023, 13:07
        3
        • J jeremy_k
          30 Apr 2023, 02:47

          For reference: https://www.riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html#connecting-disconnecting-and-emitting-signals

          The syntax for connecting a signal is object.signalName.connect(slot). There are two alternatives mentioned in the Connecting Signals Using Keyword Arguments section.

          For the first example, it would be:
          self.serialPortEdit.returnPressed.connect(self.connectButton.clicked)

          Emit a signal via object.signalName.emit(args...). For example:
          self.new_data.emit(reading)

          M Offline
          M Offline
          mjs513
          wrote on 30 Apr 2023, 13:07 last edited by
          #3

          @jeremy_k
          Thanks for getting back to me and making it a lot clearer on what has to change.

          I changed item 2 to:

          self.serWorker.connect(new_data(PyQt_PyObject))
          ```  and made the changes that you showed but getting one error on:
          

          self.serialPortEdit.returnPressed.connect(self.connectButton.clicked)

          which is
          

          TypeError: connect() failed between returnPressed() and clicked()

          changing it to this seemed to make it work:
          

          self.connectButton.clicked.connect(self.serialPortEdit.returnPressed)

          J 1 Reply Last reply 30 Apr 2023, 13:26
          0
          • M mjs513
            30 Apr 2023, 13:07

            @jeremy_k
            Thanks for getting back to me and making it a lot clearer on what has to change.

            I changed item 2 to:

            self.serWorker.connect(new_data(PyQt_PyObject))
            ```  and made the changes that you showed but getting one error on:
            

            self.serialPortEdit.returnPressed.connect(self.connectButton.clicked)

            which is
            

            TypeError: connect() failed between returnPressed() and clicked()

            changing it to this seemed to make it work:
            

            self.connectButton.clicked.connect(self.serialPortEdit.returnPressed)

            J Offline
            J Offline
            JonB
            wrote on 30 Apr 2023, 13:26 last edited by JonB
            #4

            @mjs513 said in Convert SIGNAL to new Signal Format:

            self.connectButton.clicked.connect(self.serialPortEdit.returnPressed)

            No, that's the other way round! It would equate to:

            self.connect(self.connectButton, SIGNAL("clicked()"), self.serialPortEdit, SIGNAL("returnPressed()"))
            

            which is not what your case #1 wants.

            Python connection syntax is:
            signalObject .signalMethod .connect(slotObject .slotMethod )

            Your original

            self.serialPortEdit.returnPressed.connect(self.connectButton.clicked)
            

            looks like right intention to me. I would guess the "TypeError: connect() failed between returnPressed() and clicked()" is because there is a problem here: returnPressed() signal passes no arguments but clicked() signal takes on optional [checked=false] parameter. I wonder if PyQt5 regards these signatures as incompatible and won't let you connect them directly, you will have to use a lambda?

            1 Reply Last reply
            0
            • M Offline
              M Offline
              mjs513
              wrote on 30 Apr 2023, 14:31 last edited by
              #5
              This post is deleted!
              1 Reply Last reply
              0
              • M Offline
                M Offline
                mjs513
                wrote on 30 Apr 2023, 15:29 last edited by
                #6

                @jeremy_k - @JonB

                Yeah looks like that is the correct format:

                self.serialPortEdit.returnPressed.connect(self.connectButton.clicked)
                

                With the way I made it the button doesn't work or even show up.

                but really don;t know how to use or what you mean by lamda.

                also now my conversion of item 2:

                self.connect(self.serWorker, SIGNAL("new_data(PyQt_PyObject)"), self.newData)
                

                to

                self.serWorker.connect(new_data(PyQt_PyObject))
                

                gives the following error

                AttributeError: 'SerialWorker' object has no attribute 'connect'. Did you mean: 'disconnect'?
                

                Thanks again

                J 1 Reply Last reply 30 Apr 2023, 17:01
                0
                • M mjs513
                  30 Apr 2023, 15:29

                  @jeremy_k - @JonB

                  Yeah looks like that is the correct format:

                  self.serialPortEdit.returnPressed.connect(self.connectButton.clicked)
                  

                  With the way I made it the button doesn't work or even show up.

                  but really don;t know how to use or what you mean by lamda.

                  also now my conversion of item 2:

                  self.connect(self.serWorker, SIGNAL("new_data(PyQt_PyObject)"), self.newData)
                  

                  to

                  self.serWorker.connect(new_data(PyQt_PyObject))
                  

                  gives the following error

                  AttributeError: 'SerialWorker' object has no attribute 'connect'. Did you mean: 'disconnect'?
                  

                  Thanks again

                  J Offline
                  J Offline
                  JonB
                  wrote on 30 Apr 2023, 17:01 last edited by JonB
                  #7

                  @mjs513 said in Convert SIGNAL to new Signal Format:

                  self.serWorker.connect(new_data(PyQt_PyObject))

                  AttributeError: 'SerialWorker' object has no attribute 'connect'. Did you mean: 'disconnect'?

                  Previosuly answered:

                  Python connection syntax is:

                  signalObject .signalMethod .connect(slotObject .slotMethod )

                  M 1 Reply Last reply 30 Apr 2023, 19:39
                  1
                  • J JonB
                    30 Apr 2023, 17:01

                    @mjs513 said in Convert SIGNAL to new Signal Format:

                    self.serWorker.connect(new_data(PyQt_PyObject))

                    AttributeError: 'SerialWorker' object has no attribute 'connect'. Did you mean: 'disconnect'?

                    Previosuly answered:

                    Python connection syntax is:

                    signalObject .signalMethod .connect(slotObject .slotMethod )

                    M Offline
                    M Offline
                    mjs513
                    wrote on 30 Apr 2023, 19:39 last edited by
                    #8

                    @JonB
                    Think I found the problem. Doing a search for serial worker I found that its actually a qthread class:

                    class SerialWorker(QThread):
                    
                      def __init__(self, parent = None, ser = None):
                        QThread.__init__(self, parent)
                        self.exiting = False
                        self.ser = ser
                            
                      def run(self):
                        print ("sampling start..")
                        self.acc_file = open(acc_file_name, 'w')
                        self.magn_file = open(magn_file_name, 'w')
                        count = 100
                        in_values = 9
                        reading = [0.0 for i in range(in_values)]
                        # read data for calibration    
                        while not self.exiting:
                          # determine word size
                          temp = 'b'
                          self.ser.write(temp.encode())
                          self.ser.write(chr(count))
                          for j in range(count):
                            for i in range(in_values):
                              if word == 4:
                                reading[i] = unpack('hh', self.ser.read(4))[0]
                              if word == 2:
                                reading[i] = unpack('h', self.ser.read(2))[0]            
                            self.ser.read(2) # consumes remaining '\r\n'
                            if reading[8] == 0:
                              reading[6] = 1
                              reading[7] = 1
                              reading[8] = 1      
                            # prepare readings to store on file
                            acc_readings_line = "%d %d %d\r\n" % (reading[0], reading[1], reading[2])
                            self.acc_file.write(acc_readings_line)
                            magn_readings_line = "%d %d %d\r\n" % (reading[6], reading[7], reading[8])
                            self.magn_file.write(magn_readings_line)
                          # every count times we pass some data to the GUI
                          #self.emit(SIGNAL("new_data(PyQt_PyObject)"), reading)
                          self.new_data.emit(reading)
                          print ("."),
                        # closing acc and magn files
                        self.acc_file.close()
                        self.magn_file.close()
                        return 
                      
                      def __del__(self):
                        self.exiting = True
                        self.wait()
                        print( "SerialWorker exits..")
                    

                    I have been looking at
                    https://www.pythontutorial.net/pyqt/pyqt-qthread/
                    and
                    https://www.pythonguis.com/tutorials/transmitting-extra-data-qt-signals/

                    any suggestions or better way

                    J 1 Reply Last reply 30 Apr 2023, 20:03
                    0
                    • M mjs513
                      30 Apr 2023, 19:39

                      @JonB
                      Think I found the problem. Doing a search for serial worker I found that its actually a qthread class:

                      class SerialWorker(QThread):
                      
                        def __init__(self, parent = None, ser = None):
                          QThread.__init__(self, parent)
                          self.exiting = False
                          self.ser = ser
                              
                        def run(self):
                          print ("sampling start..")
                          self.acc_file = open(acc_file_name, 'w')
                          self.magn_file = open(magn_file_name, 'w')
                          count = 100
                          in_values = 9
                          reading = [0.0 for i in range(in_values)]
                          # read data for calibration    
                          while not self.exiting:
                            # determine word size
                            temp = 'b'
                            self.ser.write(temp.encode())
                            self.ser.write(chr(count))
                            for j in range(count):
                              for i in range(in_values):
                                if word == 4:
                                  reading[i] = unpack('hh', self.ser.read(4))[0]
                                if word == 2:
                                  reading[i] = unpack('h', self.ser.read(2))[0]            
                              self.ser.read(2) # consumes remaining '\r\n'
                              if reading[8] == 0:
                                reading[6] = 1
                                reading[7] = 1
                                reading[8] = 1      
                              # prepare readings to store on file
                              acc_readings_line = "%d %d %d\r\n" % (reading[0], reading[1], reading[2])
                              self.acc_file.write(acc_readings_line)
                              magn_readings_line = "%d %d %d\r\n" % (reading[6], reading[7], reading[8])
                              self.magn_file.write(magn_readings_line)
                            # every count times we pass some data to the GUI
                            #self.emit(SIGNAL("new_data(PyQt_PyObject)"), reading)
                            self.new_data.emit(reading)
                            print ("."),
                          # closing acc and magn files
                          self.acc_file.close()
                          self.magn_file.close()
                          return 
                        
                        def __del__(self):
                          self.exiting = True
                          self.wait()
                          print( "SerialWorker exits..")
                      

                      I have been looking at
                      https://www.pythontutorial.net/pyqt/pyqt-qthread/
                      and
                      https://www.pythonguis.com/tutorials/transmitting-extra-data-qt-signals/

                      any suggestions or better way

                      J Offline
                      J Offline
                      JonB
                      wrote on 30 Apr 2023, 20:03 last edited by
                      #9

                      @mjs513 said in Convert SIGNAL to new Signal Format:

                        #self.emit(SIGNAL("new_data(PyQt_PyObject)"), reading)
                        self.new_data.emit(reading)
                      

                      Just as you have this for emitting the signal so for item #2 you need

                      # self.connect(self.serWorker, SIGNAL("new_data(PyQt_PyObject)"), self.newData)
                      self.serWorker.new_data.connect(self.newData)
                      
                      M 1 Reply Last reply 1 May 2023, 01:29
                      0
                      • J JonB
                        30 Apr 2023, 20:03

                        @mjs513 said in Convert SIGNAL to new Signal Format:

                          #self.emit(SIGNAL("new_data(PyQt_PyObject)"), reading)
                          self.new_data.emit(reading)
                        

                        Just as you have this for emitting the signal so for item #2 you need

                        # self.connect(self.serWorker, SIGNAL("new_data(PyQt_PyObject)"), self.newData)
                        self.serWorker.new_data.connect(self.newData)
                        
                        M Offline
                        M Offline
                        mjs513
                        wrote on 1 May 2023, 01:29 last edited by
                        #10

                        @JonB
                        Thanks for all your help - found that you also need to add this to the class:

                        new_data_signal = pyqtSignal('PyQt_PyObject')
                        

                        Once I did that got it all operational - just had to fix up a few minor thigs.

                        J 1 Reply Last reply 1 May 2023, 07:31
                        0
                        • M mjs513 has marked this topic as solved on 1 May 2023, 01:30
                        • M mjs513
                          1 May 2023, 01:29

                          @JonB
                          Thanks for all your help - found that you also need to add this to the class:

                          new_data_signal = pyqtSignal('PyQt_PyObject')
                          

                          Once I did that got it all operational - just had to fix up a few minor thigs.

                          J Offline
                          J Offline
                          JonB
                          wrote on 1 May 2023, 07:31 last edited by JonB 5 Jan 2023, 07:53
                          #11

                          @mjs513
                          That pyqtSignal(...) is a PyQt-ism. I think you have to use it any time you want to define your own signal.

                          However, none of this relates to your earlier problem of

                          self.connect(self.serialPortEdit, SIGNAL("returnPressed()"), self.connectButton, SIGNAL("clicked()"))
                          

                          I have now had a chance to try this. On my PyQt 5.15.6 the equivalent of the attempted

                          self.serialPortEdit.returnPressed.connect(self.connectButton.clicked)
                          

                          gives an error message like yours but with a bit more detail:

                          QObject::connect: Incompatible sender/receiver arguments
                                  QLineEdit::returnPressed() --> QPushButton::clicked(bool)
                          Traceback (most recent call last):
                            File "/home/jon/PyQt5/testconnect1.py", line 20, in <module>
                              window()
                            File "/home/jon/PyQt5/testconnect1.py", line 14, in window
                              le.returnPressed.connect(pb.clicked)
                          TypeError: connect() failed between returnPressed() and clicked()
                          

                          You can see from QLineEdit::returnPressed() --> QPushButton::clicked(bool) it is saying returnPressed() takes no argument but QPushButton::clicked(bool) does (a bool for whether any checkbox on the button is checked). Which is what I assumed the problem would be. Although this defaults to False if not passed, it is still enough to make those two signals' signatures incompatible, you cannot directly get returnPressed() signal to call clicked(bool).

                          In principle this is where you would use the lambda syntax I mentioned for the slot, like one of these:

                          self.serialPortEdit.returnPressed.connect( lambda: self.connectButton.clicked() )
                          self.serialPortEdit.returnPressed.connect( lambda: self.connectButton.clicked(False) )
                          

                          But this results in

                          le.returnPressed.connect(lambda: pb.clicked())
                          TypeError: native Qt signal is not callable
                          

                          PyQt apparently does not like us directly calling QPushButton.clicked(), because it is a "native Qt signal". We would be allowed to do this in C++. I don't know how you would get to call it from PyQt. [Following is unnecessary, see UPDATE section below.]

                          The only way I know to do this now would be:

                          self.serialPortEdit.returnPressed.connect( lambda: self.connectButton.click() )
                          

                          I still use a lambda, but I call QPushButton.click() which is a slot to "emulate" a click rather than calling the QPushButton.clicked() signal which Qt emits. In this case I could also skip the lambda (because their arguments --- none --- are compatible) and attach this slot directly to the signal:

                          self.serialPortEdit.returnPressed.connect( self.connectButton.click )
                          

                          UPDATE
                          OK, I get why, PyQt5 never lets you call a signal method directly, you always have to use emit(). So to use clicked() signal directly and not have to use the click() slot (which we are lucky even exists), you should use:

                          self.serialPortEdit.returnPressed.connect( lambda: self.connectButton.clicked.emit() )
                          
                          1 Reply Last reply
                          0

                          1/11

                          29 Apr 2023, 23:56

                          • Login

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