Button auslesen

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.
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

Hallo, ich versuche gerade zum Zeitvertreib dieses Life-Ding zu programmieren....
Zitat:

"Die Idee des "Game of Life" gibt es schon lange. Life wurde vom Mathematiker John Conway 1970 erfunden. Die Grundidee ist, dass jede Zelle acht Nachbarn hat, d.h. es liegt eine in viele kleine Quadrate eingeteilte Fläche vor. Folgende Regeln sind definiert, die festlegen, wann eine Zelle lebendig wird, lebendig bleibt und stirbt:"

So.... jetzt stehe ich da ganz am Anfang, habe mit python nie viel gemacht, aber das soll sich ja ändern...

Also... als erstes wollte ich mal die "Spielfläche" generieren... um viele Felder zu haben, die man, um ein Muster erzeugen zu können, auch gut bedienen kann, dachte ich da an "button".... viele davon.... habe jetzt erst mal 50 in einer Reihe, sollen 50 Reihen werden, aber ist ja auch mehr möglich...

Nach einem Click auf ein Feld muss man natürlich wissen, in welcher Zeile, Spalte oder welche laufende Nummer der button hat, um da dann einzufärben, nen Punkt reinzumachen, was auch immer.....

Problem..... ich kriege die Information nicht raus, wenn ich da was auslesen will, meckert er das an...


Ich tacker den Code mal eben hier hin..... und ja, ich weiß, dass es Google gibt, ich weiß auch, dass man da mehr Grundlagen anlesen muß, aber ich weiß eben auch, dass Fragen immer die schnellste Methode ist ;-)

# 30.06.2021
# Ein/Ausgabe, Datum, Uhrzeit
#
from tkinter import *
import time
import poplib







counter = 0
led_counter = 0
i = 0;

feld_str = [];

btn = [];

# Hier wird im Sekundentakt ausgegeben
#-------------------------------------
counter = 0

def counter_label(label):
def count():
global counter
global bereit_flag
bereit_flag = 0
counter += 1

label.config(text=str(counter))
label.after(1000, count) # hier erneuter Aufruf... oder so
dateandtime = time.strftime("%d.%m.%Y %H:%M:%S")
labelZahl1 = Label(master=tkFenster, bg='#FFCFC9', text = dateandtime)
labelZahl1.grid(row=0, column=0, padx='5', pady='5', sticky='ew')
if counter > 0:
bereit = Button(master=tkFenster, text='Warte. ', width='10', bg='#FBD975', command="")
bereit.grid(row=0, column=14, padx='5', pady='5')
if counter > 1:
bereit = Button(master=tkFenster, text='Warte.. ', width='10', bg='#FBD975', command="")
bereit.grid(row=0, column=14, padx='5', pady='5')
if counter > 2:
bereit = Button(master=tkFenster, text='Warte... ', width='10', bg='#FBD975', command="")
bereit.grid(row=0, column=14, padx='5', pady='5')
if counter > 3:
bereit = Button(master=tkFenster, text='Warte.... ', width='10', bg='#FBD975', command="")
bereit.grid(row=0, column=14, padx='5', pady='5')
if counter > 4:
bereit = Button(master=tkFenster, text='Bereit', width='10', bg='#00D900', command="")
bereit.grid(row=0, column=14, padx='5', pady='5')
bereit_flag = 1

count()


#----------------------------------------------------------------------------------------------


# Wird aufgerufen, wenn der START- button gedrückt wird
def buttonStartClick():

if bereit_flag == 1:
print ("Taste gedrückt")
i=0;
while i<50:

print("Taste:", i,btn)
i = i+1;
clicked_button = event.GetEventObject()
print ("Name des Buttons:", clicked_button.GetName())


#----------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------

# Fenster wird geöffnet
#print (".")
tkFenster = Tk()
tkFenster.title('Life 0.0') # Überschrift des Fensters

tkFenster.wm_geometry("500x700") # Grösse des Fensters

#-------------------------------------------------------------------------
# Label für die Ausgabe Datum und Uhrzeit
labelZahl1 = Label(master=tkFenster, bg='#FFCFC9', text='Datum und Uhrzeit ') # wird überschrieben!
labelZahl1.grid(row=0, column=0, padx='5', pady='5', sticky='ew')
#-------------------------------------------------------------------------
# Label mit der Beschriftung Datum und Uhrzeit
labelZahl2 = Label(master=tkFenster, bg='#f1f1f1', text=' Datum Uhrzeit ')
labelZahl2.config(font=('Arial', 6))
labelZahl2.grid(row=1, column=0, padx='5', pady='3', sticky='ew')


#-------------------------------------------------------------------------
# Ein/Ausgabefeld (weiss)
entryZahl2 = Entry(master=tkFenster, bg='white', width='14')
entryZahl2.grid(row=0, column=10, padx='15', pady='10', sticky='ew')
#-------------------------------------------------------------------------
# Label Ein-Ausgabefeld
labelErgebnis = Label(master=tkFenster, bg='#f1f1f1', width='14', text='Anzahl aktiv')
labelErgebnis.grid(row=1, column=10, padx='15', pady='5', sticky='ew')
#-------------------------------------------------------------------------
# Starttaste
buttonStart = Button(master=tkFenster, text='START', width='5', bg='#FBD975', command=buttonStartClick)
buttonStart.grid(row=5, column=14, padx='5', pady='5')
#-------------------------------------------------------------------------
#Button als Anzeige, dass Programm bereit

bereit = Button(master=tkFenster, text='Warte...', width='10', bg='#FBD975', command="")

bereit.grid(row=0, column=14, padx='5', pady='5')
#-------------------------------------------------------------------------

# Starten des Tickers 1 Sekunde
counter_label(labelZahl1)
#-------------------------------------------------------------------------

# Tastenfeld
while i<50:




btn.append(Button(master=tkFenster, text='',width ='2',bg='#FBD975') )
btn=Button(master=tkFenster, text='', width='2', bg='#FBD975', command=buttonStartClick)

btn.config(font=("Arial",4))
btn.place(x=0+i*10, y=300)



i = i+1




#-------------------------------------------------------------------------






# Aktivierung des Fensters
tkFenster.mainloop()
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Hast du dir denn schon Gedanken dazu gemacht, wie du den Algorithmus von Game-of-Life realisieren willst?
Ich sehe da bisher nur eine rudimentäre graphische Oberfläche.
Versuche doch erstmal das in einer Konsole auf Buchstabenbasis "*" für lebt, " " für lebt nicht, zu programmieren.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Um GUIs zu programmieren, muß man Objektorientierung mit Klassendefinition gut beherrschen.
Man rückt nicht mit Leerzeichen graphisch so ein, dass = oder sonstige Zeichen schön aussehen. Das muß man nämlich ständig bei allen Zeilen anpassen, wenn man nur eine davon verändert. Nur die Blöcke werden in Python einheitlich eingerückt, und zwar mit 4 Leerzeichen pro Ebene, nicht 2.

*-Importe benutzt man nicht, weil dadurch verschleiert wird, woher welcher Name kommt, global verwendet man nicht, weil es ein Programm schwer durchschaubar macht und nicht modular testbar.
; braucht man in Python nicht.
poplib wird importiert aber nicht benutzt.
Wenn Du einen Zeitstempel haben willst, benutzt man `datetime` statt `time`.
Man erzeugt nicht ständig neue Labels oder Buttons, sondern verändert nur vorhandene.
Im jetzigen Zustand überlagerst Du immer mehr Labels, die ständig alle neu gezeichnet werden.
`place` benutzt man nicht, sondern in Deinem Fall `grid´.
In Deiner while-Schleife erzeugst Du einen Button, hängst ihn an die Liste `btn` und überschreibst diesen Eintrag sofort wieder mit einem anderen Button. Warum? Statt der while-Schleife benutzt man eine for-Schleife.
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

Zu 1.) Also... ich wollte mit dem Schwierigsten anfangen, das schien mir die Oberfläche zu sein.

Zu 2.) Viele Tipps, schönen Dank..... werde ich berücksichtigen
Jetzt bräuchte ich nur noch eine saubere Lösung, wie man eine Anzahl x * y Buttons auf einer Oberfläche
anzeigen kann und im Programm eine Information über die Position des betätigten button bekommt ;-)
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Bei Deinem Ansatz läufst Du Gefahr, die Buttons der GUI als Datenstruktur zu verwenden. Die Datenstruktur sollte aber unabhängig von der Visualisierung sein. Als Datenstruktur würde sich eine Matrix anbieten, um von dieser die Matrix der nachfolgenden Generation auszurechnen. Wie Du diese dann anzeigen möchtest, sei es auf der Konsole (einfach) oder in einer grafischen Oberfläche (aufwendiger), kannst Du dann unabhängig von der Matrixberechnung implementieren. Das Startmuster könntest Du über eine Textdatei einlesen.
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo emmamenden,

suchst Du sowas?

Code: Alles auswählen

import tkinter as tk
from functools import partial

def main():
    root = tk.Tk()     
    zeilen = 5
    spalten = 6
    for zeile in range(zeilen):
        for spalte in range(spalten):
            tasten_wert = zeile * spalten + spalte 
            tasten_name = 'Z{}_S{}'.format(zeile, spalte)
            taste = tk.Button(root, text=tasten_wert, bg='lightgreen',
                              width=(zeilen*spalten//10+1),
                              command=partial(zeige_taste, tasten_name,
                                              tasten_wert))
            taste.grid(column=spalte, row=zeile)
    root.mainloop()            
            
def zeige_taste(tasten_name, tasten_wert):
    print('Taste', tasten_name, 'hat den Wert', tasten_wert)

if __name__ == '__main__':
    main()
Gruss Peter
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

Ich heule gleich!!! JA!!!! Verdammt, das ist gut!!!

Danke!

Ich werde wohl noch einiges an Zeit investieren müssen!!!!
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

Eine Frage noch... oder vielleicht zwei...

Woher sind diese Informationen? Ich habe ja nun auch 2, 3 Bücher, aber ich kann mir die unters Kopfkissen legen wie ich will, sogar reingucken, so etwas habe ich in der Form nicht gefunden... mag an mir liegen ;-)
Kann man da Bücher empfehlen?

Wenn ich die Größe der buttons sehr frei wählen wollte, müsste ich wohl nicht über "grid" gehen sondern über place? Die Größe der buttons dann weiterhin über width und den Grössenwert des gewählten Zeichensatzes?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Du mußt das, was in der Dokumentation von Tkinter steht für Dein Problem anpassen. In Büchern stehen meist nur die ersten Schritte, alles weitere ist dann durch Ausprobieren und Dokumentationslesen zu ergründen.

Nein, place ist in jedem Fall falsch. Du kannst doch schon die Buttongröße per width an Deine Wünsche anpassen. Was passt da nicht?
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo emmamenden,

die Breitenberechnung hab ich nicht korrekt angegeben,
es sollte heissen:

Code: Alles auswählen

width=len(str(spalten*(zeilen+1)))
Zu Tkinter hab ich das:https://anzeljg.github.io/rin2/book2/24 ... index.html
und das:https://www.tcl.tk/man/tcl8.6/TkCmd/grid.html

aber die sind nicht als Kopfkissen geeignet. :-)

Die Grösse der Buttons ist nicht abhängig vom Layoutmanager.
Grid erlaubt auch unterschiedliche Grössen, columnspan und rowspan helfen, die Anordnung aufzuhübschen.
Wenns nötig ist, auch mal mit ipadx und ipady arbeiten.

Place ist nicht mein Freund. Wenns mit grid nicht klappt, dann gehts meistens mit pack.

Gruss Peter
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

Noch einmal schönen Dank, hat mir wirklich weiter geholfen!
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

kbr hat geschrieben: Donnerstag 1. Juli 2021, 07:46 Bei Deinem Ansatz läufst Du Gefahr, die Buttons der GUI als Datenstruktur zu verwenden. Die Datenstruktur sollte aber unabhängig von der Visualisierung sein. Als Datenstruktur würde sich eine Matrix anbieten, um von dieser die Matrix der nachfolgenden Generation auszurechnen. Wie Du diese dann anzeigen möchtest, sei es auf der Konsole (einfach) oder in einer grafischen Oberfläche (aufwendiger), kannst Du dann unabhängig von der Matrixberechnung implementieren. Das Startmuster könntest Du über eine Textdatei einlesen.
Danke für den Tipp! Tatsächlich wollte ich die Button nur als Anzeige, respektive als Eingabefeld für das "Startmuster" haben, dann noch nen Button, um das Muster zu speichern, bzw. gespeicherte Muster zu laden... und natürlich nen Startbutton, evtl. einen Schieber für die Zeit pro Step und die Anzahl der Schritte.... und als Kür.... unterschiedliche Behandlungen der Grenzen.... endet das Feld da.. oder geht es am rechten Rand dann links weiter. Also... spielt sich auf dem Bildschirm nur das Abbild einer Matrix ab, die man intern bearbeitet.

Schönen Gruß.... ich "spiele" da zurzeit immer nur in der Pause ein wenig mit rum, das dauert dann doch....
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

So, nachdem ich immer in unregelmäßigen Abständen, meist in der Pause, mal ein bisschen rumprobiere, bin ich an dieser Stelle gelandet. Prinzipiell eigentlich das, was ich mir vorstelle, aber läuft nicht ;-)

Soll heißen, ich baue da ne Matrix auf, im Hintergrund habe ich ein (2) Arrays, von denen eines dann mittels dieser Button angezeigt werden soll. In eine Richtung geht das auch, wenn ich einen (oder mehrere) Button betätige, schalten die um und in der Matrix werden sie auch eingetragen, nur beim "zurückschalten" sieht es so aus, als wäre die callback-funktion (?) (zeige_taste) gar nicht mehr da. Ich habe aber den Eindruck, dass das unter dem Debugger schon mal funktioniert hätte, aber irgendwie mit ner Riesenverzögerung....
Was ich auch nicht verstehe.... dass ich das entryField "fieldPause" offensichtlich nicht vorbelegen kann, also nichts reinschreiben kann, ist das so richtig?

Hier kommt das kleine Programmchen, die ganzen Fehlermeldungen beim Beenden machen mich auch noch ein wenig nervös ;-)

Code: Alles auswählen

import  tkinter         as      tk
from    functools       import  partial
import  tkinter.font    as      tkFont
from    tkinter         import  *
import  time, threading
 
from array import array

root            = tk.Tk()

zeilen          =   20
spalten         =   36

x_pos_tasten    =  310
y_pos_tasten    =  380
y_diff          =   30
pause           =    1.0
counter         =    0


matrix_ist  = [[0 for y in range(zeilen+20)] for x in range(spalten+20)]
matrix_alt  = [[0 for y in range(zeilen+20)] for x in range(spalten+20)]

def count():
  global counter

  counter += 1

  fieldTicker.config(text=str(counter))
  threading.Timer(pause,count).start()
#-------------------------------------------------------------------------------
def array_null():

  cnt = 0
  for i in range(zeilen):
    for j in range(spalten):
      cnt+=1
      matrix_ist[i][j] = 0
      matrix_alt[i][j] = 0
#-------------------------------------------------------------------------------
labelPause = Label(root, bg='#D5E88F', text='Pause:')
labelPause.place(x=x_pos_tasten-300, y=y_pos_tasten+0*y_diff, width=50, height=20)

fieldPause = Entry(root, bg='white', width='8')
fieldPause.place(x=x_pos_tasten-250, y=y_pos_tasten+0*y_diff, width=50, height=20)
#-------------------------------------------------------------------------------

labelXPos = Label(root, bg='#D5E88F', text='Xpos:')
labelXPos.place(x=x_pos_tasten-300, y=y_pos_tasten-140, width=50, height=20)

fieldXPos = Label(root, bg='white', width = '8')
fieldXPos.place(x=x_pos_tasten-250, y=y_pos_tasten-140, width=50, height=20)

labelYPos = Label(root, bg='#D5E88F', text='Ypos:')
labelYPos.place(x=x_pos_tasten-300, y=y_pos_tasten-110, width=50, height=20)

fieldYPos = Label(root, bg='white', width='8')
fieldYPos.place(x=x_pos_tasten-250, y=y_pos_tasten-110, width=50, height=20)

labelAlive = Label(root, bg='#D5E88F', text='alive:')
labelAlive.place(x=x_pos_tasten-300, y=y_pos_tasten-50, width=50, height=20)

fieldAlive = Label(root, bg='white', width = '8')
fieldAlive.place(x=x_pos_tasten-250, y=y_pos_tasten-50, width=50, height=20)

labelTickertxt = Label(root, bg='#D5E88F', text='Ticker:')
labelTickertxt.place(x=x_pos_tasten-300, y=y_pos_tasten-80, width=50, height=20)

fieldTicker = Label(root, bg='white', width = '8')
fieldTicker.place(x=x_pos_tasten-250, y=y_pos_tasten-80, width=50, height=20)
#-------------------------------------------------------------------------------

def main():
    count()                                             #Ticker starten
    array_null()                                 
 
    root.geometry("400x500")
    
    pixelVirtual = tk.PhotoImage(width=5, height=5)     #wird für die Darstellung der Taste benötigt  

    fieldPause.config(text=str(1.0))                    # Vorbelegen
    
                                                        # Matrixdarstellung 
    
    for zeile in range(zeilen):
        for spalte in range(spalten):

            tasten_wert = zeile * spalten + spalte 
            tasten_name = 'Z{}_S{}'.format(zeile, spalte)
            
            taste = tk.Button(root, text="", image=pixelVirtual,bg='lightgreen',
                              width=5,height=5,compound="c",
                              command=partial(zeige_taste, tasten_name,
                                              tasten_wert))
            taste.grid(column=spalte, row=zeile)
-------------------------------------------------------------------------------           
    buttonStart      = tk.Button(root, text='START', width='10', bg='#FBD975', command=buttonStartClick)
    buttonStart.place(x=x_pos_tasten, y=y_pos_tasten+0*y_diff)
#-------------------------------------------------------------------------------  
    buttonStopp       = tk.Button(root, text='STOPP', width='10', bg='#FBD975', command=buttonStoppClick)
    buttonStopp.place(x=x_pos_tasten, y=y_pos_tasten+1*y_diff)
#-------------------------------------------------------------------------------  
    buttonLaden       = tk.Button(root, text='LADEN', width='10', bg='#FBD975', command=buttonLadenClick)
    buttonLaden.place(x=x_pos_tasten, y=y_pos_tasten+2*y_diff)
#-------------------------------------------------------------------------------  
    buttonSpeichern   = tk.Button(root, text='SPEICHERN', width='10', bg='#FBD975', command=buttonSpeichernClick)
    buttonSpeichern.place(x=x_pos_tasten, y=y_pos_tasten+3*y_diff)
#-------------------------------------------------------------------------------  

    root.mainloop()            

#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def zeige_matrix():
  
      pixelVirtual = tk.PhotoImage(width=5, height=5) #wird für die Darstellung der Taste benötigt  
      tasten_name = "Z1_S1"
      tasten_wert = 1
      
      for i in range(spalten):           # x- Richtung ....
        for j in range(zeilen):          # y- Richtung ....

          zeile  = j
          spalte = i
          
          tasten_wert = zeile * spalten + spalte 
          tasten_name = 'Z{}_S{}'.format(zeile, spalte)
          
          if matrix_ist[i][j] != matrix_alt[i][j]:     # nur bei Änderung
            matrix_alt[i][j] = matrix_ist[i][j]
            if matrix_ist[i][j]== 1:
                taste = tk.Button(root, text="", image=pixelVirtual,bg='red',
                              width=5,height=5,compound="c",
                              command=partial(zeige_taste, tasten_name,
                                              tasten_wert))
                taste.grid(column=spalte, row=zeile)    
            else:
               taste = tk.Button(root, text="", image=pixelVirtual,bg='lightgreen',
                              width=5,height=5,compound="c",
                              command=partial(zeige_taste, tasten_name,
                                              tasten_wert)) 

               taste.grid(column=spalte, row=zeile)
#------------------------------------------------------------------------------- 
def buttonStartClick():

      global pause

      pause =  float (fieldPause.get())
      
      print (" Button Start")
      print ("Pause =", pause)
#-------------------------------------------------------------------------------
def buttonStoppClick():

      print (" Button Stopp")

#-------------------------------------------------------------------------------
def buttonLadenClick():

      print (" Button Laden")
#-------------------------------------------------------------------------------
def buttonSpeichernClick():

      print (" Button Speichern")
#-------------------------------------------------------------------------------  
def zeige_taste(tasten_name, tasten_wert):

    print("zeige taste")
    y_pos = tasten_wert//spalten
    x_pos = tasten_wert % spalten

    print("y_pos= ",y_pos,"  x_pos= ",x_pos)
    fieldYPos.config(text=str(y_pos))
    fieldXPos.config(text=str(x_pos))

    if matrix_ist[x_pos][y_pos] == 0:
      matrix_ist[x_pos][y_pos] = 1
     
    else:
      matrix_ist[x_pos][y_pos] = 0
     
    print("x: ", x_pos,"y: ",y_pos, "=", matrix_ist[x_pos][y_pos])

    cnt = 0
    for i in range(spalten):
      for j in range(zeilen):
         
        if matrix_ist[i][j] == 1:
          cnt+=1
    print("Anzahl Zellen =", cnt)
    fieldAlive.config(text=str(cnt))
  
    zeige_matrix()
    
#------------------------------------------------------------------------------- 
if __name__ == '__main__':
    main()
    
#------------------------------------------------------------------------------- 


Zuletzt geändert von emmamenden am Mittwoch 4. August 2021, 06:45, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Man verwendet maximal ein Leerzeichen. Wenn man schön ausgerichtete Blöcke hat, würde eine Änderung in einer Zeile Anpassungen an vielen bedeuten.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 2, mal 4, mal 6, ...
Benutze keine *-Importe. Du importierst doch tkInter schon richtig, nutzt das aber nicht konsequent.
`array` wird importiert aber nicht benutzt. Ist auch selten sinnvoll, `array` überhaupt zu benutzen.
Threads darf man nicht mit GUIs mischen, die Fehlermeldungen machen Dich zurecht nervös, mit tkinter benutzt man after.
Global darf man nicht benutzen.
`place` benutzt man nicht, organisiere Deine GUI in Frames.
Deine `main`-Funktion wird nicht konsequent genutzt, weil viel Code auch noch auf oberster Ebene liegt.
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

Schönen Dank für die Tipps,
das mit den Einrückungen ist schon gegenüber C ein wenig gewöhnungsbedürftig; da rückt man ja auch ein, aber eben nur für die Lesbarkeit/Optik.

Dann muss ich da wohl noch einiges ändern, fand das nur eigenartig, dass das "Ein/Ausschalten" der Schaltflächen unter dem Debugger irgendwie geht, ansonsten man aber den Eindruck hat, dass nach dem ersten Umschalten die Funktion "tot" ist....
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@emmamenden: hier geht es auch um Lesbarkeit und Optik. Dem Compiler ist es egal, dass Du wie Kraut und Rüben eingerückt hast. Dem sind auch die komischen Zeilen mit den vielen Minuszeichen egal, mich behindern sie beim Lesen. Üblich sind zwei Leerzeilen zwischen Funktionen um einen optischen Abstand zu haben.

Näher habe ich mir Deinen Code auch nicht angeschaut, wenn mit `global` und Threads es wenig Sinn macht, die ganzen anderen Baustellen anzugehen.
Falsch ist zum Beispiel noch die Funktion zeige_matrix, weil Du darin ständig neue Buttons erzeugst, statt die bestehenden zu ändern. GUI-Elemente werden einmal beim Erzeugen des Fensters angelegt und danach nur noch verändert.
Warum rechnest Du Dir einen Tastenwert aus Spalte und Zeile aus, nur um den später wieder in Zeile und Spalte zurückzurechnen?
Der Tastenname wird gar nicht benutzt.
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Grundsätzlich vielleicht mal ein Hinweis auf den Style Guide for Python Code. Das mit der Namensschreibweise (klein_mit_unterstrichen statt camelCase) könnte man auch einfach umsetzen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Dennis89
User
Beiträge: 1153
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

hier habe ich mal ein kleines Beispiel, wie du so ein GUI aufbauen solltest. Arbeite dich in die objektorientierte Programmierung ein und berücksichtige die Ratschläge die dir gegeben wurden.

Code: Alles auswählen

#!/usr/bin/env python3

import tkinter as tk
from functools import partial


class Buttons(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.pushed_buttons = []
        self.buttons = []
        for number in range(5):
            button = tk.Button(self, text=f'Nr. {number}', command=partial(self.show_number, number))
            button.grid(column=number, row=0)
            self.buttons.append(button)

    def show_number(self, number):
        if not number in self.pushed_buttons:
            self.pushed_buttons.append(number)
            print(number)
        else:
            print('Button wurde schon gedrückt')


def main():
    root = tk.Tk()
    root.title('Nur mal so zum zeigen')
    app = Buttons(root)
    app.pack()
    app.mainloop()


if __name__ == "__main__":
    main()

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
emmamenden
User
Beiträge: 16
Registriert: Mittwoch 15. August 2018, 05:39

Code: Alles auswählen

#-------------------------------------------------------------------------------

def calculate_matrix():

    #  Der Reihe nach die 8 Nachbarn der aktuellen Zelle betrachten
    #  und die Zustände in n[1] bis n[8] speichern (1 oder 0)
    #  Ist der Index der zu betrachtenden Zelle  x < 0 dann ist x = spalten-1  
    #                                            y < 0 dann ist y = zeilen-1
    #  ist der Index der zu betrachtenden Zelle  x > (spalten-1) dann ist x = 0
    #                                            y > (zeilen-1)  dann ist y = 0
    #
    #  drei Regeln:
    #       Zelle bleibt leben, wenn Summe                                   n = 2 oder 3
    #       Zelle wird geboren mit genau 3 Nachbarn                          n = 3(Überschneidung mit oberer Regel)
    #       Zelle stirbt mit mehr als 3 Nachbarn oder weniger als 2 Nachbarn n > 3 oder n < 2
    #


    for zeile in range(zeilen):                                 # Achtung Anzahl spalten(36)/zeilen(20): 
        for spalte in range(spalten):                           # heisst: x von 0..35, y von 0..19
            matrix_neu[zeile][spalte] = 0
            

    for zeile in range(zeilen):
        for spalte in range(spalten):                           #     Schema Position
                                                                #
            #Position 1                                         #     1 2 3
            x_pos = spalte-1                                    #     4 x 5       x = aktuelle Zelle
            y_pos = zeile-1                                     #     6 7 8
            if x_pos < 0: 
                x_pos = spalten-1                      
            if y_pos < 0: 
                y_pos = zeilen-1                      
            n[1] = matrix_ist[y_pos][x_pos]                      
            
             #Position 2                         
            x_pos = spalte
            y_pos = zeile-1                      
            if y_pos < 0: 
                y_pos = zeilen-1 
            n[2] = matrix_ist[y_pos][x_pos]
            
             #Position 3                         
            x_pos = spalte+1
            y_pos = zeile-1
            if x_pos > (spalten-1): 
                x_pos = 0
            if y_pos < 0: 
                y_pos=zeilen-1 
            n[3] = matrix_ist[y_pos][x_pos]
            
             #Position 4                         
            x_pos = spalte-1
            y_pos = zeile
            if x_pos < 0: 
                x_pos = spalten-1
            n[4] = matrix_ist[y_pos][x_pos]
            
             #Position 5                        
            x_pos = spalte+1
            y_pos = zeile
            if x_pos > (spalten-1): 
                x_pos = 0
            n[5] = matrix_ist[y_pos][x_pos]
            
             #Position 6                        
            x_pos = spalte-1
            y_pos = zeile+1
            if x_pos < 0: 
                x_pos = spalten-1
            if y_pos > (zeilen-1): 
                y_pos = 0 
            n[6] = matrix_ist[y_pos][x_pos]
            
             #Position 7                        
            x_pos = spalte
            y_pos = zeile+1
            if y_pos > (zeilen-1): 
                y_pos = 0
            n[7] = matrix_ist[y_pos][x_pos]
            
             #Position 8                        
            x_pos = spalte+1
            y_pos = zeile+1
            if x_pos > (spalten-1): 
                x_pos = 0
            if y_pos > (zeilen-1): 
                y_pos = 0
            n[8] = matrix_ist[y_pos][x_pos]
            
            summe = 0
            for k in range(8):      # k = 0..7
                summe = summe + n[k+1]
                
                
            # Die drei Regeln:
            
            #1.) Zelle unverändert, wenn summe 2 oder 3 (Überschneidung mit Regel 2!)

            if summe == 2:
                matrix_neu[zeile][spalte] = matrix_ist[zeile][spalte]
            
            #2.) Zelle wird auf jeden Fall 1, wenn summe genau 3
            
            if summe == 3:
                matrix_neu[zeile][spalte] = 1
                
            #3.) Zelle stirbt, wenn Summe > 3
            
            if summe > 3:
                matrix_neu[zeile][spalte] = 0
                
            #4.) Zelle stirbt, wenn n<2
            
            if summe <2:
                matrix_neu[zeile][spalte] = 0
                
            if summe == 3:
                print("Zeile:",zeile,"     Spalte:",spalte,"     Nachbarn:",summe)
                

    for zeile in range(zeilen):
        for spalte in range(spalten):
          matrix_ist[zeile][spalte] = matrix_neu[zeile][spalte]  
          
   

Hallo nochmal... mein "Ziel" habe ich erreicht, dieses Conway Game of Life läuft....

Ein Problem hatte ich der Betrachtung der Feldgrenzen, also, wenn der Arrayindex des zu betrachtenden Nachbarn <0 oder >"zeilen-1" oder "spalten-1"

In x- Richtung funktionierte das auch, in y-Richtung nicht... alles richtig, ging aber nicht... bis ich dann festgestellt habe, dass ich y_pos und Y-pos verwendet habe und der Untetrschied kaum zu sehen war; schade, dass man in python nicht deklarieren muss...
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@emmamenden: Funktionen (und Methoden) bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben. Auf Modulebene darf es keine Variablen geben, da gehört nur Code hin der Konstanten, Funktionen, und Klassen definiert.

`calculate_matrix()` ist deswegen keine richtige Funktion, sondern nur ein Name für ein Stück Code. Was das ganze ziemlich unübersichtlich macht.

`zeilen` und `spalten` sollte man von der Matrix abfragen, damit man sicher sein kann, dass die Werte davon mit den tatsächlichen Dimensionen der Matrix übereinstimmen.

Statt eine Matrix mit 0en zu füllen und am Ende dann die Werte Element für Element wieder in die Ausgangsmatrix zu kopieren, würde man einfach immer eine neue Matrix erstellen und am Ende einfach die alte Matrix durch die neue ersetzen. Die Funktion würde die alte Matrix als Argument bekommen, und eine neu erstellte Matrix als Ergebnis liefern.

Statt da 8 mal fast den gleichen Code für jede Position zu schreiben bzw. zu kopieren, würde man das mit einer Schleife über die Delta-Werte der Positionen lösen wo der Code nur *einmal* steht.

Und auch gleich die Summe ausrechnen und nicht erst alles umständlich in einer globalen Liste speichern die den wirklich schlechten Namen `n` trägt und zudem noch aus irgendwelchen Gründen erst bei Index 1 mit sinnvollen Werten belegt wird. Selbt wenn man die 1en und 0en in einer Liste sammeln würde, dann würde man das mit einer leeren Liste beginnend mit `append()` machen, und am Ende einfach die `sum()`-Funktion zum addieren verwenden.

Die Umsetzung der Regeln mit den vielen ``if``\s ist umständlich. Ob lebendig oder tot kann man als *eine* Bedingung ausdrücken und dann auch gleich das Ergebnis speichern, denn eigentlich sind das ja gar keine 0 und 1 Werte sondern Wahrheitswerte. Dafür sollte man 0 und 1 nicht missbrauchen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten