[Python-de] pyQt4 QPushButton und QtCore.SIGNAL("clicked()")

Sebastian Wiesner basti.wiesner at gmx.net
Mo Aug 4 16:02:41 UTC 2008


Uwe Wilske <wnf at wlsoft.de> at Monday 04 August 2008, 16:36:11
> Hallo,
>
> Kann mir jemand sagen, warum on_bb_Quelle_clicked() dreimal nacheinander
> ausgeführt wird, wenn ich einmal auf bb_Quelle klicke?

Weil du es dreimal verbindest.  Auch wenn dir das vielleicht nicht so ganz 
bewusst ist ...

> -------------------------------------------------------------------------
>--
>
> #!/usr/bin/env python
> import sys
> from PyQt4 import QtGui,QtCore
> from am_main import Ui_Dialog as Dlg
>
> class Download_Dlg(QtGui.QDialog, Dlg):
>      def __init__(self):
>          QtGui.QDialog.__init__(self)
>          self.setupUi(self)
Innerhalb dieser Methode werden die ersten zwei Verbindungen hergestellt.  
Warum das so ist, siehe unten ...

>          self.ed_Quelle.setText('xxx')
>
>          #Slots einrichen
>          self.connect(self.bb_Quelle,QtCore.SIGNAL("clicked()"),
>              self.on_bb_Quelle_clicked)
Hier wird die dritte – unnötige – Verbindung manuell erstellt.

>      def on_bb_Quelle_clicked(self):
>          print 'Quellverzeichnis lesen'
>          print self.objectName
>          filename = QtGui.QFileDialog.getExistingDirectory(self,
>             'Open File','/media')
>          self.ed_Quelle.setText(filename)
>          print filename
>
>
> if __name__ == '__main__':
>    app = QtGui.QApplication(sys.argv)
>    dialog = Download_Dlg()
>    dialog.show()
>    sys.exit(app.exec_())
>
> -------------------------------------------------------------------------
> [...]
> from PyQt4 import QtCore, QtGui
>
> class Ui_Dialog(object):
>      def setupUi(self, Dialog):
>           [...]
>          QtCore.QMetaObject.connectSlotsByName(Dialog)
Dieser Aufruf ist wohl die Ursache deiner Verwirrung.  Diese Methode macht 
folgendes:  Sie iteriert über alle Signale aller Qt-Kindobjekte 
von "Dialog". Für jedes Signal werden alle Attribute von "Dialog" auf eine 
bestimmte Signatur hin überprüft:  

"on_<objektname>_<signalname>"

"objektname" ist dabei selbstverständlich nicht der Python-Name, an den das 
Objekt gebunden ist, sondern der per "setObjectName" zugewiesene Qt-Name.  
Dieser Name wird vom Designer so zugewiesen, wie du das Objekt im Designer 
benannt hast.  "signalname" bezeichnet dabei den Namen des Signals.  Wird 
nun ein solches Attribut gefunden, verbindet diese Methode automatisch das 
passende Signal des Objekts mit diesem Attribut.  In deinem Fall aus findet 
es den Button "bb_Quelle", durchsucht dessen Signale und findet das 
passende Attribute "on_bb_Quelle_clicked".  

Allerdings erklärt das erstmal nur eine Verbindung.  Die Frage bleibt, warum 
werden hier zwei Signale verbunden?

Zum Verständnis muss man sich bewusst sein, dass das "clicked" Signal ein 
optionales Argument entgegen nimmt.  Da C++ sowas nicht kennt, gibt es in 
der C++-Klasse QPushButton eigentlich *zwei* clicked-Signale, eines mit 
Parameter, eines ohne Parameter.  Die "connectSlotsByName"-Methode würde 
nun die Argumenttypen überprüfen, nur sind die ja nicht festzustellen 
(Python deklariert keine Typen).  Als "Lösung" dieses Problems werden 
einfach beide Signale verbunden.  Ob das sinnvoll ist, sei dahingestellt, 
es lässt sich auf jeden Fall einfach korrigieren.  Dazu stellt PyQt4 
den "pyqtSignature"-Dekorator bereit, der es erlaubt, die C++-Signatur 
einer Python-Methode zu spezifizieren. Dein Slot müsste also wie folgt 
deklariert werden:

@pyqtSignature('') # es wird kein Argument entgegen genommen
def on_bb_Quelle_clicked(self):
    # do something

Die manuelle Verbindung kannst du weglassen, der Aufruf von "self.connect" 
ist ja durch das automatische Verbinden überflüssig.

Dokumentiert ist das Ganze übrigens auch:
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#the-qtcore-pyqtsignature-decorator
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#connecting-slots-by-name
http://doc.trolltech.com/4.4/qmetaobject.html#connectSlotsByName
http://doc.trolltech.com/4.4/designer-using-a-component.html#widgets-and-dialogs-with-auto-connect

Hih
lunar

-- 
Freiheit ist immer die Freiheit der Andersdenkenden.
                                            (Rosa Luxemburg)
-------------- nächster Teil --------------
Ein Dateianhang mit Binärdaten wurde abgetrennt...
Dateiname   : nicht verfügbar
Dateityp    : application/pgp-signature
Dateigröße  : 189 bytes
Beschreibung: This is a digitally signed message part.
URL         : <http://python.net/pipermail/python-de/attachments/20080804/d40f5222/attachment.pgp>


Mehr Informationen über die Mailingliste python-de