Seite 1 von 1

GUI Button richtig verwenden?

Verfasst: Mittwoch 26. April 2023, 13:28
von Borokai
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.

Re: GUI Button richtig verwenden?

Verfasst: Mittwoch 26. April 2023, 14:30
von Kebap
Schau mal nach, was time.sleep(5) bewirkt.

Re: GUI Button richtig verwenden?

Verfasst: Mittwoch 26. April 2023, 14:46
von __deets__
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.

Re: GUI Button richtig verwenden?

Verfasst: Mittwoch 26. April 2023, 15:22
von peterpy
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

Re: GUI Button richtig verwenden?

Verfasst: Mittwoch 26. April 2023, 20:53
von Borokai
@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.

Re: GUI Button richtig verwenden?

Verfasst: Donnerstag 27. April 2023, 09:10
von grubenfox
Wobei der von __deets__ genannte Thread auch ein Process sein könnte, womit wir statt beim threading dann beim multiprocessing wären.

Re: GUI Button richtig verwenden?

Verfasst: Donnerstag 27. April 2023, 09:18
von peterpy
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