Seite 1 von 1

Tkinter GUI aktualisieren

Verfasst: Dienstag 28. Oktober 2014, 13:28
von M4rcde
Hallo Profis,

ich weiß jetzt schon, dass dieser Thread sicherlich schon mehrfach erstellt wurde, habe ihn aber leider nicht gefunden (unterschiedliche Definitionen des Problems).
Ich schreibe gerade mein erstes Programm in Tkinter.
Ich habe schon die Canvas erstellt und auch schon Kreise an bestimmten Punkten "ausgegeben".
Mein Programm soll allerdings diesen Kreis (hängt von Radius r ab) alle 2 Sekunden aktualisieren. Das würde ich mit einer while-Schleife und time.sleep() realisieren.
Dennoch stell sich die Frage, wie kann ich die GUI verändern (alten Kreis löschen, neuen mit anderem Radius anzeigen), wenn bereits diese Tkinter.mainloop() ausgeführt wurde?
Hab mir schon diverses Zeug zu text updates durchgelesen, beidenen einfach der Text verändert wird, aber wie verändere ich einen Kreis?

Danke euch im vorraus für Antworten und Tipps.

Marc

Re: Tkinter GUI aktualisieren

Verfasst: Dienstag 28. Oktober 2014, 13:52
von BlackJack
@M4rcde: Mit Schleife und `sleep()` geht das nicht weil die `mainloop()` ja schon läuft und auch laufen muss damit die GUI ordentlich dargestellt wird.

Du müsstest mit der `after()`-Methode auf Widgets arbeiten und immer wieder eine Funktion/Methode registrieren die in x Sekunden ausgeführt werden soll, dann kurz etwas macht, und die Kontrolle wieder an die GUI-Hauptschleife zurück gibt.

Löschen brauchst Du die Kreise nicht, wenn Du Dir die IDs merkst, kannst Du die Eigenschaften der Grafikelemente darüber später auch wieder ändern.

Re: Tkinter GUI aktualisieren

Verfasst: Dienstag 28. Oktober 2014, 20:58
von M4rcde
Damn, ich bekomm after() net hin....
haste ein simples Beispiel parat für Kreise?


Danke schonmal ;)
Marc

Re: Tkinter GUI aktualisieren

Verfasst: Dienstag 28. Oktober 2014, 21:08
von M4rcde
Gerade sieht der Code so aus:

Code: Alles auswählen

import Tkinter
import time

master = Tkinter.Tk()

canvas_width = 900
canvas_height = 400
w = Tkinter.Canvas(master, 
           width=canvas_width,
           height=canvas_height)


def circle(canvas,x,y, r):
   id = canvas.create_oval(x-r,y-r,x+r,y+r)
   return id


circle(w,0,0, 50)
w.pack()
Tkinter.mainloop()

Re: Tkinter GUI aktualisieren

Verfasst: Dienstag 28. Oktober 2014, 21:09
von EyDu
Benutze einfach mal die Forumsuche und suche nach Tkinter und after. Zu dem Thema gibt es hier wahrscheinlich alle zwei Wochen eine Frage.

Re: Tkinter GUI aktualisieren

Verfasst: Dienstag 28. Oktober 2014, 21:35
von M4rcde
habe ich wie gesagt schon mehrfach durchsucht. Kann mit den Codes leider wenig anfangen und die entsprechen auch nicht den Anwendungszwecken von mir.
Da muss es doch ein ganz simples Review geben. Das ist doch was ganz simples... An dem Problem sitz ich den ganzen Tag...
Unglaublich, alles was ich probier klappt net...

Re: Tkinter GUI aktualisieren

Verfasst: Mittwoch 29. Oktober 2014, 08:07
von Sirius3
@M4rcde: was probierst Du denn, und wie äußert sich das "klappt net"?

Re: Tkinter GUI aktualisieren

Verfasst: Mittwoch 29. Oktober 2014, 10:38
von wuf
Hi M4rcde

Hier etwas zum ausprobieren mit 'widget.after()':

Code: Alles auswählen

import Tkinter as tk

CANVAS_WIDTH = 400
CANVAS_HEIGHT = 400

CIRCLE_XORG = 50
CIRCLE_YORG = 50
CIRCLE_RADIUS = 50

STEP_TIME = 30 # Milliseconds
XSTEP = 1
YSTEP = 1

def move_circle():
    canvas.move("MyCircle", XSTEP, YSTEP)
    x0, y0, x1, y1 = canvas.bbox("MyCircle")
    if x1 > CANVAS_WIDTH: return
    canvas.after(STEP_TIME, move_circle)
    
def circle(x, y, r):
    canvas.create_oval(x-r, y-r, x+r, y+r, tag="MyCircle", fill='yellow')

master = tk.Tk()
master.title("Moving Circle")
master.geometry("+{}+{}".format(20,20))
 
canvas = tk.Canvas(master, width=CANVAS_WIDTH, height=CANVAS_HEIGHT)
canvas.pack() 
 
circle(CIRCLE_XORG, CIRCLE_YORG, CIRCLE_RADIUS)

move_circle()

master.mainloop()
Gruss wuf :wink:

Re: Tkinter GUI aktualisieren

Verfasst: Mittwoch 29. Oktober 2014, 10:58
von BlackJack
@wuf: Das mit den Tag finde ich ungünstig. Damit ist man entweder auf diesen einen Kreis beschränkt, beziehungsweise auf eine Gruppe von Kreisen die man immer zusammen ansprechen muss. Dann sollte das Tag 'MyCircles' heissen. Warum nicht einfach die ID des Kreises zurückgeben lassen statt ein Tag zu setzen?

Re: Tkinter GUI aktualisieren

Verfasst: Mittwoch 29. Oktober 2014, 12:24
von wuf
Hi BlackJack

Da hast du natürlich recht. Mein Versuchsskript ist nur für ein Canvasobjekt "MyCircle" gedacht sonst ergibt sich für mehrere Canvasobjekte folgendes Verhalten:

Code: Alles auswählen

import Tkinter as tk

CANVAS_WIDTH = 400
CANVAS_HEIGHT = 400

CIRCLE_XORG = 50
CIRCLE_YORG = 50
CIRCLE_RADIUS = 50

STEP_TIME = 30 # Milliseconds
XSTEP = 1
YSTEP = 1

def move_circle():
    canvas.move("MyCircle", XSTEP, YSTEP)
    x0, y0, x1, y1 = canvas.bbox("MyCircle")
    if x1 > CANVAS_WIDTH: return
    canvas.after(STEP_TIME, move_circle)
    
def circle(x, y, r):
    canvas.create_oval(x-r, y-r, x+r, y+r, tag="MyCircle", fill='yellow')

master = tk.Tk()
master.title("Moving Circle")
master.geometry("+{}+{}".format(20,20))
 
canvas = tk.Canvas(master, width=CANVAS_WIDTH, height=CANVAS_HEIGHT)
canvas.pack() 
 
circle(CIRCLE_XORG, CIRCLE_YORG, CIRCLE_RADIUS)
circle(CIRCLE_XORG+50, CIRCLE_YORG+50, CIRCLE_RADIUS)

move_circle()

master.mainloop()
Für mehrere Canvasobjekte muss deren Tag erweitert werden.

Gruss wuf :wink:

Re: Tkinter GUI aktualisieren

Verfasst: Donnerstag 30. Oktober 2014, 13:48
von M4rcde
Ich danke euch, habe also nun after() zum laufen gebracht. Allerdings funktioniert after() offensichtlich nicht in einer while-schleife, aber des bekomm ich noch hin :) Danke

Re: Tkinter GUI aktualisieren

Verfasst: Donnerstag 30. Oktober 2014, 13:54
von BlackJack
@M4rcde: Die Funktion bei `after()` darf nicht lange laufen, wie jede Rückruffunktion bei GUIs weil die GUI-Hauptschleife laufen muss wenn die GUI nicht einfrieren soll.

Man muss die Schleifenschritte in Aufrufe umorganisieren, wie das Beispiel von wuf ja zeigt. Also keine Schleife in der der Kreis in jedem durchlauf bewegt/verändert wird, sondern ein Funktionsaufruf in dem das gemacht wird was sonst in einem Schleifendurchlauf passiert und diese funktion wird dann Regelmässig von der GUI aufgerufen wenn man sie immer wieder mit `after()` dazu bringt.

Re: Tkinter GUI aktualisieren

Verfasst: Donnerstag 30. Oktober 2014, 14:00
von M4rcde
BlackJack hat geschrieben:@M4rcde: Die Funktion bei `after()` darf nicht lange laufen, wie jede Rückruffunktion bei GUIs weil die GUI-Hauptschleife laufen muss wenn die GUI nicht einfrieren soll.

Man muss die Schleifenschritte in Aufrufe umorganisieren, wie das Beispiel von wuf ja zeigt. Also keine Schleife in der der Kreis in jedem durchlauf bewegt/verändert wird, sondern ein Funktionsaufruf in dem das gemacht wird was sonst in einem Schleifendurchlauf passiert und diese funktion wird dann Regelmässig von der GUI aufgerufen wenn man sie immer wieder mit `after()` dazu bringt.
Ich danke vielmals! Werde mich da wie gesagt nun mal einlesen :) Dankeschön!