Convert SIGNAL to new Signal Format
-
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:
- self.connect(self.serialPortEdit, SIGNAL("returnPressed()"), self.connectButton, SIGNAL("clicked()"))
- self.connect(self.serWorker, SIGNAL("new_data(PyQt_PyObject)"), self.newData)
- self.emit(SIGNAL("new_data(PyQt_PyObject)"), reading)
Any help would be appreciated.
Thanks
Mike -
@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
@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)
-
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)
-
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)
@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)
-
@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)
@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 butclicked()
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? -
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
-
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
@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 )
-
@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 )
@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
-
@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
@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)
-
@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)
-
-
@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.
@mjs513
ThatpyqtSignal(...)
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 sayingreturnPressed()
takes no argument butQPushButton::clicked(bool)
does (abool
for whether any checkbox on the button is checked). Which is what I assumed the problem would be. Although this defaults toFalse
if not passed, it is still enough to make those two signals' signatures incompatible, you cannot directly getreturnPressed()
signal to callclicked(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 theQPushButton.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 useemit()
. So to useclicked()
signal directly and not have to use theclick()
slot (which we are lucky even exists), you should use:self.serialPortEdit.returnPressed.connect( lambda: self.connectButton.clicked.emit() )