Neuling: Tastendruckzähler mit GUI

Code-Stücke können hier veröffentlicht werden.
Antworten
Jensus
User
Beiträge: 6
Registriert: Mittwoch 19. Januar 2022, 09:42

Hallo zusammen,

ich bastle gerade einen Counter der einfach nur hochzählen soll und dies in einer Fullscreen-GUI anzeigen soll.

Also simpel: Drücke x -> zähle um 1 hoch und zeige das in der GUI an

Mein Problem ist, dass ich zu wenig Erfahrung habe, um es hinzubekommen, dass die Variable hochzählt bei Tastendruck. Die einzelnen Snippets für sich funktionieren aber ich schaffe es nicht, dass in den Kontext zu bringen bzw. die richtige Reihenfolge.

Mein Code sieht aktuell so aus:

Code: Alles auswählen

from tkinter import *
from tkinter import ttk
import tkinter as tk

Code: Alles auswählen

import keyboard

Code: Alles auswählen

root = Tk()
root.attributes ('-fullscreen',True)

counter = 1


label1 = Label(root, text=counter, width=20, height=20)
label1.config(font=("OpenSans", 450))
label1.config(fg="#005ba6")
label1.config(bg="black")


label1.place(relx = 0.5,
                   rely = 0.5,
                   anchor = 'center')

#while True:  # making a loop
       # if keyboard.is_pressed('q'):  # if key 'q' is pressed 
          #  counter = counter +1
         #   print(counter)
          #  label1.configure(text=counter)
            
            
        
root.mainloop()

Den unteren Teil habe ich auskommentiert, weil das nicht funktioniert wie es soll.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich wuerde auf tkinter verzichten, und stattdessen pygame benutzen. Und damit ist das dann auch viel einfacher fuer deinen Kenntnisstand, denn da hast du eine Hauptschleife, und in der kannst du auch Input-Ereignisse einfach abfragen. Siehe zB https://stackoverflow.com/questions/453 ... a-key-down
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

So funktionieren GUIs nicht. Bei einer GUI brauchst Du immer eine Hauptschleife und kannst auf Ereignisse reagieren. In TkInter per `bind`.
Benutze keine *-Importe, Du hast ja eh schon richtigerweise tkinter als tk importiert.
ttk wird gar nicht benutzt.
Warum setzt Du manche Optionen vom Label beim Erstellen und manche per `config`?
Das 1 bei label1 ist unsinnig. Variablennamen werden nicht durchnummeriert, sondern man gibt ihnen sprechende Namen. Man benutzt kein place, sondern pack oder grid.

Code: Alles auswählen

from functools import partial
import tkinter as tk

def step(counter, event):
    if event.char == 'x':
        counter.set(counter.get() + 1)

def main():
    root = tk.Tk()
    counter = tk.IntVar(root, 1)

    tk.Label(root, textvariable=counter, font=("OpenSans", 45), fg="#005ba6", bg="black").pack()
    root.bind('<KeyPress>', partial(step, counter))
    root.mainloop()

if __name__ == "__main__":
    main()
Jensus
User
Beiträge: 6
Registriert: Mittwoch 19. Januar 2022, 09:42

Vielen Dank erstmal für den Vorschlag, das funktioniert natürlich gut.

Frage: Was tut diese Zeile hier: root.bind('<KeyPress>', partial(step, counter))
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Diese Zeile bindet eine Rückruffunktion, wenn eine Taste gedrückt wurde. Wie ich schon schrieb, müssen GUIs auf Ereignisse reagieren, und damit wird gesagt, wie auf welches Ereignis reagiert werden soll.
Jensus
User
Beiträge: 6
Registriert: Mittwoch 19. Januar 2022, 09:42

Super, danke. Das versteh ich.

Jetzt spinnen wir das mal weiter: Jetzt habe ich diesen Zähler der beim Tastendruck "x" hochzählt.

Nur für mich um zu verstehen wie es generell funktioniert mal eine Idee: jetzt soll die Zahl zum Beispiel bei jedem Tastendruck auf x einmal kurz aufblinken und von mir aus die Farbe von blau zu weiß wechseln oder es soll ein Sound abgespielt werden oder was auch immer. An welcher Stelle vom Code baue ich diese Funktion mit ein? Ich habe es an diversen Stellen probiert aber zum Laufen bekomme ich es nicht.

Ich stehe noch vor einem Wald, weil ich nicht ganz verstehe wo das einzubinden ist.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich habe es schonmal gesagt, und ich sage es nochmal: pygame ist die bessere Vorgehensweise fuer solche Probleme. Denn wenn du das jetzt mit tkinter bauen willst, musst du dich noch zusaetzlich mit timer-callbacks mittels der after-Methode auseinandersetzen. Wohingegen pygame einen Schleife hat, die deinem aktuellen Verstaendis offensichlich noch genehmer ist.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Jetzt muß ich mich __deets__ anschließen, wenn jetzt auch noch lustige Blinkeffekte und Sound dazukommen sollen, ist das mehr ein Spiel, also pygame.
Jensus
User
Beiträge: 6
Registriert: Mittwoch 19. Januar 2022, 09:42

__deets__ hat geschrieben: Donnerstag 20. Januar 2022, 11:19 Ich habe es schonmal gesagt, und ich sage es nochmal: pygame ist die bessere Vorgehensweise fuer solche Probleme. Denn wenn du das jetzt mit tkinter bauen willst, musst du dich noch zusaetzlich mit timer-callbacks mittels der after-Methode auseinandersetzen. Wohingegen pygame einen Schleife hat, die deinem aktuellen Verstaendis offensichlich noch genehmer ist.
Alles klar, das habe ich mir schon gedacht. Sorry, wollte deinen Beitrag auch nicht ignorieren habe mich lediglich gefragt ob beide Methoden gleich verwertbar sind!

Vielen Dank für den Hinweis. Ich fuchse mich da mal rein und zeige euch dann auch gerne wie ich es gelöst habe. Bekomm ich hin.
Jensus
User
Beiträge: 6
Registriert: Mittwoch 19. Januar 2022, 09:42

Code: Alles auswählen

#import pyautogui
import pygame #Importieren der Bibliothek

pygame.init () #pygame wird initialisiert

screen = pygame.display.set_mode((700,700))

# Titel für das Fenster
pygame.display.set_caption("Counter")

# solange die Variable True ist, läuft das Programm
programmaktiv = True

counterstand = 0

# Schleife Hauptprogramm
while programmaktiv:
    
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            programmaktiv = False
            print("Spieler hat Quit-Button angeklickt")
        elif event.type == pygame.KEYDOWN:
            print("Spieler hat Taste gedrückt")
            
            
            # Mögliche Tasten für den Counter
            if event.key == pygame.K_x:
                print ("Man hat x gedrückt")
                                
                
            if event.key == pygame.K_y:
                print("Man hat y gedrückt")
                
                

pygame.quit ()

Mein Code sieht jetzt mal vom Rahmen her so aus. Ich habe jetzt mit mehreren Methoden schon Text anzeigen können bin mir aber nicht sicher welche Methode die sinnvollste ist. Was würdet ihr empfehlen als "Counter" bzw. wie würdet ihr den aktuellen Zählerstand darstellen?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mit den Font-Objekten von pygame. Oder du willst die Zahlen durch 10 Grafiken darstellen.
Jensus
User
Beiträge: 6
Registriert: Mittwoch 19. Januar 2022, 09:42

__deets__ hat geschrieben: Montag 24. Januar 2022, 15:20 Mit den Font-Objekten von pygame. Oder du willst die Zahlen durch 10 Grafiken darstellen.
Ich habe es jetzt funktionsfähig hinbekommen. Ist das so einigermaßen sauber oder hab ich Blödsinn gecodet?

Code: Alles auswählen

screen = pygame.display.set_mode((700,700))
screen.fill((BLACK))    #Display mit schwarzer Farbe füllen
pygame.display.flip()    #Bildschirm "umdrehen?" oder aktualisieren??

# Titel für das Fenster
pygame.display.set_caption("Counter")
w, h = pygame.display.get_surface().get_size()  #Höhe und Breite vom Screen abfragen um ihn später zu nutzen und zentrale Objekte platzieren zu können

# solange die Variable True ist, läuft das Programm
programmaktiv = True

counter = 0

# Schleife Hauptprogramm
while programmaktiv:

    pygame.display.flip() #ohne flip werden die Zahlen übereinander geschrieben?

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            programmaktiv = False
            print("Spieler hat Quit-Button angeklickt")
        elif event.type == pygame.KEYDOWN:
            print("Spieler hat Taste gedrückt")
            
            
            # Mögliche Tasten für den Counter
            if event.key == pygame.K_x:
                print ("Man hat x gedrückt")
                screen.fill ((BLACK))
                counter = counter +1
                myfont = pygame.font.SysFont('Arial Black', 550)
                textsurface = myfont.render(str(counter), False, (SBBLAU))
                text_rect = textsurface.get_rect(center=(w/2, h/2)) #Text wird "richtig" zentriert
                screen.blit(textsurface,(text_rect))
                pygame.mixer.music.load('ka-ching.mp3') #Sound laden
                pygame.mixer.music.play(0, 0.0) #Sound abspielen (1. 1x und 2. von Anfang an)
                pygame.mixer.music.set_volume(1) #Lautstärke 100%

                                
                
            if event.key == pygame.K_y:
                print("Man hat y gedrückt")
                
                

pygame.quit ()
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Den Font jedes mal wieder neu anzulegen ist Bloedsinn. "my" ist ein unsinniger Prefix, warum nicht our, your, their oder them? Da du nur einen Font hast, kannst du den auch einfach "font" nennen. Die Lautstaerke jedes mal neu zu setzen ist auch unnoetig, wenn sie nie anders gesetzt wird - gehoert genauso wie der Font vor die Schleife.

Und dann gibt's natuerlich noch die ueblichen Dinge - das sollte alles in eine main-Funktion, und einen main-guard haben, und globaler Zustand ist schlecht, etc. pp. Das findet sich hier im Grunde in jedem 2ten Post.
Antworten