Malen, wenn Fenster schon geöffnet ist

Fragen zu Tkinter.
Antworten
Zero1234
User
Beiträge: 10
Registriert: Samstag 28. April 2012, 00:34

Hallo,
ich würde gerne auf mein canvas malen, nachdem ich das Fenster schon sehen kann. Mein Hauptprogramm stoppt aber nach dem erstellen des Fensters und läuft erst dann weiter, wenn ich das Fenster schließe. Kann ich das Fenster vielleicht in einem eigenen Thread aufrufen, oder gibt es andere, möglichst Anfänger gerechte wege mein Problem zu lösen?

Hauptprogramm:

Code: Alles auswählen

import zeichnen

x1=1
x2=1
y1=1
y2=1
bild = zeichnen.Leinwand(200,200)

while x1>0 and x2>0 and y1>0 and y2>0:
    x1=input()
    y1=input()
    x2=input()
    y2=input()
    bild.set_line(x1,x2,y1,y2)

In eigene Datei (zeichnen.py) ausgelagerte Klasse:

Code: Alles auswählen

from tkinter import *

class Leinwand():
    def __init__(self, canvas_width, canvas_height):
        master = Tk()
        global bild
        bild = Canvas(master,
           width=canvas_width,
           height=canvas_height)
        bild.pack()
        mainloop()

    def set_line(self, x1, y1, x2, y2):
        bild.create_line(x1, y1, x2, y2)

danke schonmal
BlackJack

@Zero1234: Der Aufruf der `mainloop()` kehrt erst zurück wenn das Hauptfenster zerstört wurde. Du könntest vorher eine Funktion mit der `after()`-Methode auf einem Widget zum Aufruf nach dem Anzeigen planen. Aber die sollte nicht mit `input()` blockieren, denn solange die Hauptschleife nicht läuft, wird die GUI nicht aktualisiert.

Threads sind auch keine so gute Idee weil GUI-Toolkits in der Regel nicht „thread safe” sind, das heisst man darf auch bei `tkinter` die GUI nur aus dem Thread heraus manipulieren in dem die `mainloop()` läuft.

Grundsätzlich solltest Du Dich bei GUI-Programmierung von einem linearen Programmablauf verabschieden, den *Du* komplett in der Hand hast. GUI-Programmierung bedeutet ereignisbasierte Programmierung.
Zero1234
User
Beiträge: 10
Registriert: Samstag 28. April 2012, 00:34

Vielen danke erstmal für die Antwort.
Mein Hauptprogramm mit dem Input war auch nur um mein Problem simpel zu erklären. Eigentlich brauche ich die Ausgabe für ein Zeitkritischeres Programm, das Motoren steuert und Positionsdaten davon empfängt. Ich möchte ganz zeitunkritisch vielleicht ein Paar mal pro sekunde ein Paar neue Koordinaten auf dem Bildschirm plotten, ohne dass das die Gui mein ganzes Programm anhält. Dafür müsste ich, wenn überhaupt wohl mit einem extra Thread für die GUI arbeiten, oder?

Die einzige andere Möglichkeit die mir einfällt wäre sehr umständlich...ich könnte mein Hauptprogramm die Daten in eine Datenbak schreiben lassen und ein Programm machen, das nur für die Gui da ist und mit der after()-Methode nach einiger Zeit ein paar neue Daten aus der gleichen Datenbak ausliest. simpler wäre mir allerdings lieber.
BlackJack

@Zero1234: Wenn Thread dann die Arbeit dort hin verlagern und nicht die GUI und dann brauchst Du keine Datenbank sondern kannst die Threads über eine `Queue.Queue` kommunizieren lassen. Also Dein Arbeitsthread schreibt da Werte rein und bei der GUI schaust Du mit `after()` regelmässig in die Queue ob etwas zum Anzeigen vorliegt.
Zero1234
User
Beiträge: 10
Registriert: Samstag 28. April 2012, 00:34

Vielen Dank, das klingt nach einem Plan. Werd mir die Sache mit den Threads mal ansehen.
schönen Abend noch
Zero1234
User
Beiträge: 10
Registriert: Samstag 28. April 2012, 00:34

Ich habe mich heute erst für Tkinter entschieden, weil das zeichnen dort am einfachsten ist, aber gibt es vielleicht GUI-Toolkits, bei denen ich nicht auf Threads zurückgreifen muss? Qt zum beispiel?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nein. Wie BlackJack schon schrieb, arbeiten GUIs ereignisbasiert. BlackJack hat eigentlich auch schon genau beschrieben wie man die Aufgabe umsetzen kann.
Das Leben ist wie ein Tennisball.
Antworten