Blinkende Felder

Fragen zu Tkinter.
Antworten
py_peter
User
Beiträge: 3
Registriert: Mittwoch 9. Dezember 2020, 17:18

Hallo Zusammen, bin Neu hier im Forum.
Mein Problem: Möchte dass die Farbfelder jeweils zufällig aufblinken und dies jeweils x (später einstellbar) mal. Leider blinken die Felder nach dem Drücken des Starbutton gleichzeitig auf. Ideal wäre ein Feld nach dem anderen. Ist hier threading angebracht bzw. falsch eingesetzt?
Danke im Voraus für eure Infos.

CODE:

from tkinter import *
import random
import time
import threading


root = Tk()
root.title("COLOR GAME")

def leucht_rot():
time.sleep(0.5)
b1.config(bg='red')
time.sleep(1)
b1.config(bg = '#8b0000')

def leucht_blau():
time.sleep(0.5)
b3.config(bg='blue')
time.sleep(1)
b3.config(bg = '#8470ff')

def leucht_gelb():
time.sleep(0.5)
b2.config(bg='yellow')
time.sleep(1)
b2.config(bg = '#ffd700')

def leucht_gruen():
time.sleep(0.5)
b4.config(bg='#00ff00')
time.sleep(1)
b4.config(bg = '#228b22')


# Zufällige helle Farben
def startb():
blist=(b1, b2, b3, b4)
def bzufall(blist):
return random.choice(blist)

for i in range(3):
if bzufall(blist) == b1:
threading.Thread(target=leucht_rot).start()
print("Button 1")
if bzufall(blist) == b2:
threading.Thread(target=leucht_gelb).start()
print("Button 2")
if bzufall(blist) == b3:
threading.Thread(target=leucht_blau).start()
print("Button 3")
if bzufall(blist) == b4:
threading.Thread(target=leucht_gruen).start()
print("Button 4")


# Funtion für Clicken der Buttons
def b_click(b):
pass

# Buttons erzeugen
b1 = Button(root, width=25, height=13, bg='#8b0000', command=lambda: b_click(b1))
b2 = Button(root, width=25, height=13, bg='#ffd700', command=lambda: b_click(b2))
b3 = Button(root, width=25, height=13, bg='#8470ff', command=lambda: b_click(b3))
b4 = Button(root, width=25, height=13 , bg='#228b22', command=lambda: b_click(b4))
start_button = Button(root, text='START', bg='black', fg='white', width=12, height=13, command = lambda: startb())

# Buttons gliedern
b1.grid(row=0, column=0)
b2.grid(row=1, column=0)
b3.grid(row=0, column=1)
b4.grid(row=1, column=1)
start_button.grid(row=0, column=2)


root.mainloop()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dieses Thema kommt hier immer wieder in der ein oder anderen Form. Zur Programmierung von zeitabhängigen Abläufen braucht man bei GUIs immer Timer. Im Fall von tkinter realisiert durch “after”. Zu dem them wurde hier schon viel diskutiert & Beispiele erbracht. Mal ein bisschen durch die Themen im tkinter Forum stöbern.
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze keine *-Importe, da das unkontrolliert hunderte Namen in den eigenen Namensraum schaufelt und man keine Übersicht hat, woher welcher Name kommt. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 2 und mal 4.
Threads darf man mit GUI-Frameworks nicht benutzen, jedenfalls darf auf kein GUI-Element außerhalb des Hauptthreads zugreifen.
Alles was eine Funktion braucht, muß sie über ihre Argumente bekommen, also b1/b2/b3/b4 in den leucht-Funktionen.
Die vier Funktionen sind auch so ähnlich, dass man sie in eine zusammenfassen kann, aber da das sleep nicht verwendet werden darf, muß man es wieder in zwei aufspalten.
Wenn man anfängt Variablen durchzunummerieren, will man eigentlich eine passende Datenstruktur verwenden.
Benutze kein lambda, wo es einfach durch functools.partial ersetzbar ist.

In startb erzeugst Du 12 Zufallsknöpfe, die, wenn sie mit einem bestimmten Knopf übereinstimmen, wird die Farbe dieses Knopfes geändert, das passiert also 0 bis 12 mal. Ich glaube nicht, dass das gewollt ist.
Wenn Du die Buttons nacheinander leuchten lassen willst, mußt Du einen Button auswählen und diesen leuchten lassen, und mit after dann nach einer bestimmten Zeit den nächsten auswählen.

Code: Alles auswählen

import tkinter as tk
import random
from functools import partial

BUTTON_COLORS = [
    ('red', '#4b0000'),
    ('blue', '#44708f'),
    ('yellow', '#ffd700'),
    ('#00ff00', '#228b22'),
]

def leuchte_on(button):
    button['bg'] = button.highlight_color
    button.after(1000, leuchte_off, button)

def leuchte_off(button):
    button['bg'] = button.default_color

def start_colors(buttons):
    for i in range(3):
        for button in buttons:
            if random.choice(buttons) == button:
                button.after(500, leuchte_on, button)


# Funtion für Clicken der Buttons
def button_clicked(button):
    pass
    
def main():
    root = tk.Tk()
    root.title("COLOR GAME")

    # Buttons erzeugen
    buttons = []
    for index, (highlight_color, default_color) in enumerate(BUTTON_COLORS):
        button = tk.Button(root, width=25, height=13, bg=default_color)
        button['command'] = partial(button_clicked, button)
        button.highlight_color = highlight_color
        button.default_color = default_color
        row, column = divmod(index, 2)
        button.grid(row=row, column=column)
        buttons.append(button)
    start_button = tk.Button(root, text='START', bg='black', fg='white', width=12, height=13, command=partial(start_colors, buttons))
    start_button.grid(row=0, column=2)
    root.mainloop()

if __name__ == '__main__':
    main()
py_peter
User
Beiträge: 3
Registriert: Mittwoch 9. Dezember 2020, 17:18

Besten Dank für den Lösungsvorschlag. Habs ausprobiert, aber leider blinken die Felder immer noch gleichzeitig und nicht mit ca.1 Sekunde Abstand nacheinander?
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Natürlich nicht, weil ich nichts an der Funktionalität geändert habe. Ich habe ja schon geschrieben, wie es geändert werden könnte. Aber wie genau Du es haben willst, weißt Du ja am besten.
py_peter
User
Beiträge: 3
Registriert: Mittwoch 9. Dezember 2020, 17:18

Habe die Funktionalität nun dementsprechend geändert und es läuft super. Nochmals Danke
Antworten