Move verschiebt Objekt, zeichnet es aber nicht

Fragen zu Tkinter.
Antworten
LT67
User
Beiträge: 6
Registriert: Sonntag 4. Oktober 2015, 10:19

Hallo,
ich habe folgendes Problem. Mein Programm soll nach dem Drücken der linken Maustaste einen Ball zeichnen und ihn danach über den Canvas wandern lassen. Leider zeichnet er mir nur den "letzten" Ball. Weder wird der erste Ball gezeichnet, noch kann man die Wanderung über den Canvas sehen. Was mache ich falsch? Für einen Hinweis wäre ich dankbar.

Henning

Code: Alles auswählen

import tkinter
import time


class MyGame(tkinter.Frame):
    cFrameWidth = 400
    cFrameHeight = 400
        

    def __init__(self, root:tkinter.Tk):
       
        super().__init__(root)
        self.pack()
        self.cv = tkinter.Canvas(self, width = self.cFrameWidth, \
                         height = self.cFrameHeight, \
                         background = "white")
        self.cv.bind("<Button 1>", self.pressLeftButton)
        self.cv.pack()


        # object Number on Canvas
        self.myObjectOnCv = None

    def start(self):
        self.drawMyObjectOnCv()
        time.sleep(3)
        self.moveMyObjectOnCv()


    def drawMyObjectOnCv(self):
        self.myObjectOnCv = self.cv.create_oval( \
            50, \
            25, \
            50 + 20, \
            25 + 20, \
            fill="blue", width = 0)

    def moveMyObjectOnCv(self):
        for x in range(1,25):
            self.cv.move(self.myObjectOnCv, 10, 10)
            time.sleep(0.25)

    def pressLeftButton(self, event):
        self.cv.unbind("<Button 1>")
        self.start()
        


root = tkinter.Tk()
mg = MyGame(root)
root.lift()
root.attributes('-topmost', True)
root.attributes('-topmost', False)
root.mainloop()
BlackJack

@LT67: Die GUI wird erst wieder aktualisiert wenn Deine Methode die Kontrolle an die GUI-Hauptschleife wieder zurückgibt. Du darfst das da also nicht alles in einer Schleife und `sleep()` machen sondern mit der `after()`-Methode auf Widget-Objekten und einer Funktion die genau einen Schleifenschritt macht und sich dann wieder per `after()` registriert.

Das mit den Typannotationen solltest Du sein lassen. Mal davon abgesehen das es ja eh keine Auswirkung hat, schränkst Du das `root`-Argument von `MyGame.__init__()` völlig unnötig auf ein Hauptfenster ein wo ein Frame eigentlich auch in jedes andere Containerwidget eingefügt werden kann.

Die Namensschreibweisen halten sich nicht an den Style Guide for Python Code und einiges sind echt übliche Abkürzungen. Man sollte bei Namen nicht erst raten müssen was die wohl bedeuten mögen. Falls das 'c' bei den Klassenattributen für „constant“ stehen sollte: Konstanten werden einfach komplett gross geschrieben.

Widgets layouten sich nicht selbst. Das `self.pack()` in der `__init__()` gehört dort nicht hin. Damit schränkt man noch weiter unnötig ein wie der Frame verwendet werden kann.

Die Backslashes an den Zeilenenden sind überflüssig solange noch nicht alle Klammern die geöffnet wurden auch wieder geschlossen wurden. Dann erkennt der Compiler auch so dass das noch nicht das Ende der Anweisung sein kann.
LT67
User
Beiträge: 6
Registriert: Sonntag 4. Oktober 2015, 10:19

Hallo BlackJack,
vielen Dank für die Hinweise. Das Programm funktioniert. Den Style Guide for Python Code werde ich lesen und umsetzen und auf Typannotationen verzichten. Du hattest empfohlen self.pack() nicht in die __init__() mit aufzunehmen. Wo würdest Du das hinpacken?
Würdest Du eine eigene Funktion zum Aufbau des Fensters schreiben, die aus __init__() heraus aufgerufen wird?

Vielen Dank für Antwort.

Henning
BlackJack

@LT67: Falls sich die letzte Frage auf die Vorletzte bezieht: Das wäre vom Prinzip dann ja immer noch so das sich das Objekt beim erstellen selbst layoutet. Das sollte man dem Ersteller überlassen, wie das alle bereits vorhandenen Widgets ja auch tun.
LT67
User
Beiträge: 6
Registriert: Sonntag 4. Oktober 2015, 10:19

Hallo BlackJack,

vielen Dank für die Antwort.
Henning
Antworten