pyqt disconnect slots. New style
Asked Answered
T

3

8

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))
Timberlake answered 24/3, 2013 at 15:2 Comment(0)
S
15

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)
Synonymous answered 24/3, 2013 at 15:40 Comment(1)
What you said about lambas, is that true for functools.partial as well?Phanerogam
F
5

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.

Forfend answered 26/10, 2019 at 11:35 Comment(1)
This should definetely be the accepted answer, it's the cleanest way to do it.Bulla
M
1

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)
Mortgagor answered 25/4, 2017 at 6:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.