pyQt4 QPushButton und QtCore.SIGNAL("clicked()")
Hallo, Kann mir jemand sagen, warum on_bb_Quelle_clicked() dreimal nacheinander ausgeführt wird, wenn ich einmal auf bb_Quelle klicke? --------------------------------------------------------------------------- #!/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) self.ed_Quelle.setText('xxx') #Slots einrichen self.connect(self.bb_Quelle,QtCore.SIGNAL("clicked()"), self.on_bb_Quelle_clicked) 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_()) --------------------------------------------------------------------------- # -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'am_main.ui' # # Created: Mon Aug 4 16:16:53 2008 # by: PyQt4 UI code generator 4.3.3 # # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(QtCore.QSize(QtCore.QRect(0,0,516,300).size()).expandedTo(Dialog.minimumSizeHint())) self.widget = QtGui.QWidget(Dialog) self.widget.setGeometry(QtCore.QRect(0,0,451,121)) self.widget.setObjectName("widget") self.vboxlayout = QtGui.QVBoxLayout(self.widget) self.vboxlayout.setObjectName("vboxlayout") self.gb_Quelle = QtGui.QGroupBox(self.widget) self.gb_Quelle.setObjectName("gb_Quelle") self.ed_Quelle = QtGui.QLineEdit(self.gb_Quelle) self.ed_Quelle.setGeometry(QtCore.QRect(10,20,341,24)) self.ed_Quelle.setObjectName("ed_Quelle") self.bb_Quelle = QtGui.QPushButton(self.gb_Quelle) self.bb_Quelle.setGeometry(QtCore.QRect(360,20,28,28)) self.bb_Quelle.setObjectName("bb_Quelle") self.vboxlayout.addWidget(self.gb_Quelle) self.gb_Ziel = QtGui.QGroupBox(self.widget) self.gb_Ziel.setObjectName("gb_Ziel") self.ed_Ziel = QtGui.QLineEdit(self.gb_Ziel) self.ed_Ziel.setGeometry(QtCore.QRect(10,20,341,24)) self.ed_Ziel.setObjectName("ed_Ziel") self.bb_Ziel = QtGui.QPushButton(self.gb_Ziel) self.bb_Ziel.setGeometry(QtCore.QRect(360,20,28,28)) self.bb_Ziel.setObjectName("bb_Ziel") self.vboxlayout.addWidget(self.gb_Ziel) self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Kamera Download", None, QtGui.QApplication.UnicodeUTF8)) self.gb_Quelle.setTitle(QtGui.QApplication.translate("Dialog", "Kopieren von Kamera", None, QtGui.QApplication.UnicodeUTF8)) self.bb_Quelle.setText(QtGui.QApplication.translate("Dialog", "...", None, QtGui.QApplication.UnicodeUTF8)) self.gb_Ziel.setTitle(QtGui.QApplication.translate("Dialog", "in das Grundverzeichnis", None, QtGui.QApplication.UnicodeUTF8)) self.bb_Ziel.setText(QtGui.QApplication.translate("Dialog", "...", None, QtGui.QApplication.UnicodeUTF8)) -- Uwe Wilske
Uwe Wilske <wnf@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-qtco... http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#connecti... http://doc.trolltech.com/4.4/qmetaobject.html#connectSlotsByName http://doc.trolltech.com/4.4/designer-using-a-component.html#widgets-and-dia... Hih lunar -- Freiheit ist immer die Freiheit der Andersdenkenden. (Rosa Luxemburg)
On 04.08.08 16:36:11, Uwe Wilske wrote:
Hallo,
Kann mir jemand sagen, warum on_bb_Quelle_clicked() dreimal nacheinander ausgeführt wird, wenn ich einmal auf bb_Quelle klicke?
Sicher das es 3x ist? 2x waere normal, denn in PyQt gibt es 2 clicked() Signale, einmal mit und einmal ohne Parameter. Siehe http://www.riverbankcomputing.com/static/Docs/PyQt4/pyqt4ref.html#the-qtcore... damit kannst du sicherstellen das du nur das signal bekommst ohne parameter. Andreas -- You look like a million dollars. All green and wrinkled.
Sebastian Wiesner schrieb:
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 ...
Ja das war mir wirklich nicht bewusst Nachdem ich die von Hand erstellte Verbindung gelöscht habe trat das Ereignis nur noch zweimal auf. Und nachdem ich die Zeile @QtCore.pyqtSignature('') # es wird kein Argument entgegen genommen eingefügt habe trat das Ereignis nur noch einmal auf. Vielen Dank für die ausführliche Erklärung. Deshalb liebe ich diese Liste: Schnelle und kompetente Auskünfte. -- Uwe Wilske
participants (3)
-
Andreas Pakulat
-
Sebastian Wiesner
-
Uwe Wilske