Anfängerchen bittet um Hilfe

Fragen zu Tkinter.
addili
User
Beiträge: 7
Registriert: Samstag 10. Mai 2008, 09:43

Montag 12. Mai 2008, 21:01

Hallo erst mal!
Ich habe in meinem Infokurs ein Projekt aufbekommen.
Und zwar handelt es sich dabei um ein Sonnensystem das sich natürlich dreht und die Geschwindigkeit soll mit Buttons verstellbar sein.
Das war bis dahin ja kein Problem...
ABER... wie Informatiklehrer so sind hatte auch meiner etwas zu mekern.
(Gruß an Herr Schulz *räusper*)
Und zwar soll sich der Standpunkt der Sonne, die Distanz der Planeten. Größe etc verändern wenn der Canvas größer gezogen oder verkleinert wird.
Dazu brauche ich natürlich einen Befehl der mir sagt wie groß der Canvas nach dem verziehen ist!
Mein Leher meinte es würde mit cget funktionieren aber, wie er dann selbst rausfand, funktionierte das nicht.
Auch bei google etc habe ich nichts dazu gefunden.
Außerdem stellt sich ja noch die Frage wie ich das machen soll wenn Höhe und Breite unterschiedlich sind?
Ich könnte es dann natürlich von der kleineren abhängik machen das auch Pluto immer im Bild ist^^
Gibt es vielleicht eine Möglichkeit es nicht zu zulassen Breite und Höhe unterschiedliche Werte bekommen?

Freue mich über Anregungen, Antworten und Beispiele

Danke schonmal und liebe Grüße

Addili
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Montag 12. Mai 2008, 21:13

Hallo und willkommen im Forum,

magst Du uns auch verraten welches Toolkit Du verwendest? (Woher kommt der "Canvas"?) Ggf. wäre auch etwas Code nicht schlecht. Den kannst Du hier im Forum oder wenn es viel Code ist auch hier posten. Denn je spezifischer Deine Information, desto leichter ist es zu antworten

Gruß,
Christian

PS Der Threadtitel ist nicht gerade sehr aussagekräftig. Dieser Eintrag hilft Dir vielleicht beim nächsten Thread mehr Erfolg zu haben ;-) .
addili
User
Beiträge: 7
Registriert: Samstag 10. Mai 2008, 09:43

Montag 12. Mai 2008, 21:29

Hi nochmal
und erst mal danke für die Tipps!
Ich weiß nicht ob das das richtige ist aber so erstelle ich den Canvas:
(leider hab ich keine Ahnung wie ich das so schoen mach wie die anderen hier im Forum also musses so auch gehenxD)

from Tkinter import*
...
...
...
fenster = Tk()
zeichnen = Canvas(fenster)
zeichnen['width']=breite
zeichnen['height']=breite
zeichnen['bg']='white'
zeichnen.pack(side="top",expand=1,fill="both")

Ich hoffe mal du kanns dem die nötigen Informationen entnehmen
und freu mich wenn du (oder jemand anderes) mir helfen könnte

Edit (Leonidas): Verschoben.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Montag 12. Mai 2008, 22:45

Code: Alles auswählen

zeichnen.cget('width')
zeichnen.cget('height')
:?:

Kenne mich mit Tkinter aber nicht so dolle aus ...

HTH
Christian
addili
User
Beiträge: 7
Registriert: Samstag 10. Mai 2008, 09:43

Montag 12. Mai 2008, 22:57

Die Idee hatte mein Infolehrer auch
doch wenn ich da hinschreib:

höhe = zeichnen.cget("height")
print höhe

und das dann halt in einer unendlichen Schleife laufen lasse verändert sich nichts beim Canvas...

trotzdem Danke
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Montag 12. Mai 2008, 23:18

Wenn ich Dich wörtlich nehme, dann holst Du zwar die die Höhe (oder die Breite), machst aber nichts damit. In Deinem ersten Post hier hast Du geschrieben, daß Du davon abängig die Position einiger Planten ändern willst. Das mußt Du auch machen. (Oder stehe ich hier irgendwo fürchterlich auf dem Schlauch?)
EyDu
User
Beiträge: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Montag 12. Mai 2008, 23:20

addili hat geschrieben:und das dann halt in einer unendlichen Schleife laufen lasse verändert sich nichts beim Canvas...
Das hast du sicherlich nach dem Start der mainloop getan, da passiert dann sicher nichts.

Die Suche hilft übrigens weiter http://www.python-forum.de/viewtopic.ph ... 71f62c9f01
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Dienstag 13. Mai 2008, 07:24

addili hat geschrieben:Die Idee hatte mein Infolehrer auch
Wie kann dir dein Lehrer eine solche Aufgabe stellen, wenn er selbst nicht weiß, wie es geht. Vielleicht geht es ja gar nicht, und du sollst es machen ....
Das finde ich schon eigenartig.

In diesem Fall kann ich dich aber beruhigen - es geht mit Tkinter.
Aber nicht so, wie dein Lehrer und du euch das gedacht habt.
Wie es geht, kann man in der einschlägigen Doku aber nachlesen. :wink:

Konkret:

Code: Alles auswählen

import Tkinter as tk

def formatausgabe(ereignis):
    print "Breite: %i px" %leinwand.winfo_width()
    print "Hoehe: %i px" %leinwand.winfo_height()

fenster = tk.Tk()
leinwand = tk.Canvas(fenster)
leinwand.pack(expand=True,fill="both")
leinwand.bind("<Configure>",formatausgabe)
tk.mainloop()
addili
User
Beiträge: 7
Registriert: Samstag 10. Mai 2008, 09:43

Dienstag 13. Mai 2008, 09:01

Um erst mal auf ein paar Feagen einzugehen:

@CM: Natürlich habe ich vor mit den Angaben auch was zu machen wie zB 1/2 Breite ist der Mittelpunkt der Sonne (nur ein Beispiel, ich weiß das es nicht besonders sinnvoll ist) aber um sowas machen zu können muss ich natürlich erst mal die Angaben vom Canvad haben^^

@EyDu: Nein ich habe es nicht nach mainloop laufen lassen ich bin zwr ein Anfänger aber sooo Anfängermäßig auch wieder nicht... Bei mir sieht das ganze dann so aus:

Code: Alles auswählen

while (1==1):
        if(feld.stop==0):
                merkur.MOVE(feld.zeichnen)
                venus.MOVE(feld.zeichnen)
                erde.MOVE(feld.zeichnen)
                mond_erde.MOVE(feld.zeichnen)
                ....
                ....
                my_breite = feld.zeichnen.cget("height")
        print my_breite
        feld.zeichnen.update()
fenster.mainloop()
Die Objekte sind vorher natürlich alle Difiniert und ich brauche die Schleife Damit der nächste Punkt des Planeten immer wieder berechnet wird und verschwindet und gezeigt wird (Unterprogramm 'MOVE'). Die Alternative hängt mit einem Stop-Button zusammen.
Also wie du sehen müstest... eigentlich müsste es funktionieren wenn es gehen würde...


@pütone: Danke erst mal für den Tipp aber leider wieß ich nicht wirklich wie ich das verwirklichen sollte...
Es ist ja so, dass bei mir das Universum eine eigene Klasse ist. Dort wird im Init das Feld erstellt und somit auch der Canvas. Wie soll ich das dann auf die Schleife übertragen? Außerdem bräuchte ich ja schon irgendeinen Datencontainer indem die Zahl steht und verändert wird...
Ist das jetzt so das Höhe und Breite nicht unterschiedlich sein können? Ich hoffe du vezeihst das ich damit 'leicht' überfordert binxD
Also vei mir sieht das so aus... Bitte um hiiiifle...
(darunter stehen noch ein paar Buttont und die dazugehörigen Unterprogramme etc aber die interessieren ja nicht)

Code: Alles auswählen

class Universum:
        
        def __init__(self, fenster, breite):
                self.text  = "STOP"
                self.stop  = 0
                self.gesch = 0.02
                self.zeichnen = Canvas(fenster)
                self.zeichnen['width']=breite
                self.zeichnen['height']=breite
                self.zeichnen['bg']='white'
                self.zeichnen.pack(side="top",expand=1,fill="both")
PS.: man merkt das du noch nie am an meinem kleinem Gymnasium Infounterricht hattest denn da kommt sowas öffters vor... Auch meine Sinus Cosinus-Formel habe ich mir aus Pascal (mein Varter ist Informatiker, hat aber leider nie Python gelernt) umschreiben weil er mir nicht weterhelfen konnte...




Zum Abschluss noch mal danke an alle die mir bis jetzt geholfen haben!

Edit (BlackJack): Code-Tags gesetzt.
BlackJack

Dienstag 13. Mai 2008, 11:27

@addili: Das sieht aber doch so aus, als wenn Du die `mainloop()` noch nicht verstanden hast. Du führst eine Endlosschleife *vor* der `mainloop()` aus, dass heisst die GUI wird nie gestartet.

Bei GUI-Programmierung muss man sich von einem grösstenteils linearen Programmablauf verabschieden und ereignisbasiert arbeiten. Alles vor dem Aufruf von `mainloop()` dient dem "Aufsetzen" des Programms. Wenn nicht nur Benutzer Ereignisse erzeugen können sollen, in dem sie zum Beispiel auf einen Button klicken oder die Fenstergrösse ändern, sondern auch regelmässig etwas passieren soll, muss man zum Beispiel die `after()`-Methode auf Widgets verwenden.

Ich würde allerdings erst einmal die Universum-Simulation ohne GUI implementieren und Simulation und GUI sauber von einander trennen.

Weitere Anmerkungen zum Quelltext: Um Bedingungen muss man keine Klammern setzen und ``1==1`` kann man direkter als `True` schreiben.

Die Himmelskörper könnte man in eine Liste stecken.

`zeichnen` scheint wohl ein `Canvas` zu sein, und ist damit ein ungeeigneter Name. Verben sind eigentlich nur für Methoden geeignet. Und komplett gross geschriebene Namen stehen konventionell für Konstanten -- `MOVE()` sollte also `move()` heissen.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Dienstag 13. Mai 2008, 11:29

@pütone: Wenn man fill='both' weglässt und den Canvas-Background auf weiß setzt, sieht man, dass sich die Größe des Canvas durch das Ziehen natürlich nicht ändert. winfo_width() bezieht sich immer auf das Toplevel-Window. Ich würde deshalb auch eher fenster.winfo_width() schreiben. Man muss also noch die Größe des Canvas mit z.B.

Code: Alles auswählen

leinwand['width'] = fenster.winfo_width() - 4 
anpassen.
MfG
HWK

Edit:
1. winfo_width() gibt es doch für alle Widgets.
2. Durch fill='both' ändern sich zwar ['width'] und ['height'] nicht, aber winfo_width() und winfo_height(), und man kann sogar außerhalb von leinwand.winfo_width() und leinwand.winfo_height() zeichnen. Die gezeichneten Elemente werden dann beim Vergrößern des Fensters sichtbar.
3. Meine Variante liefert also wohl dasselbe Ergebnis wie pütones, aber umständlicher.
Zuletzt geändert von HWK am Dienstag 13. Mai 2008, 12:24, insgesamt 2-mal geändert.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Dienstag 13. Mai 2008, 12:07

HWK hat geschrieben:@pütone: Wenn man fill='both' weglässt und den Canvas-Background auf weiß setzt, sieht man, dass sich die Größe des Canvas durch das Ziehen natürlich nicht ändert. winfo_width() bezieht sich immer auf das Toplevel-Window. Ich würde deshalb auch eher fenster.winfo_width() schreiben.
Da im Code von addili das "fill='both'" gesetzt war, war mir das nicht so wichtig; ebenso die Tatsache, dass dieser Wert nicht aufs Pixel genau stimmt. Ich wollte überhaupt nur den Weg zeigen, wie es umsetzbar ist.

Du hast aber natürlich Recht, es wäre besser gewesen, die winfo-Methoden gleich an das Fenster zu binden, denn da gehören sie hin.

@addili:
Du fragst, wie du das in dein Programm einbauen sollst. Z.B. so:

1. Hinweis von BlackJack berücksichtigen und die Berechnung der einzelnen Positionen der Planeten von der Darstellung der Planeten trennen.

2. Funktion bzw. Methode an das "<Configure>"-Ereignis binden, die zunächst die aktuellen Canvas-Maße ermittelt und davon abhängig die Bildschirmkoordinaten der Planeten ermittelt und dann neu zeichnet bzw. die einzelnen Items verschiebt.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Dienstag 13. Mai 2008, 12:23

@pütone: Ich habe noch etwas 'rumprobiert. Siehe dazu mein Edit.
MfG
HWK
addili
User
Beiträge: 7
Registriert: Samstag 10. Mai 2008, 09:43

Dienstag 13. Mai 2008, 13:03

also ehrlich gesagt blicke ich so garnicht mehr durch aber egal...
who the fuck is GUI???
naja ist auch nicht so wichtig
ich versuch mal mit euren Hinweisen etwas anzufangen...
Für mich ist das mainloop einfach etwas was mein Programm zum laufen bringt...
Also das sich das Fenster öffnet und offen bleibt
Wenn mir dazu sonst nichts erklärt wird außer, dass ich das da hinschreiben muss.
Ich finde es halt prakrischer die Unterprogramme alle groß zu schreiben udhn ich finde dies ist auch kein Grund kritisiert zu werden genauso wenig wie der Name meines Canvases.
So schlimm wenn ich anstatt true 1==1 schreibe?
Habs so beigebracht bekommen
Was hat das denn noch mit meiner Frage zu tun?
Naja ist auch egal
Ich versteh das ganze mit dem GUI etc so wie so nch...
Wusste nich das man so eine einfache frage nach einem befehl so kompliziert ausschlachen kann...
ich gebs dann einafch mal auf

trotzdem danke
BlackJack

Dienstag 13. Mai 2008, 13:21

GUI = Graphical User Interface. Ist schon irgendwie wichtig.

Namensgebung und Konventionen sind wichtig, weil sie das lesen und verstehen von Quelltext vereinfachen. Das gilt auch für das vereinfachen von Ausdrücken. Wer für Endlosschleifen ``(1==1)`` statt einem einfachen ``True`` als "Abbruchbedingung" lehrt, sollte IMHO niemanden unterrichten dürfen.

Du denkst Du hast eine einfache Frage nach einem Befehl gestellt, aber so einfach ist das leider nicht. Deine Probleme mit dem Programm lassen sich nicht mit dem nennen einfacher Funktionen lösen, weil es grundlegende Verständnisprobleme bei der Funktionsweise von ereignisbasierter Programmierung sind. Und so funktionieren GUIs nun mal.
Antworten