Event_handler?

Fragen zu Tkinter.
Antworten
GHoeberth
User
Beiträge: 8
Registriert: Mittwoch 27. August 2014, 17:44

Ich arbeite an einen Grafik Programm, das Berechnungen anzeigen soll - WÄHREND sie berechnet werden.
Also ähnlich einem Fraktalprogramm, bei dem man zusehen kann, wie das Fraktal entsteht.
Zudem sollte man die Berechnung abbrechen können, indem man auf einen Stop-Button drückt.

Aber wenn man mit einem Knopfdruck die Berechnung startet, bleibt der Knopf , bis die Berechnung zu Ende ist.
Erst danach, nimmt das Programm überhaupt neue Befehle an?

Wie kann ich die Zeichnung während der Berechnung anzeigen lassen und wie das Programm unterbrechen?

Hier mein Code:

Code: Alles auswählen

from tkinter import *
import tkinter.ttk as ttk
import PIL
import PIL.Image
import PIL.ImageTk
import PIL.ImageDraw


class PicDatei:
    def __init__(self, aufl: int):
        self.Aufloesung = aufl
        self.image = PIL.Image.new(
            "RGB", (self.Aufloesung, self.Aufloesung), (0, 0, 0))


def draw_pic():
    print('draw_pic')
    bildgroesse = 400
    global Zeichnung
    global Groesse
    Zeichnung = PicDatei(int(bildgroesse))
    Breite = w.Canvas1.winfo_width()
    Hoehe = w.Canvas1.winfo_height()

    if Breite <= Hoehe:
        Groesse = Breite
    else:
        Groesse = Hoehe

    Zeichnung.image2 = Zeichnung.image.resize((Groesse, Groesse), resample=0)
    w.Canvas1.image = PIL.ImageTk.PhotoImage(Zeichnung.image2)
    w.Canvas1.create_image(0, 0, image=w.Canvas1.image, anchor="nw")
    ''' hier soll irgeneine komplizierte Funktion ausgeführt werden
        die vom User auf dem Bildschirm mitverfolgt werden kann 
        (also immer wieder redraw des Bildes an Canvas1)
        Wenn der User den Stop-Button drückt, wird das Zeichnen unterbrochen'''
    d = PIL.ImageDraw.Draw(Zeichnung.image)
    for cycl in range(0, 20, 1):
        for y in range(0, bildgroesse, 1):
        
            '''Hier sollte die Zeichnung aktualisiert werden 
            und überprüft werden, ob der Stop-Button gedrückt wurde
            Wenn ja, dann "break" '''
            
            for x in range(0, bildgroesse, 1):
                pixel = (x, y)
                r, g, b = Zeichnung.image.getpixel(pixel)
                rgb = ((x+y+b) % 255, (x+r) % 255, (y+g) % 255)
                d.point(pixel, fill=rgb) 

    Zeichnung.image2 = Zeichnung.image.resize((Groesse, Groesse), resample=0)
    w.Canvas1.image = PIL.ImageTk.PhotoImage(Zeichnung.image2)
    w.Canvas1.create_image(0, 0, image=w.Canvas1.image, anchor="nw")

    


def stop_draw():
    print('stop_draw')
    sys.stdout.flush()


def init(top, gui, *args, **kwargs):
    global w, top_level, root
    w = gui
    top_level = top
    root = top


def destroy_window():
    # Function which closes the window.
    global top_level
    top_level.destroy()
    top_level = None


def vp_start_gui():
    global val, w, root
    root = Tk()
    top = New_Toplevel_1(root)
    init(root, top)
    root.mainloop()


def destroy_New_Toplevel_1():
    global w
    w.destroy()
    w = None


class New_Toplevel_1:
    def __init__(self, top=None):
        _bgcolor = '#e4e0d3'  # Closest X11 color: 'AntiqueWhite2'
        _fgcolor = '#000000'  # X11 color: 'black'
        _compcolor = '#d2d6e2'  # Closest X11 color: 'gray85'
        _ana1color = '#dee2d2'  # Closest X11 color: 'gray86'
        _ana2color = '#e2d6d2'  # Closest X11 color: 'gray85'

        top.geometry("574x450+442+293")
        top.title("New Toplevel 1")

        self.Canvas1 = Canvas(top)
        self.Canvas1.place(relx=0.24, rely=0.04, relheight=0.92, relwidth=0.72)
        self.Canvas1.configure(width=416)

        self.Button1 = Button(top)
        self.Button1.place(relx=0.03, rely=0.09, height=24, width=107)
        self.Button1.configure(command=draw_pic)
        self.Button1.configure(text='''Draw''')

        self.Button2 = Button(top)
        self.Button2.place(relx=0.03, rely=0.18, height=24, width=107)
        self.Button2.configure(command=stop_draw)
        self.Button2.configure(text='''Stop''')


if __name__ == '__main__':
    vp_start_gui()
Wäre dankbar für ein paar Tipps, wie man das lösen könnte.
Danke
herzlichen Gruß
Gerhard
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bei GUIs darfst du den mainloop nicht lange aufhalten. In tkinter ist die Loesung einen Timer zu benutzen. Den bekommst du mit der after-Methode (wird hier viel diskutiert, einfach mal ein bisschen durch die Archive wuehlen). Und dann baust du deinen Code entweder so, dass er stueckweise laufen kann (zB als Generator), oder du laesst den in einem eigenen Thread laufen & fuellst eine Queue mit Zwischenschritten, die dann per Timer geleert und angezeigt werden.

Was NICHT FUNKTIONIERT: aus dem Thread direkt GUI-Elemente manipulieren. Auch wenn das gegebenenfalls so aussieht als ob, ist das ein Weg der frueher oder spaeter zu harten Abstuerzen fuehrt, und darum nicht betreten werden darf.
GHoeberth
User
Beiträge: 8
Registriert: Mittwoch 27. August 2014, 17:44

danke schon mal für die schnelle Antwort.
werde mich im Forum nach den von dir genannten Stichwörtern umsehen.
Antworten