Ich bin Anfänger und arbeite mit DrPython unter Linux.
Mein problem ist, dass mit mainloop() eine Grafik nach der Berechnung am Bildschirm dargestellt wird. Ich möchte jedoch, dass die Grafik schon während der Berechnung sichtbar ist und ich so die Zeichnungsschritte sehen kann.
Wie kann ich mainloop() abändern, dass dies möglich ist.
Ich importiere Tkinter.
Danke!
Eine Grafik soll immer sichtbar sein, auch während der Berechnungen
-
- User
- Beiträge: 206
- Registriert: Freitag 13. März 2015, 18:36
Könntest du vielleicht den Code zeigen?
Unter mainloop() kann ich mir jetzt nicht so viel vorstellen.
Unter mainloop() kann ich mir jetzt nicht so viel vorstellen.
-
- User
- Beiträge: 5
- Registriert: Donnerstag 4. August 2016, 18:11
Ich schicke hier den Code dazu. Das Programm soll eine analoge Uhr werden. Dazu muss allerdings das Ziffernblatt immer sichtbar sein und das bekomme ich nicht her. Mainloop stellt die fertige Grafik dann dar. Aber das möchte ich nicht. Danke für die Unterstützung!
Hier der Code:
Hier der Code:
Code: Alles auswählen
from Tkinter import *
from math import *
from time import *
master = Tk()
canvas_width = 1290
canvas_height = 780
w = Canvas(master,
width=canvas_width,
height=canvas_height)
w.pack()
def Kreis(canvas,x,y,r):
id = canvas.create_oval(x-r,y-r,x+r,y+r,fill = 'yellow')
return id
def Zeiger(canvas,lx,ly,llx,lly):
id = canvas.create_line(lx,ly,llx,lly,fill = 'red')
return id
def Zeiger_loeschen(canvas,lx,ly,llx,lly):
id = canvas.create_line(lx,ly,llx,lly,fill = 'yellow')
return id
def Uhreinteilung(canvas,lx,ly,r):
laenge = 40
w.create_line(lx,ly-r+laenge/2,lx,ly-r-laenge/2,fill = 'blue')
w.create_line(lx+r-laenge/2,ly,lx+r+laenge/2,ly,fill = 'blue')
w.create_line(lx,ly+r-laenge/2,lx,ly+r+laenge/2,fill = 'blue')
w.create_line(lx-r-laenge/2,ly,lx-r+laenge/2,ly,fill = 'blue')
def Uhreinteilung_fein(canvas,lx,ly,r):
laenge = 20
for i in range(0,360,30):
rand_x_1 = lx+(r+laenge/2)*cos(pi/180*i)
rand_y_1 = ly+(r+laenge/2)*sin(pi/180*i)
rand_x_2 = lx+(r-laenge/2)*cos(pi/180*i)
rand_y_2 = ly+(r-laenge/2)*sin(pi/180*i)
w.create_line(rand_x_1,rand_y_1,rand_x_2,rand_y_2,fill ='blue')
a = canvas_width/2
b = canvas_height/2
c = 300
Kreis(w,a,b,c)
Uhreinteilung(w,a,b,c)
Uhreinteilung_fein(w,a,b,c)
zeigerlaenge = 250
for i in range(0,360,10):
a_neu = a + zeigerlaenge*cos(pi/180*i)
b_neu = b + zeigerlaenge*sin(pi/180*i)
Zeiger(w,a,b,a_neu,b_neu)
sleep(1.0)
Zeiger_loeschen(w,a,b,a_neu,b_neu)
mainloop()
Zuletzt geändert von Anonymous am Freitag 26. August 2016, 10:13, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
@Kurt_Schwaz: GUI-Programmierung funktioniert anders. Da hat man selbst nicht die (volle) Kontrolle über den Programmablauf, in dem man ein Programm schreibt das linear so ausgeführt wird wie es im Quelltext steht, sondern der Programmablauf wird von der GUI-Hauptschleife gesteuert und voran getrieben. Man schreibt Code der die GUI aufsetzt und registriert dann Rückruffunktionen/-methoden die bei bestimmten Ereignissen von der GUI-Hauptschleife aufgerufen werden, kurz etwas machen, und dann die Kontrolle wieder an diese Schleife zurück geben.
Hier müsstest Du anstelle der Schleife zum Beispiel mit der `after()`-Methode auf Widgets arbeiten, mit der man eine Zeit in Millisekunden, eine Funktion, und optional Argumente für diese Funktion, für einen späteren Aufruf registrieren kann.
Ausserdem enthält das Programm von Ansatz her noch einen Fehler: `Canvas` ist Vektorgrafik, das heisst man zeichnet da tatsächlich geometrische Figuren die als Objekte im Speicher angelegt und bei Änderungen immer wieder übereinandergemalt werden. Wenn das Programm abgelaufen ist, dann existieren in der Grafik 72 Linien für den Zeiger. Statt also für's löschen eine neue Linie über die alten Zeigerlinien zu zeichnen, sollte man nur *eine* Linie für den Zeiger verwenden und die entweder tatsächlich löschen, oder aber deren Koordinaten anpassen/verändern um den Zeiger weiter zu rücken.
Sonstige Anmerkungen: Lass das mit den Sternchen-Importen bleiben. Damit holst Du dir im Falle von `Tkinter` ca. 190 Namen in das Modul. Module machen keinen Sinn wenn man am Ende doch alles per *-Import wieder in einem Namensraum zusammen wirft. Das Programm ist dann schwerer zu verstehen, weil man nicht sieht welcher Name woher kommt. Und es besteht die Gefahr von Namenskollisionen.
Auf Modulebene gehören nur Definitionen von Konstanten, Funktionen, und Klassen. Variablen und anderer Code gehören in Funktionen und/oder Klassen. Wenn man dann auch noch das Hauptprogramm auf Modulebene mit Funktionsdefinitionen vermischt wird es noch unübersichtlicher. Das Hauptprogramm sollte auch deswegen in einer Funktion stehen, damit man das Modul so schreiben kann, das man es importieren kann, ohne dass das Hauptprogramm ausgeführt wird. Nur so kann man einzelne Funktionen/Klassen interaktiv oder automatisiert testen und auch einige Werkzeuge zur statischen Analyse oder Dokumentationserzeugung erwarten das so.
Die Namensschreibweise hält sich nicht an den Style Guide for Python Code. Konstanten werden komplett in Grossbuchstaben geschrieben. Funktionsnamen komplett klein. Einbuchstabige Namen sind in der Regel keine guten Namen. Funktionsnamen beschreiben üblicherweise eine Tätigkeit weil die etwas tun, und um sie von eher passiven Werten unterscheiden zu können.
Nach Kommas und um binäre Operatoren machen sich aus Gründen der Lesbarkeit Leerzeichen ganz gut.
Es macht wenig Sinn einen Wert an einen Namen zu binden, wenn der Name nur dazu verwendet wird den Wert gleich in der nächsten Zeile an den Aufrufer zurück zu geben.
Hier müsstest Du anstelle der Schleife zum Beispiel mit der `after()`-Methode auf Widgets arbeiten, mit der man eine Zeit in Millisekunden, eine Funktion, und optional Argumente für diese Funktion, für einen späteren Aufruf registrieren kann.
Ausserdem enthält das Programm von Ansatz her noch einen Fehler: `Canvas` ist Vektorgrafik, das heisst man zeichnet da tatsächlich geometrische Figuren die als Objekte im Speicher angelegt und bei Änderungen immer wieder übereinandergemalt werden. Wenn das Programm abgelaufen ist, dann existieren in der Grafik 72 Linien für den Zeiger. Statt also für's löschen eine neue Linie über die alten Zeigerlinien zu zeichnen, sollte man nur *eine* Linie für den Zeiger verwenden und die entweder tatsächlich löschen, oder aber deren Koordinaten anpassen/verändern um den Zeiger weiter zu rücken.
Sonstige Anmerkungen: Lass das mit den Sternchen-Importen bleiben. Damit holst Du dir im Falle von `Tkinter` ca. 190 Namen in das Modul. Module machen keinen Sinn wenn man am Ende doch alles per *-Import wieder in einem Namensraum zusammen wirft. Das Programm ist dann schwerer zu verstehen, weil man nicht sieht welcher Name woher kommt. Und es besteht die Gefahr von Namenskollisionen.
Auf Modulebene gehören nur Definitionen von Konstanten, Funktionen, und Klassen. Variablen und anderer Code gehören in Funktionen und/oder Klassen. Wenn man dann auch noch das Hauptprogramm auf Modulebene mit Funktionsdefinitionen vermischt wird es noch unübersichtlicher. Das Hauptprogramm sollte auch deswegen in einer Funktion stehen, damit man das Modul so schreiben kann, das man es importieren kann, ohne dass das Hauptprogramm ausgeführt wird. Nur so kann man einzelne Funktionen/Klassen interaktiv oder automatisiert testen und auch einige Werkzeuge zur statischen Analyse oder Dokumentationserzeugung erwarten das so.
Die Namensschreibweise hält sich nicht an den Style Guide for Python Code. Konstanten werden komplett in Grossbuchstaben geschrieben. Funktionsnamen komplett klein. Einbuchstabige Namen sind in der Regel keine guten Namen. Funktionsnamen beschreiben üblicherweise eine Tätigkeit weil die etwas tun, und um sie von eher passiven Werten unterscheiden zu können.
Nach Kommas und um binäre Operatoren machen sich aus Gründen der Lesbarkeit Leerzeichen ganz gut.
Es macht wenig Sinn einen Wert an einen Namen zu binden, wenn der Name nur dazu verwendet wird den Wert gleich in der nächsten Zeile an den Aufrufer zurück zu geben.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Eigentlich geht das doch normalerweise so schnell, das man den Aufbau eh nicht sieht, oder?Kurt_Schwaz hat geschrieben:Ich möchte jedoch, dass die Grafik schon während der Berechnung sichtbar ist und ich so die Zeichnungsschritte sehen kann.
Ansonsten mußt du halt sagen, das die Oberfläche aktualisiert werden soll. bsp: root.update()
@Kurt_Schwaz: Sternchenimporte solltest Du vermeiden, da nicht kontrolliert werden kann, was denn da alles importiert wird. Anweisungen und Definitionen sollten nicht gemischt werden, da das unleserlich ist. Zudem sollten eigentlich alle Anweisungen in einer Funktion stehen. Es sollte keine globalen Variablen geben, zudem Du canvas zwar übergibst, aber das globale w verwendest. Apropos w. Variablennamen sollten sprechend sein. Der Zeiger hat aus gutem Grund eine ID. TK-Canvas ist eine Vektorgraphik. Du erzeugst also hunderte rote Zeiger, die gleich danach wieder von gelben Zeiger übermalt werden. Statt dessen solltest Du einen Zeiger erzeugen und dessen Koordinaten einfach immer aktualisieren.
Zum Aktualisieren kennt Tk die after-Methode, die nach einer vorgegebenen Zeit aufgerufen wird. Schleifen funktionieren ja, wie Du bereits gemerkt hast, nicht.
Zum Aktualisieren kennt Tk die after-Methode, die nach einer vorgegebenen Zeit aufgerufen wird. Schleifen funktionieren ja, wie Du bereits gemerkt hast, nicht.
Code: Alles auswählen
import Tkinter as tk
from math import cos, sin, pi
canvas_width = 1290
canvas_height = 780
zeigerlaenge = 250
def Kreis(canvas,x,y,r):
return canvas.create_oval(x-r,y-r,x+r,y+r,fill = 'yellow')
def Zeiger(canvas,lx,ly,llx,lly):
return canvas.create_line(lx,ly,llx,lly,fill = 'red')
def Uhreinteilung(canvas,lx,ly,r):
laenge = 40
canvas.create_line(lx,ly-r+laenge/2,lx,ly-r-laenge/2,fill = 'blue')
canvas.create_line(lx+r-laenge/2,ly,lx+r+laenge/2,ly,fill = 'blue')
canvas.create_line(lx,ly+r-laenge/2,lx,ly+r+laenge/2,fill = 'blue')
canvas.create_line(lx-r-laenge/2,ly,lx-r+laenge/2,ly,fill = 'blue')
def Uhreinteilung_fein(canvas,lx,ly,r):
laenge = 20
for i in range(0,360,30):
rand_x_1 = lx+(r+laenge/2)*cos(pi/180*i)
rand_y_1 = ly+(r+laenge/2)*sin(pi/180*i)
rand_x_2 = lx+(r-laenge/2)*cos(pi/180*i)
rand_y_2 = ly+(r-laenge/2)*sin(pi/180*i)
canvas.create_line(rand_x_1,rand_y_1,rand_x_2,rand_y_2,fill ='blue')
def update_clock(canvas, zeiger_id, i):
a = canvas_width/2
b = canvas_height/2
a_neu = a + zeigerlaenge*cos(pi/180*i)
b_neu = b + zeigerlaenge*sin(pi/180*i)
canvas.coords(zeiger_id, a, b, a_neu, b_neu)
canvas.after(1000, update_clock, canvas, zeiger_id, i+1)
def main():
master = tk.Tk()
canvas = tk.Canvas(master, width=canvas_width, height=canvas_height)
canvas.pack()
a = canvas_width/2
b = canvas_height/2
c = 300
Kreis(canvas, a, b, c)
Uhreinteilung(canvas, a, b, c)
Uhreinteilung_fein(canvas, a, b, c)
zeiger_id = Zeiger(canvas, a, b, a, b)
update_clock(canvas, zeiger_id, 0)
master.mainloop()
if __name__ == '__main__':
main()
Ich hatte mich da auch mal dran ausgetobt.
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import Tkinter as tk
from math import cos, pi as PI, sin
CANVAS_WIDTH = 1290
CANVAS_HEIGHT = 780
def zeichne_kreis(canvas, x, y, radius):
return canvas.create_oval(
x - radius, y - radius, x + radius, y + radius, fill='yellow'
)
def zeichne_zeiger(canvas, x_1, y_1, x_2, y_2):
return canvas.create_line(x_1, y_1, x_2, y_2, fill='red')
def loesche_zeiger(canvas, zeiger_id):
canvas.delete(zeiger_id)
def zeichne_uhreinteilung(canvas, x, y, radius, laenge=20):
canvas.create_line(
x, y - radius + laenge, x, y - radius - laenge, fill='blue'
)
canvas.create_line(
x + radius - laenge, y, x + radius + laenge, y, fill='blue'
)
canvas.create_line(
x, y + radius - laenge, x, y + radius + laenge, fill='blue'
)
canvas.create_line(
x - radius - laenge, y, x - radius + laenge, y, fill='blue'
)
def zeichne_uhreinteilung_fein(canvas, x, y, radius, laenge=10):
for winkel in xrange(0, 360, 30):
canvas.create_line(
x + (radius + laenge) * cos(PI / 180 * winkel),
y + (radius + laenge) * sin(PI / 180 * winkel),
x + (radius - laenge) * cos(PI / 180 * winkel),
y + (radius - laenge) * sin(PI / 180 * winkel),
fill='blue'
)
def aktualisiere_zeiger(canvas, center_x, center_y, winkel, zeiger_id=None):
if zeiger_id:
loesche_zeiger(canvas, zeiger_id)
if winkel < 360:
zeigerlaenge = 250
canvas.after(
1000,
aktualisiere_zeiger,
canvas,
center_x,
center_y,
winkel + 10,
zeichne_zeiger(
canvas,
center_x,
center_y,
center_x + zeigerlaenge * cos(PI / 180 * winkel),
center_y + zeigerlaenge * sin(PI / 180 * winkel)
)
)
def main():
root = tk.Tk()
canvas = tk.Canvas(root, width=CANVAS_WIDTH, height=CANVAS_HEIGHT)
canvas.pack()
center_x = CANVAS_WIDTH / 2
center_y = CANVAS_HEIGHT / 2
radius = 300
zeichne_kreis(canvas, center_x, center_y, radius)
zeichne_uhreinteilung(canvas, center_x, center_y, radius)
zeichne_uhreinteilung_fein(canvas, center_x, center_y, radius)
aktualisiere_zeiger(canvas, center_x, center_y, 0)
root.mainloop()
if __name__ == '__main__':
main()
-
- User
- Beiträge: 5
- Registriert: Donnerstag 4. August 2016, 18:11
Danke, Sirius3, für Deine ausführliche Lösung und Beschreibung! Ich probiere es aus.
Danke!
Danke!
-
- User
- Beiträge: 5
- Registriert: Donnerstag 4. August 2016, 18:11
Danke für die ausführlichen Hilfen! Ich sehe nun auch den Sinn!
Danke!!
Ciao
Kurt
Danke!!
Ciao
Kurt
@Sirius3 Deine Uhr läuft prima mit zwei kleinen Änderungen
Und in der main-Funktion
Code: Alles auswählen
def update_clock(canvas, zeiger_id, i):
a = canvas_width/2
b = canvas_height/2
a_neu = a + zeigerlaenge*cos(pi/180*i)
b_neu = b + zeigerlaenge*sin(pi/180*i)
canvas.coords(zeiger_id, a, b, a_neu, b_neu)
canvas.after(1000, update_clock, canvas, zeiger_id, i+1)
# hier i+6, dann rückt sie im Sekundentakt vor
Code: Alles auswählen
update_clock(canvas, zeiger_id, 0)
# hier anstelle 0, -90 als Startpunkt, dann beginnt sie bei 12 bzw. 0 Uhr
-
- User
- Beiträge: 5
- Registriert: Donnerstag 4. August 2016, 18:11
Herzlichen Dank!