GUI Button richtig verwenden?

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
Borokai
User
Beiträge: 2
Registriert: Mittwoch 26. April 2023, 12:58

Hallo,

ich habe vor kurzem angefangen mich mit Python zu beschäftigen bzw. es zu lernen.
Normalerweise finde ich die Lösungen für meine Probleme am liebsten lebst um es zu lernen, aber manche Probleme kann man schwierig googeln wie mein momentanes.

Ich habe eine GUI erstellt und möchte nun ein Bild suchen. Das funktioniert zwar alles, aber ich kann das Programm nicht mehr stoppen. Es führt die Suche aus und während dieser 5 Sekunden Wartezeit lässt sich in dem Fenster nichts mehr anklicken und eine Ladezeit wird angezeigt. Wie kann ich es schreiben, dass die Befehle die ich durch das Fenster gebe Vorrang haben? Ich möchte, dass ich auf "Startet die Suche" klicke, damit eine Schleife starte in der das Bild gesucht wird und wenn ich erneut auf "Startet die Suche" klicke die Suche angehalten wird bzw. abgebrochen wird.

Code: Alles auswählen

import win32com.client as comclt
wsh = comclt.Dispatch("WScript.Shell")
from tkinter import *
import pyautogui
print(pyautogui.size())
import time
from python_imagesearch.imagesearch import imagesearch_loop, imagesearcharea,\
    imagesearch
from random import randint
from time import sleep


def button_action():
    while True:
        
                pos = imagesearch("Check.png", 0.8)
                if pos[0] != -1: pyautogui.leftClick(pos [0], pos [1], 0.8)
                time.sleep(5)

                     
fenster = Tk()

fenster.title("Erster Test")


change_button = Button(fenster, text="Suche", command=button_action)
exit_button = Button(fenster, text="Beenden", command=fenster.quit)

anweisungs_label = Label(fenster, text="Startet die Suche")

info_label = Label(fenster, text="Schließt das Programm")

fenster.geometry("450x400")

anweisungs_label.place(x = 0, y = 0, width=200, height=150)
change_button.place(x = 220, y = 65, width=200, height=20)
info_label.place(x = 100, y = 160, width=300, height=100)
exit_button.place(x = 100, y = 260, width=300, height=100)

fenster.mainloop()


Schon mal vielen Dank für eure Antworten.
Benutzeravatar
Kebap
User
Beiträge: 695
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Schau mal nach, was time.sleep(5) bewirkt.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Eine GUI ist inheränt ereignisbasiert. Du darfst da nur kurz code laufen lassen, damit die nicht einfriert. Dazu müssen längere Aufgaben entweder in durch Timer aufgerufene, kleine Schritte zerlegt werden. Oder in einen Thread gepackt werden, der aber dann tunlichst NICHT an GUI-Objekten spielen darf. Sonst kracht es.

Dieses Thema wird hier auch oft diskutiert, durchsuch mal das Forum nach Diskussionen und Beispielen.
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo Borokai,
deine while Schleife wird nie beendet, da fehlt ein break.
Schau mal was das macht:

Code: Alles auswählen

import tkinter as tk
import time
from functools import partial

def zaehle(taste, anzeige, zahl, zaehler):    
    taste.config(state='disabled')
    zaehler += 1    
    print(zaehler)    
    ident = taste.after(2000, zaehle, taste, anzeige, zahl, zaehler    )
    if zaehler > 3:
        taste.config(state='normal')
        zaehler = 0
        taste.after_cancel(ident)
    zahl.set(zaehler)
            

def main():
    root=tk.Tk()
    zahl = tk.StringVar()
    zaehler = 0
    anzeige = tk.Label(root, textvariable=zahl, width=5)
    taste = tk.Button(root, text='Start', bg='green')
    taste.config(command=partial(zaehle, taste, anzeige, zahl, zaehler))
    
    taste.pack()
    anzeige.pack()
    root.mainloop()

if __name__ == "__main__":
    main()
Gruss Peter
Borokai
User
Beiträge: 2
Registriert: Mittwoch 26. April 2023, 12:58

@Kebap Ich dachte es wäre möglich eine höhere Instanz in die Aufgabe zu integrieren, die stehts Vorrang hat, aber wie es scheint muss das ganz anders geschrieben werden um verschiedene Aufgaben zuzuteilen, denn das soll nur der Anfang werden und immer weiter mit Buttons und damit auch Aufgaben gefüllt werden. time.sleep(5) bricht das Programm ab bis die Zeit um ist und damit kann ich natürlich auch das Fenster nicht mehr kontrollieren. Das war mir schon klar, dass es daran liegt.

@__deets__ ich werde mir noch ziemlich viel durchlesen ich wollte nur einen Anhaltspunkt wo ich anfangen werde zu suchen. Ich werde mein Projekt neu anfangen und erstmal versuchen eine GUI mit einer Aufgabe zu erzeugen.

@peterpy Das Script deaktiviert den Start Button für 3 Sekunden, nach 3 Sekunden wird er wieder freigeschalten und auf 0 Sekunden gesetzt, sodass der Zähler von vorne beginnt. Scheint aber nicht zu sein wonach ich suche.

Danke für die Antworten. Ich werde mal im Forum nach einer GUI suchen um mein Projekt neu aufzubauen, nachdem das so nicht funktioniert. Wie deets geschrieben hat, kann man die Buttons nur mit kleinen Aufgaben belegen ansonsten wird die GUI unbrauchbar. Schließlich läuft ein langer Code auf einem Button und dieser kann wohl erst wieder verwendet werden, wenn die Aufgabe ausgeführt wurde. Durch meine endlose while-Schleife wird der Button also niemals wieder frei.
Benutzeravatar
grubenfox
User
Beiträge: 436
Registriert: Freitag 2. Dezember 2022, 15:49

Wobei der von __deets__ genannte Thread auch ein Process sein könnte, womit wir statt beim threading dann beim multiprocessing wären.
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo Borokai ,
ich hab das Beispiel erweitert und das inaktiv setzen der Taste auskommentiert.
Betätige im Abstand von zwei drei Sekunden die Taste Start und schau was passiert.
Dann begreifst Du, warum die Taste Start während des Zählens inaktiv sein soll.
Das Beispiel soll dir zeigen, dass die Gui auch während des Zählens funktioniert.

Code: Alles auswählen

import tkinter as tk
import time
from functools import partial

def zaehle(taste_start, anzeige, zahl, zaehler):    
    #taste_start.config(state='disabled')
    zaehler += 1    
    print(zaehler)    
    ident = taste_start.after(2000, zaehle, taste_start, anzeige, zahl, zaehler)
    if zaehler > 10:
        taste_start.config(state='normal')
        zaehler = 0
        taste_start.after_cancel(ident)
    zahl.set(zaehler)

def zeige_zeit(zeit_var):    
    zeit = time.strftime('%H:%M:%S')
    zeit_var.set(zeit)
    
def main():
    root=tk.Tk()
    zahl = tk.StringVar()
    zeit_var = tk.StringVar()
    zaehler = 0
    rahmen_links = tk.Frame(root)
    rahmen_rechts = tk.Frame(root)
    anzeige = tk.Label(rahmen_links, textvariable=zahl, width=5)
    taste_start = tk.Button(rahmen_links, text='Start', bg='green')
    taste_start.config(command=partial(zaehle, taste_start, anzeige,
                                         zahl, zaehler))
    tk.Button(rahmen_rechts, text='Zeit anzeigen', bg='lightgreen',
              command=partial(zeige_zeit, zeit_var)).pack(fill='x')
    feld_zeit = tk.Label(rahmen_rechts, textvariable=zeit_var)
    rahmen_links.pack(side='left')
    rahmen_rechts.pack(side='right')
    taste_start.pack()
    anzeige.pack()
    feld_zeit.pack(fill='x')
    root.mainloop()

if __name__ == "__main__":
    main()
Gruss Peter
Antworten