Seite 1 von 1

Einer Funktion innerhalb einer Klasse Argumente zuweisen - Dartzähler

Verfasst: Montag 21. Dezember 2020, 18:35
von Python_Stefan
Hallo zusammen,

ich habe eine PyQt5 Oberfläche erstellt und möchte mir damit meinen eigenen Dartzähler programmieren. Ich hatte die Idee, nicht jfür jede einzelne Punktzahl eine Funktion zu schreiben, sondern insgesamt nur eine Funktion zu schreiben und abhängig von der Punktzahl die Zahl hineinzugeben. Mein dargestellter Code ist nur ein Muster für die Punktzahl "20". Meine Frage: Warum funktioniert der Befehl "self.b_2.clicked.connect(self.abziehen(20))" nicht? Ich erhalte dann den Error: "TypeError: argument 1 has unexpected type 'int'".

Und die zweite Frage: was muss ich tun, damit es klappt und ich das für alle Punktzahlen anwenden kann.
Zur besseren Orientierung habe ich in die Zeilen, zu denen ich die Fragen habe an den Rand Emojis gemacht (diese sind nicht in meinem Programmcode enthalten).


from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(QtWidgets.QWidget):

def __init__(self):
super().__init__()
self.punkte = 501


def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(391, 215)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label_punkte = QtWidgets.QLabel(self.centralwidget)
self.label_punkte.setGeometry(QtCore.QRect(160, 10, 47, 13))
self.label_punkte.setObjectName("label_punkte")
self.b_1 = QtWidgets.QPushButton(self.centralwidget)
self.b_1.setGeometry(QtCore.QRect(140, 50, 75, 23))
self.b_1.setObjectName("b_1")
self.b_2 = QtWidgets.QPushButton(self.centralwidget)
self.b_2.setGeometry(QtCore.QRect(140, 90, 75, 23))
self.b_2.setObjectName("b_2")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 391, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.b_2.clicked.connect(self.abziehen(20)) :geek: :geek: :geek: :geek: :geek: :geek: :geek: :geek:

self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)

def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_punkte.setText(_translate("MainWindow", "501"))
self.b_1.setText(_translate("MainWindow", "10"))
self.b_2.setText(_translate("MainWindow", "20"))


def abziehen(self,zahl): :geek: :geek: :geek: :geek: :geek: :geek: :geek: :geek: :geek: :geek:
self.punkte = self.punkte - zahl
self.label_punkte.setText(str(self.punkte))
return self.punkte


if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())

Re: Einer Funktion innerhalb einer Klasse Argumente zuweisen - Dartzähler

Verfasst: Montag 21. Dezember 2020, 22:38
von Dennis89
Hallo,

bitte poste deinen Code mal in den Code-Tags. Dann kann man ihn besser lesen. Achte darauf, dass die Einrückungen stimmen.
Die Smilies sind nett gemeint, aber du könntest sie weglassen und dafür die vollständige(!) Fehlermeldung mit angeben. Alles Was dir Python als Fehlermeldung ausgibt am besten immer dazu kopieren.

Wenn du deine Fehlermeldung mal in eine Suchmaschine und/oder Übersetzer eingibst dann weist du schon mal, dass du ein Problem mit einem Datentyp hast.

Vielleicht sieht ein erfahrener Programmierer den Fehler sofort, mir ist es ehrlich gesagt zu unübersichtlich ohne Code-Tags :?:

Grüße
Dennis

Re: Einer Funktion innerhalb einer Klasse Argumente zuweisen - Dartzähler

Verfasst: Montag 21. Dezember 2020, 23:01
von Python_Stefan
Ich hoffe so ist es übersichtlicher:

Code: Alles auswählen

# -*- coding: utf-8 -*-

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(QtWidgets.QWidget):

    def __init__(self):
        super().__init__()
        self.punkte = 501


    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(391, 215)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label_punkte = QtWidgets.QLabel(self.centralwidget)
        self.label_punkte.setGeometry(QtCore.QRect(160, 10, 47, 13))
        self.label_punkte.setObjectName("label_punkte")
        self.b_1 = QtWidgets.QPushButton(self.centralwidget)
        self.b_1.setGeometry(QtCore.QRect(140, 50, 75, 23))
        self.b_1.setObjectName("b_1")
        self.b_2 = QtWidgets.QPushButton(self.centralwidget)
        self.b_2.setGeometry(QtCore.QRect(140, 90, 75, 23))
        self.b_2.setObjectName("b_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 391, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.b_2.clicked.connect(self.abziehen(20))			#hier entsteht ein Problem

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label_punkte.setText(_translate("MainWindow", "501"))
        self.b_1.setText(_translate("MainWindow", "10"))
        self.b_2.setText(_translate("MainWindow", "20"))    


    def abziehen(self,zahl):								#hier ist wohl auch ein Problem
        self.punkte = self.punkte - zahl
        self.label_punkte.setText(str(self.punkte))
        return self.punkte


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

knopf20 = Ui_MainWindow()


Re: Einer Funktion innerhalb einer Klasse Argumente zuweisen - Dartzähler

Verfasst: Dienstag 22. Dezember 2020, 00:42
von __blackjack__
@Python_Stefan: Das ist generierter Quelltext in dem mal ein deutlicher Kommentar oben stand das man da nichts dran ändern sollte. Quelltext generieren macht man sowieso nicht mehr, stattdessen lädt man die *.ui-Datei zur Laufzeit. Siehe das `PyQt5.uic`-Modul.

Das Problem ist das man die GUI so wie Du das machst nicht mehr mit dem Designer verändern kann. Das sollte man aber dringend tun, denn absolute Koordinaten statt Layouts funktionieren nicht wirklich. Das geht auf dem Rechner mit dem Bildschirm und den Einstellungen auf denen das so erstellt wurde, kann aber auf anderen Probleme machen, bis hin zu unbenutzbaren GUIs weil die Grössen nicht hinhauen und man Text nicht lesen kann oder Elemente sich überlappen.

`QPushButton.clicked.connect()` erwartet eine Funktion oder Methode als Argument. Du übergibst da aber eine ganze Zahl. Nämlich den Rückgabewert von ``self.abziehen(20)``. Du darfst die Methode an der Stelle nicht aufrufen, sondern Du musst dort etwas übergeben was kein Argument erwartet und die Methode aufruft wenn die Schaltfläche angeklickt wird. Der vorgesehene Weg dafür ist `functools.partial()`.

Ein Rückgabewert macht bei so einer Methode auch keinen Sinn, denn die GUI-Hauptschleife die das am Ende aufrufen wird, weiss damit nichts anzufangen.

Re: Einer Funktion innerhalb einer Klasse Argumente zuweisen - Dartzähler

Verfasst: Dienstag 22. Dezember 2020, 00:54
von Python_Stefan
@ __blackjack__: vielen Dank für deine Rückmeldung. Ich werde morgen alle Sachen, die du angesprochen hast recherchieren und direkt ausprobieren.

Re: Einer Funktion innerhalb einer Klasse Argumente zuweisen - Dartzähler

Verfasst: Dienstag 22. Dezember 2020, 20:47
von Python_Stefan
Leider komme ich mit den gegebenen Informationen nicht weiter. Ich habe versucht functools.partial() anzuwenden, siehe folgender Code. Allerdings erhalte ich, wenn ich den Code ausführe folgenden Error: TypeError: abziehen() missing 1 required positional argument: 'zahl', obwohl ich meines Erachtens eine zahl eingegeben habe. Was genau mache ich falsch und wie geht es richtig?

Code: Alles auswählen

# -*- coding: utf-8 -*-

from PyQt5 import QtCore, QtGui, QtWidgets
from functools import partial

class Ui_MainWindow(QtWidgets.QWidget):

    def __init__(self):
        super().__init__()
        self.punkte = 501

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(391, 215)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label_punkte = QtWidgets.QLabel(self.centralwidget)
        self.label_punkte.setGeometry(QtCore.QRect(160, 10, 47, 13))
        self.label_punkte.setObjectName("label_punkte")
        self.b_1 = QtWidgets.QPushButton(self.centralwidget)
        self.b_1.setGeometry(QtCore.QRect(140, 50, 75, 23))
        self.b_1.setObjectName("b_1")
        self.b_2 = QtWidgets.QPushButton(self.centralwidget)
        self.b_2.setGeometry(QtCore.QRect(140, 90, 75, 23))
        self.b_2.setObjectName("b_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 391, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.b_2.clicked.connect(b_2)					# hier habe ich die Funktion mit partial eingefügt

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label_punkte.setText(_translate("MainWindow", "501"))
        self.b_1.setText(_translate("MainWindow", "10"))
        self.b_2.setText(_translate("MainWindow", "20"))


    def abziehen(self,zahl):							#das ist die Funktion auf die ich partial anwenden möchte
        self.punkte = self.punkte - zahl
        self.label_punkte.setText(str(self.punkte))


    b_2 = partial(abziehen(2))						#hier habe ich versucht partial mit dem Wert zwei für 'zahl' anzuwenden


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Re: Einer Funktion innerhalb einer Klasse Argumente zuweisen - Dartzähler

Verfasst: Mittwoch 23. Dezember 2020, 00:36
von Python_Stefan
Falls jemand das gleiche Problem hat, dann kann meine Lösung vielleicht helfen. Ich konnte die Anzahl der Zeilen reduzieren indem ich für jeden Button eine neue Funktion basierend auf der Funktion "abziehen" geschrieben habe.

Beispiel:
def minus20:
return self.abziehen(20)

und dann:
b_20.clicked.connect(self.minus20)


Auf diese Weise hat meine Ursprungsidee nicht funktioniert, aber der Code konnte trotzdem deutlich reduziert werden.

Re: Einer Funktion innerhalb einer Klasse Argumente zuweisen - Dartzähler

Verfasst: Mittwoch 23. Dezember 2020, 01:10
von __deets__
b_20.clicked.connect(partial(self.minus, 20))

ist der richtige Weg.