[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    [PyQt] How do you explicitly connect parameterless signals?
From:       Russell Warren <russ () perspexis ! com>
Date:       2014-05-23 23:08:43
Message-ID: CAD91c14HyB-j6BgKbz8vRQWjq-MTP_2b7nBW94n1NWJdnc9=Yw () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


I have some cases where I want to decorate my slots, where the decorator
has a typical (*args, **kwargs) catch-all signature.  Unfortunately, when
doing this, I'm unable to connect the signals and slots properly to a
parameter-free overload when one with parameters is available.

From the docs I thought it could be explicitly done at the connection side
with the use of:

    button.clicked[].connect(foo)

or it could be explicit at the slot instead (?) that we want the
parameter-free one via:

    @pyqtSlot()
    def foo():

but I can't get either of these to work.  When my button slot has *args in
the params, I always get the 'checked' boolean.

How do I force PyQt5 to *not* connect up the version with the (bool, )
signature?

Full example code is below, with a stripped down example of the decorator
issue:

import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import pyqtSlot

app = QtWidgets.QApplication(sys.argv)

w = QtWidgets.QWidget()
w.setWindowTitle('Signal connection checking')

b1 = QtWidgets.QPushButton("Connection to ()")
b2 = QtWidgets.QPushButton("Connection to (checked)")
b3 = QtWidgets.QPushButton("Connection to (*args)")

layout = QtWidgets.QVBoxLayout(w)
layout.addWidget(b1)
layout.addWidget(b2)
layout.addWidget(b3)

def bogus_decorator(f):
    def wrapper(*args):
        print "wrapper called with args = %r" % (args, )
        return f() #<-- have to do this to make the code work
        #should be the code below, but it fails since we call with
        #an unexpected arg and get a corresponding TypeError.
        #return f(*args) #<--- will fails since it passes an unexpected arg
    return wrapper

def onVoidClick():
    print "normal (void) clicked!"

def onBoolClick(checked):
    print "normal (bool) clicked!"

@pyqtSlot() #<-- shouldn't this force the parameter-free overload?
@bogus_decorator
#@pyqtSlot()  #<--- order does not matter
def onWrappedStarClick():
    #this always gets called with the (bool) overload
    print "Actual handler fired!"

b1.clicked.connect(onVoidClick)
b2.clicked.connect(onBoolClick)

#How to connect this next one so that it works like onVoidClick()?
# - explicitly defining the slot with @pyqtSlot() does not work
# - explicitly connecting an overload with clicked[()].connect doesn't work
b3.clicked.connect(onWrappedStarClick)
#b3.clicked[()].connect(onStarClick)

w.show()

sys.exit(app.exec_())

[Attachment #5 (text/html)]

<div dir="ltr"><div>I have some cases where I want to decorate my slots, where the \
decorator has a typical (*args, **kwargs) catch-all signature.   Unfortunately, when \
doing this, I&#39;m unable to connect the signals and slots properly to a \
parameter-free overload when one with parameters is available.<br>


</div><div><br></div><div><div>From the docs I thought it could be explicitly done at \
the connection side with the use of:<br></div></div><div><br></div><div><font \
face="courier new, monospace">      button.clicked[].connect(foo)</font></div>


<div><br></div><div>or it could be explicit at the slot instead (?) that we want the \
parameter-free one via:</div><div><br></div><div><font face="courier new, monospace"> \
@pyqtSlot()</font></div><div><font face="courier new, monospace">      def \
foo():</font></div>


<div><br></div><div>but I can&#39;t get either of these to work.   When my button \
slot has *args in the params, I always get the &#39;checked&#39; \
boolean.</div><div><br></div><div>How do I force PyQt5 to *not* connect up the \
version with the (bool, ) signature?</div>


<div><br></div><div>Full example code is below, with a stripped down example of the \
decorator issue:<br></div><div><br></div><div><div><font face="courier new, \
monospace">import sys</font></div><div><font face="courier new, monospace">from PyQt5 \
import QtWidgets</font></div>

<div><font face="courier new, monospace">from PyQt5.QtCore import \
pyqtSlot</font></div> <div><font face="courier new, \
monospace"><br></font></div><div><font face="courier new, monospace">app = \
QtWidgets.QApplication(sys.argv)</font></div><div><font face="courier new, \
monospace"><br></font></div><div><font face="courier new, monospace">w = \
QtWidgets.QWidget()</font></div>

<div><font face="courier new, monospace">w.setWindowTitle(&#39;Signal connection \
checking&#39;)</font></div><div><font face="courier new, \
monospace"><br></font></div><div><font face="courier new, monospace">b1 = \
QtWidgets.QPushButton(&quot;Connection to ()&quot;)</font></div>


<div><font face="courier new, monospace">b2 = QtWidgets.QPushButton(&quot;Connection \
to (checked)&quot;)</font></div><div><font face="courier new, monospace">b3 = \
QtWidgets.QPushButton(&quot;Connection to (*args)&quot;)</font></div>

<div><font face="courier new, monospace"><br></font></div><div><font face="courier \
new, monospace">layout = QtWidgets.QVBoxLayout(w)</font></div><div><font \
face="courier new, monospace">layout.addWidget(b1)</font></div> <div><font \
face="courier new, monospace">layout.addWidget(b2)</font></div><div><font \
face="courier new, monospace">layout.addWidget(b3)</font></div><div><font \
face="courier new, monospace"><br></font></div><div><font face="courier new, \
monospace">def bogus_decorator(f):</font></div>

<div><font face="courier new, monospace">      def \
wrapper(*args):</font></div><div><font face="courier new, monospace">            \
print &quot;wrapper called with args = %r&quot; % (args, )</font></div> <div><font \
face="courier new, monospace">            return f() #&lt;-- have to do this to make \
the code work</font></div><div><font face="courier new, monospace">            \
#should be the code below, but it fails since we call with</font></div>

<div><font face="courier new, monospace">            #an unexpected arg and get a \
corresponding TypeError.</font></div> <div><font face="courier new, monospace">       \
#return f(*args) #&lt;--- will fails since it passes an unexpected \
arg</font></div><div><font face="courier new, monospace">      return \
wrapper</font></div><div><font face="courier new, monospace"><br>

</font></div><div><font face="courier new, monospace">def \
onVoidClick():</font></div><div><font face="courier new, monospace">      print \
&quot;normal (void) clicked!&quot;</font></div><div> <font face="courier new, \
monospace"><br></font></div><div><font face="courier new, monospace">def \
onBoolClick(checked):</font></div><div><font face="courier new, monospace">      \
print &quot;normal (bool) clicked!&quot;</font></div>

<div><font face="courier new, monospace"><br></font></div><div><font face="courier \
new, monospace">@pyqtSlot() #&lt;-- shouldn&#39;t this force the parameter-free \
overload?</font></div><div><font face="courier new, \
monospace">@bogus_decorator</font></div>


<div><font face="courier new, monospace">#@pyqtSlot()   #&lt;--- order does not \
matter</font></div><div><font face="courier new, monospace">def \
onWrappedStarClick():</font></div><div><font face="courier new, monospace">      \
#this always gets called with the (bool) overload</font></div>

<div><font face="courier new, monospace">      print &quot;Actual handler \
fired!&quot;</font></div><div><font face="courier new, monospace"><br></font></div> \
<div><font face="courier new, \
monospace">b1.clicked.connect(onVoidClick)</font></div><div><font face="courier new, \
monospace">b2.clicked.connect(onBoolClick)</font></div><div><font face="courier new, \
monospace"><br></font></div>

<div><font face="courier new, monospace">#How to connect this next one so that it \
works like onVoidClick()?</font></div><div><font face="courier new, monospace"># - \
explicitly defining the slot with @pyqtSlot() does not work</font></div>


<div><font face="courier new, monospace"># - explicitly connecting an overload with \
clicked[()].connect doesn&#39;t work</font></div><div><font face="courier new, \
monospace">b3.clicked.connect(onWrappedStarClick)</font></div>

<div><font face="courier new, \
monospace">#b3.clicked[()].connect(onStarClick)</font></div><div><font face="courier \
new, monospace"><br></font></div><div><font face="courier new, \
monospace">w.show()</font></div><div> <font face="courier new, \
monospace"><br></font></div><div><font face="courier new, \
monospace">sys.exit(app.exec_())</font></div><div><br></div></div> </div>


[Attachment #6 (text/plain)]

_______________________________________________
PyQt mailing list    PyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic