Qt Slots/Signals immer per Hand erstellen?

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab mal mit Qt Designer eine GUI erstellt, was Neuland für mich ist.
Aus der .ui Datei hab ich mit pyuic4 ein Python Skript erzeugt.

Ist es normal, das man dann alle Buttons selbst mit self.connect() "verbinden" muß ? Kann man das nicht automatisch machen lassen?

Als Beispiele hab ich das gefunden und dort wird das per Hand gemacht:
http://www.opendocs.net/pyqt/pyqt4.html ... rated-code
http://openbook.galileocomputing.de/pyt ... 8525b31a3e

Muß ich evtl. im Designer im Bereich "Signale und Slots" was erstellen, damit pyuic4 die Buttons mit einer Methode verbindet?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

Hi Jens,

Hier mal ein code-schnipsel aus "Rapid-Gui Programming with Python and Qt" von Mark Summerfield.

Code: Alles auswählen

 buttonLayout = QVBoxLayout()
        for text, slot in (
                ("Add &Text", self.addText),
                ("Add &Box", self.addBox),
                ("Add Pi&xmap", self.addPixmap),
                ("&Copy", self.copy),
                ("C&ut", self.cut),
                ("&Paste", self.paste),
                ("&Delete...", self.delete),
                ("&Rotate", self.rotate),
                ("Pri&nt...", self.print_),
                ("&Open...", self.open),
                ("&Save", self.save),
                ("&Quit", self.accept)):
            button = QPushButton(text)
            if not MAC:
                button.setFocusPolicy(Qt.NoFocus)
            self.connect(button, SIGNAL("clicked()"), slot)
            if text == "Pri&nt...":
                buttonLayout.addStretch(5)
            if text == "&Quit":
                buttonLayout.addStretch(1)
            buttonLayout.addWidget(button)
        buttonLayout.addStretch()

        layout = QHBoxLayout()
        layout.addWidget(self.view, 1)
        layout.addLayout(buttonLayout)
        self.setLayout(layout)
Das funktioniert aber nur wenn Du per Hand ein Dialog oder Mainwindow erstellst.
Aber vielleicht kannst Du was zurecht basteln.

Ach ja, besser Du erwaehnst nicht, dass Du mit pyuic4 arbeitest (wie ich :wink: ). Das bringt Dir hier nur Aerger ein.

Wolf
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

jens hat geschrieben: Ist es normal, das man dann alle Buttons selbst mit self.connect() "verbinden" muß ? Kann man das nicht automatisch machen lassen?
Das kann ja nur gehen, wenn der Designer die Zielmethode auch kennt!

Im Designer kannst Du z.B. im Signal/Slot Editor bereits auf allg. bekannte Slots verlinken (z.B. exit() o.ä.).

Ansonsten: Lade Deine Widgets doch lieber dynamisch mit dem uic-Modul :-) Dann sparst Du Dir das händische Kompilieren nach Änderungen im UI-Design.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hyperion hat geschrieben:Das kann ja nur gehen, wenn der Designer die Zielmethode auch kennt!
Na, ich dachte, wenn ich den Button "foo_bar" nenne, dann ruft er einfach "self.foo_bar" auf. Kann man evtl. eine for-Schleife über alle Button's erhalten um das zu machen?
Hyperion hat geschrieben:Ansonsten: Lade Deine Widgets doch lieber dynamisch mit dem uic-Modul :-) Dann sparst Du Dir das händische Kompilieren nach Änderungen im UI-Design.
Der Nachteil ist aber, das ich dann nicht vom generierten Code "abschauen" kann.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab mir mal sowas gebaut:

Code: Alles auswählen

    def connectPushButtons(self):
        for button_name in dir(self):
            button = getattr(self, button_name)
            if not isinstance(button, QtGui.QPushButton):
                continue

            method_name = button_name + "_clicked"
            method = getattr(self, method_name, None)
            if method is None:
                print "Error: there exist no method '%s', please implement" % method_name
                continue

            self.connect(button, QtCore.SIGNAL("clicked()"), method)
Könnte man noch verallgemeinern.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Qt kennt eine "Autoslot"-Bezeichnung, vllt. suchst Du das:

Code: Alles auswählen

from PyQt4 import QtGui, uic, QtCore

class MyWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        uic.loadUi('form.ui', self)

    @QtCore.pyqtSlot()
    def on_pushButton_clicked(self):
        print "pushButton clicked"

app = QtGui.QApplication([])
win = MyWidget()
win.show()
app.exec_()
'form.ui' ist ein QWidget mit einem PushButton mit dem Namen pushButton. Die Nomenklatur der Autoslots ist on_name_signal, das @QtCore.pyqtSlot() oben ist notwendig, da es das Signal 'clicked' zweimal gibt und man nur hiermit clicked() von clicked(bool) unterscheiden kann (ist nur in PyQt so).
Qt-Dok hierzu: http://doc.trolltech.com/4.6/qmetaobjec ... lotsByName
PyQt-Dok: http://www.riverbankcomputing.co.uk/sta ... ts-by-name

Du kannst auch im Designer neue Slots erstellen und verlinken und brauchst dann nur noch die Methode zu implementieren.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

@QtCore.pyqtSlot() sieht nett aus! Gefällt mir, danke für die Info...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Der @QtCore.pyqtSlot()-Dekorator dient hier eigentlich nur der Unterscheidung der verschiedenen Signalsignaturen (besser: erstellt eine passende Slotsignatur). Für ein Signal, das es nur mit einer Signatur gibt, reicht:

Code: Alles auswählen

def on_widgetName_signalXY(self, *signalParameter):
    ...
Wenn Du im obigen Bsp. den Dekorator weglässt, wird die Methode zweimal aufgerufen, da die Signale 'clicked()' und 'clicked(bool)' separat abgesetzt werden, und mit @QtCore.pyqtSlot(bool) würdest Du die Methode an 'clicked(bool)' heften.
Siehe hierzu die Riverbankdokumentation, da steht es nochmal etwas ausführlicher.
Antworten