views:

255

answers:

4

if i want to add 10 QPushButton at one time:

NumCount=20
for i in range(NumCount):
  btn=QPushButton("%s %s" %("Button" i+1),self)
  btn.clicked.connect(self.btnclick)

def btnclick(self):
  # here is my question 
  # how to define which button clicked?
  # how to print btn.text?

as stated in the def(btnclick).

+2  A: 

When you are in a slot, you can use sender() method (just call self.sender()) and you will receive a reference to the object, from which signal was emitted. Here is documentation about it.

gruszczy
+1  A: 

I'd subclass QPushButton and define my own sender and slot. The QObject.sender() method is tempting, but it gives me the heebie-jeebies.

class MyPushButton(QPushButton):
    def __init__(self, text = '', parent = None):
        QPushButton.__init__(self, text, parent)
        self.clicked.connect(self._handle_click)

    my_click = QtCore.pyqtSignal(QObject)

    def _handle_click(self):
        my_click.emit(self)

def btnclick(btn):
    print 'Handle button %s' % btn

for i in xrange(20):
    btn = MyPushButton('%s %s' % ('Button', i + 1), self)
    btn.my_click.connect(btnclick)

A slightly more Pythonic way of doing this could define the behavior within the class, like so:

class MyPushButton(QPushButton):
    def __init__(self, button_number, parent = None):
        QPushButton.__init__(self, '%s %s' % ('Button', button_number), parent)
        self.button_number = button_number
        self.clicked.connect(self._handle_click)

     def _handle_click(self):
        print 'Handle button %s' % self

for i in xrange(20):
    btn = MyPushButton(i + 1, self)
Chris B.
Seriously, there's nothing wrong with sender(). I've used it quite a lot and it works just fine. However, one should use some care. I usually use your method when signalling externally (i.e. to other objects) but sender() when routing signals inside a class.
Marcus Lindblom
There may not be anything wrong with .sender(), but as the documentation says, this "violates the object-oriented principle of modularity". Which wouldn't be the death of anyone, admittedly. I might be tempted to use it in as a "quick-and-dirty" fix. But Python makes it so easy to do better and cleaner it's probably better just to do it right, in the long run.
Chris B.
+1 Subclassing is evil, external functions rule :))
mlvljr
+1  A: 

As gruszcsy said, there's self.sender() (in QObject) to get that exact info.

There's also the QSignalMapper class that provides a higher-level mapping from several signal senders to one slot. It helps for the basic cases of many-to-one signal/slot mapping.

Chris B's suggestion about defining a new slot that transmits the sender as a parameter is a bit more complicated, but cleaner in terms of program structure and separation between classes. I tend to use that method when the target slot is in another object. For mapping inside a class's private slot, sender() is both neat and quite appropriate, IMO.

Marcus Lindblom
A: 

Here is a small app demonstrating one possible solution:

from PyQt4.QtGui import QPushButton, QWidget
from PyQt4.QtGui import QVBoxLayout, QApplication

def smart_connect(btn, btn_click_slot):
    proxy_slot = lambda checked: btn_click_slot(btn)
    btn.clicked.connect(proxy_slot)

class MyWidget(QWidget):
    btn_count = 4
    def __init__(self):
        super(MyWidget, self).__init__()
        lt = QVBoxLayout(self)
        for i in range(self.btn_count):
            btn = QPushButton("Button %s"%(i+1))
            smart_connect(btn, self.btn_click)
            lt.addWidget(btn)
    def btn_click(self, btn):
        print "Button '%s' was clicked."%btn.text()

app = QApplication([])
wgt = MyWidget()
wgt.show()
app.exec_()

Please enjoy :)

mlvljr