Seite 1 von 1

Button Erstellung in Schleife

Verfasst: Donnerstag 8. März 2018, 14:27
von Theynk
Guten Tag zusammen.

Ich habe folgendes Problem. Ich will Daten aus einer Datenbank auslesen und diese dann durch Buttons aufrufen und in ein neues Fenster kommen. Das auslesen etc ist kein Problem, allerdings wird in der Schleife nur der letzte Datensatz als Button ausgegeben. Ich bin noch ein ziemlicher Anfänger was die Programmierung mit Python angeht.

Im folgenden mal ein Teil des Quellcodes:

cursor.execute("SELECT Werkzeugname, Schrankfach, Ausgeliehen FROM Werkzeuge")

daten_Werkzeuge = cursor.fetchall()

i = 0
x = 50
y = 180

while i<len(daten_Werkzeuge):
daten = daten_Werkzeuge
Werkzeugname = []
Werkzeugname = daten[0]
Schrankfach = []
Schrankfach = daten[1]
Ausgeliehen = []
Ausgeliehen = daten[2]

labelAW = Label(FenstergefundenerMitarbeiter,image=ImageAW)
labelAW.place(x=0, y=0, width=800, height=480)

#Vorname ausgeben
labelFenstergefundenerMitarbeiter_Vorname = Label(master=FenstergefundenerMitarbeiter, text ="Vorname:")
labelFenstergefundenerMitarbeiter_Vorname.place(x=300, y = 20, width = 100, height=20)

labelFenstergefundenerMitarbeiter_Vorname1 = Label(master=FenstergefundenerMitarbeiter, text =Vorname)
labelFenstergefundenerMitarbeiter_Vorname1.place(x=300, y = 40, width = 100, height=30)

#Nachname ausgeben
labelFenstergefundenerMitarbeiter_Nachname = Label(master=FenstergefundenerMitarbeiter, text ="Nachname:")
labelFenstergefundenerMitarbeiter_Nachname.place(x=420, y = 20, width = 100, height=20)

labelFenstergefundenerMitarbeiter_Nachname1 = Label(master=FenstergefundenerMitarbeiter, text =Nachname)
labelFenstergefundenerMitarbeiter_Nachname1.place(x=420, y = 40, width = 100, height=30)

gesamt = str(Schrankfach) + " " + Werkzeugname

#Buttonerstellung
if Ausgeliehen == "Nein":
button = Button(master=FenstergefundenerMitarbeiter, text = gesamt , bg="#00FF00" , command= print("20"))
button.place(x = x, y = y, width = 100, height = 50)
else:
button = Button(master=FenstergefundenerMitarbeiter, text = gesamt , bg="#FF0000" , command=print("20"))
button.place(x = x, y = y, width = 100, height = 50)

x += 120
if x > 650 and y == 180:
x = 50
y = 250

ButtonMitarbeiterhinzugefügt_schliessen = Button(master=FenstergefundenerMitarbeiter, text ="Zurück", command=zurückWerkzeugentnahme)
ButtonMitarbeiterhinzugefügt_schliessen.place(x=50, y=330, width = 330, height=100)

i += 1

Die "print("20") Funktion dient erstmal nur zur Überprüfung. Später soll dann sobald ich den Button klicke, die neue Seite aufgerufen werden.
Ich bin für jede Hilfe sehr dankbar.

Re: Button Erstellung in Schleife

Verfasst: Donnerstag 8. März 2018, 14:46
von Sirius3
@Theynk: die while-Schleife ist ein Anti-Pattern. Viel besser Lesbar ist es, direkt mit einer for-Schleife über die Einträge in Deiner Liste `daten_Werkzeuge` zu iterieren. Was ist der Sinn, die Variablen `Werkzeugname`, `Schrankfach` und `Ausgeliehen` an eine leere Liste zu binden um den Wert gleich in der nächsten Zeile wieder zu überschreiben?

place sollte nicht verwendet werden, weil das für jede Monitorauflösung und jedes Betriebsystem angepasst werden muß. Nimm pack. Zudem packst Du in Deiner Schleife alle Labels übereinander. Variablennamen sollen zwar aussagekräftig sein, aber 42 Zeichen lang müssen sie auch nicht sein. Da es sich um lokale Variablen handelt ist die Information, dass es sich um ein Label handelt, dass es im Fenster gefundenerMitarbeiter ist auch überflüssig. `vorname` reicht völlig, oder weil es nur zwei Zeilen gültig ist, hier ausnahmsweise auch `label`. `Vorname` und `Nachname` sind nicht definiert.
Statt Strings mit str und + zusammenzustückeln nimmt man die format-Methode. `print("20")` ist ein Funktionsaufruf, der None zurückliefert. None als command an einen Knopf zu binden, ist ziemlich sinnfrei. Wenn sich zwei Zeilen nur in einem Parameter unterscheiden, definiert man diesen als Variable und hat nur einen Aufruf. Mit `x` und `y` wird zwar gerechnet, aber es wird nie verwendet.
Variablennamen werden generell klein_mit_unterstrich geschrieben.

Ich lass mal die konstanten Labels und Buttons weg, die haben in der Schleife sowieso nichts zu suchen, und komme auf das:

Code: Alles auswählen

        cursor.execute("SELECT Werkzeugname, Schrankfach, Ausgeliehen FROM Werkzeuge")
        for idx, (werkzeugname, schrankfach, ausgeliehen) in enumerate(cursor):
            row, column = divmod(idx, 4)
            gesamt = "{} {}".format(schrankfach, werkzeugname)
            color = "#00FF00" if ausgeliehen == "Nein" else "#FF0000"
            button = Button(master=fenster_gefundener_mitarbeiter, text=gesamt, bg=color, command=partial(was_auch_immer, werkzeugname))
            button.grid(row=row, column=column)

Re: Button Erstellung in Schleife

Verfasst: Donnerstag 8. März 2018, 15:13
von Theynk
Schon mal danke für deine Hilfe. Ich dachte man muss es vorher definieren, dass es sich um eine Liste handelt. Place habe ich genutzt, da das Programm nur über das offiziele Touch-Display läuft. Das mit den Labels habe ich ausversehen da rein gepackt. Habe ich jetzt mal direkt raus genommen. Ok das mit den Variablennamen merke ich mir. Dachte nur, dass man so genau sieht wofür das ist. Wie gesagt die print funktion war nur, um erstmal zu testen ob die Buttons erstellt werden.

Ich habe deinen Quellcode jetzt einmal kopiert und eingefügt, allerdings werden keine Buttons erstellt.

Was ist denn die Bedeutung von "in enimerate(cursor):" ebenso weiß ich nicht was "divmod" und bei command "partial" bedeutet. Wie gesagt ich bin noch ein Anfänger.

Re: Button Erstellung in Schleife

Verfasst: Donnerstag 8. März 2018, 17:20
von Theynk
Also ich habe jetzt mit deinen Verbesserungsvorschlägen es noch einmal mit meiner while-Schleife probiert und auf einmal klappt es. Muss ich dann nochmal überprüfen woran das liegt. Danach muss ich dann jetzt noch programmieren, dass wenn ich zu viele Datensätze auslese auf eine nächste Seite springen kann. Jetzt hätte ich nur dazu noch zwei Fragen. Ich habe gesehen, dass ein Eintrag zu lang ist. Könnte ich irgendwie ein Zeilenumbruch machen, so dass oben die Schrankfachnummer steht und unten der Werkzeugname? Und die zweite ist, dass ich jetzt testen wollte, ob ich die Variablen von den einzelnen Buttons übergeben kann. Hier werden die allerdings nur einmal am Anfang in die Shell geschrieben, beim Druck allerdings nicht.

Hier noch einmal der Code:
def weiterWerkzeugentnahme(Schrankfach, MitarbeiterNr):
print(Schrankfach)
print(MitarbeiterNr)

while i<len(daten_Werkzeuge):
daten = daten_Werkzeuge
Werkzeugname = daten[0]
Schrankfach = daten[1]
Ausgeliehen = daten[2]

gesamt = str(Schrankfach) + " " + Werkzeugname

#Buttonerstellung
if Ausgeliehen == "Nein":
button = Button(master=FenstergefundenerMitarbeiter, text = gesamt , bg="#00FF00" , command= weiterWerkzeugentnahme(Schrankfach, MitarbeiterNr)
button.place(x = x, y = y, width = 100, height = 50)
else:
button = Button(master=FenstergefundenerMitarbeiter, text = gesamt , bg="#FF0000" , command=weiterWerkzeugentnahme(Schrankfach, MitarbeiterNr)
button.place(x = x, y = y, width = 100, height = 50)

x += 120
if x > 650 and y == 180:
x = 50
y = 250

i += 1

Re: Button Erstellung in Schleife

Verfasst: Freitag 9. März 2018, 12:54
von Theynk
Ich habe es jetzt mit dem "lambda" Befehl hinbekommen, dass die Funktion nicht direkt ausgeführt wird, allerdings sobald ich jetzt ein Button betätige, wird immer nur die Variable von dem letzten Knopf übergeben und nicht die von z.B. dem 2. Knopf. Gibt es dafür eine Lösung, so dass ich wenn ich den 2. Button drücke, davon die Variablen übergeben werden?

Re: Button Erstellung in Schleife

Verfasst: Freitag 9. März 2018, 13:21
von Sirius3
@Sirius3: warum, glaubst Du, habe ich bei meiner Lösung Deines Problems `partial` benutzt? Alle Deine Fragen, was `enumerate`, `divmod` oder `partial` macht, kann man einfach durch einen Blick in die Dokumentation beantworten.

Re: Button Erstellung in Schleife

Verfasst: Freitag 9. März 2018, 13:55
von Theynk
Das weiß ich nicht xD Mit partial bekomme ich ich ein Syntax Fehler.

button = Button(master=fenster_gefundener_mitarbeiter, text = gesamt , bg=color , command= partial(weiterWerkzeugentnahme(Schrankfach, MitarbeiterNr))
button.place(x = x, y = y, width = 100, height = 50)

Der Fehler kommt auch mit .grid

Re: Button Erstellung in Schleife

Verfasst: Freitag 9. März 2018, 14:25
von Sirius3
@Theynk: Du rufst ja auch `weiterWerkzeugentnahme` wieder auf, statt die Funktion an `partial` zu übergeben.

Re: Button Erstellung in Schleife

Verfasst: Freitag 9. März 2018, 14:31
von Theynk
Sorry aber das verstehe ich nicht. Ich kenne die Funktion ja gar nicht. Wie muss ich das denn an partial übergeben und kann dies dann aufrufen?

Re: Button Erstellung in Schleife

Verfasst: Freitag 9. März 2018, 15:20
von __deets__
Hast du dir mal die partial Dokumentation angeschaut? https://docs.python.org/3/library/funct ... ls.partial

Das Verhalten ist da klar beschrieben: du uebergibst eine Funktion, und Parameter. Die Rueckgabe ist dann wieder eine neue Funktion, die also fuer dein command als Callback/Rueckruffunktion geeignet ist, aber die Argumente die du vorher schon mitgegeben hast werden dann automatisch schon uebergeben. Also

Code: Alles auswählen

def testfunktion(ein_argument):
      print(ein_argument)

f = partial(testfunktion, "das ist alles nicht so schwer")
f() # jetzt ohne Argument aufrufbar!
Und dein Syntaxfehler kommt einfach von vergessenen Klammern, das hat aber mit partial nix zu tun.

Code: Alles auswählen

Button(.., command=lambda : 
geht auch nicht, fehlt auch die schliessende Klammer.

Re: Button Erstellung in Schleife

Verfasst: Freitag 9. März 2018, 15:40
von Theynk
Super gut es klappt besten dank :) :) :)

Jetzt werde ich mich mal daran wagen, dass wenn die Daten aus fetchall() größer als 12 sind nur die ersten 12 auf der ersten Seite dargestellt wird und dann ein Button entsteht, von dem aus ich auf eine nächste Seite komme, wo dann die anderen dargestellt werden. Ich habe zwar noch keine Idee aber werde es mal versuchen. Nochmal besten dank ich habe da schon lange dran rumprobiert.