Denkfehler bei ButtonArray

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
MissMapeL
User
Beiträge: 22
Registriert: Mittwoch 30. Oktober 2019, 10:26

Hallo,
ich beginne gerade erst mit Python und sthe vermutlich z.Zt. 'auf dem Verständnis-Schlauch'.
Warum werden beim Clicken nicht die geklickten Buttons sondern immer der in der letzten Spalte rot?

Wäre für eine Klärung SUPER-dankbar.

from tkinter import *

class App:
def __init__(self, master):
frame=Frame(root)
frame.grid(row=0,column=0)

xmax = 3
ymax = 4
self.btn= [[0 for y in range(ymax)]]*3
for x in range(xmax):
for y in range(ymax):
self.btn[x][y] = Button(frame,command= lambda x1=x, y1=y: self.color_change(x1,y1), height=10, width=25)
self.btn[x][y].grid(column=x, row=y) #frame.pack()


def color_change(self,x,y):
self.btn[x][y].config(bg="red")
print(x,y)

root = Tk()
app = App(root)
root.mainloop()
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Sternchenimport sind böse, weil man sich da unkontrolliert hunderte Namen in den eigenen Namensraum schaufelt. Tkinter wird üblicherweise als `import tkinter as tk` eingebunden und alle Namen per tk.xy angesprochen.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 2 und mal 3 oder 5.
In Python erzeugt man keine Listen mit Dummy-Werten und füllt sie danach. `0` ist auch ein sehr schlechter Dummywert: None sagt, dass es (noch) kein Objekt gibt. Da liegt auch das Problem, dass Du keine Liste mit drei Unterlisten hast, sondern die Liste enthält drei mal (siehe *3), die selbe Liste, so dass nur die Buttons der letzten Reihe übrigbleiben, der Rest wird in der for-Schleife überschrieben (übrigens die innere Listcomprehension ist unötig, weil man bei unveränderlichen Objekten auch [0]*ymax schreiben könnte). Aber wie schon geschreiben: macht man nicht.
Statt `lambda` benutzt man `partial`. Keine Abkürzungen benutzen.

Die letzten drei Zeilen gehören auch in eine Funktion, die man üblicherweise `main` nennt. Das verhindert, dass man aus Versehen globale Variablen benutzt (wie in App.__init__).

Code: Alles auswählen

import tkinter as tk
from functools import partial

class App:
    COLUMN_MAX = 3
    ROW_MAX = 4
    def __init__(self, master):
        frame = tk.Frame(master)
        frame.grid(row=0,column=0)
        self.buttons = []
        for column in range(self.COLUMN_MAX):
            buttons = []
            for row in range(self.ROW_MAX):
                button = tk.Button(frame, command=partial(self.color_change, column, row), height=10, width=25)
                button.grid(column=column, row=row)
                buttons.append(button)
            self.buttons.append(buttons)

    def color_change(self, column, row):
        self.buttons[column][row]['bg'] = 'red'
        print(column, row)

def main():
    root = tk.Tk()
    app = App(root)
    root.mainloop()
    
if __name__ == '__main__':
    main()
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Um noch mal ein Beispiel zu geben was bei deinem `self.btn= [[0 for y in range(ymax)]]*3` eigentlich passiert.

Code: Alles auswählen

>>> ymax = 4
>>> btn = [[0 for y in range(ymax)]] * 3
>>> btn
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> btn[1][2] = 3
>>> btn
[[0, 0, 3, 0], [0, 0, 3, 0], [0, 0, 3, 0]]
(Ich wollte ja ausführlicher antworten, aber das hatte Sirius3 dann schon erledigt.)
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@MissMapeL: Noch eine Kleinigkeit: Listen sind keine Arrays, man sollte sie deswegen auch nicht so nennen. Es gibt in Python auch Arrays, damit sind dann meistens die Datentypen mit diesem Namen aus dem Numpy-Package gemeint.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
MissMapeL
User
Beiträge: 22
Registriert: Mittwoch 30. Oktober 2019, 10:26

Vielen Dank für die schnellen Antworten.
Ich werde mir die Kritik ( 4 Leerzeichen pro Ebene, ...) zu Herzen nehmen und gelobe sofortige Besserung.
Bisher habe ich vor allem C# und VB programmiert. Aus diesen Sprachen habe ich die Idee der Arrays übernommen.

Auf zum nächsten Veruch...
Liebe Grüße und Danke an alle!!!
Antworten