Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pyqt disconnect slots. New style

I assign a slot with this.

...
self.query = QtGui.QLineEdit(self)            
self.query.textChanged.connect(lambda: self.makeThread(self.googleSearch()))
self.query.returnPressed.connect(lambda: self.launchNavigator(1))
...

but how can I disconnect? I tried with this but it does not work...

self.query.textChanged.disconnect(lambda: self.makeThread(self.googleSearch()))
self.query.returnPressed.disconnect(lambda: self.launchNavigator(1))
like image 722
fpilee Avatar asked Mar 24 '13 15:03

fpilee


3 Answers

The lambda expressions return different functions that (more or less by chance ;) ) will do the same thing. Therefore, what you connected your signal to is not the same thing as the second lambda you're using when trying to disconnect it; see this example:

>>> f = lambda x: x
>>> g = lambda x: x
>>> f is g
False

You can either use self.query.textChanged.disconnect() without any parameters, which will disconnect the signal from all slots (which might be ok if you only have that one connection) or you will have to store a reference to the lambda somewhere:

self.func1 = lambda: self.makeThread(self.googleSearch())
self.query.textChanged.connect(self.func1)
...
self.query.textChanged.disconnect(self.func1)
like image 81
rainer Avatar answered Nov 12 '22 21:11

rainer


There is an elegant way of disconnecting a signal using the QConnection object returned by the original connection. So:

self.conn1 = self.query.textChanged.connect(lambda: self.makeThread(self.googleSearch()))
self.conn2 = self.query.returnPressed.connect(lambda: self.launchNavigator(1))

And then subsequently:

self.disconnect(self.conn1)
self.disconnect(self.conn2)

This feature was not implemented prior to PyQt 5.13.1, although it has existed in Qt for a long time.

like image 4
Mario Camilleri Avatar answered Nov 12 '22 21:11

Mario Camilleri


I would like to add a caveat/extension to @rainer's answer pertaining to bound methods. Keep in mind that binding a method to an instance (e.g., by writing self.slotname) actually creates a new closure every time (as in this question).

You would therefore have the same problem doing

def test_slot(self):
    self.makeThread(self.googleSearch())

...

    self.query.textChanged.connect(self.test_slot)

...

    self.query.textChanged.disconnect(self.test_slot)

as you did with the original lambda in your question. The solution is to store the closure self.test_slot in an attribute, as @rainer suggests. This is necessary because a new object that is roughly equivalent to lambda: type(self).test_slot(self) is generated every time you write self.test_slot in your code. The following will work fine as long as you do the book-keeping accurately:

    self.func = self.test_slot
    self.query.textChanged.connect(self.func)

...

    self.query.textChanged.disconnect(self.func)
like image 1
Mad Physicist Avatar answered Nov 12 '22 21:11

Mad Physicist