Tkinter App, Turtle ein JPG Skin zuweisen

Fragen zu Tkinter.
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Code: Alles auswählen

APP_TITLE = "JPEG-Hintergrund"

app_win = tk.Tk()
app_win.title(APP_TITLE)

# Erzeugt das Hintegrund PIL-Bildobjekt 
pil_background_image = Image.open("Labyrinth.jpg")
# Konvertiert das Hintegrund PIL-Bildobjekt zum Tk-Bildobjekt
app_win.tk_background_image = ImageTk.PhotoImage(pil_background_image)

# Erzeugt das Turtle PIL-Bildobjekt
pil_turtle_image = Image.open("Turtle.jpg")
# Konvertiert das Turtle PIL-Bildobjekt zum Tk-Bildobjekt
app_win.tk_turtle_image = ImageTk.PhotoImage(pil_turtle_image)

# Abmessungen des Hintergrundbildes
width = app_win.tk_background_image.width()
height = app_win.tk_background_image.height()

# Erzeuge Bildfläche für das ablegen des Hintergrundbildes
canvas = tk.Canvas(app_win, width=width, height=height, highlightthickness=0)
canvas.pack()

# Legt das Hintegrundbild auf die Bildfläche
canvas.create_image(0, 0, image=app_win.tk_background_image, anchor='nw',
    tag="Hintergrund")
    
# Lege die Turle auf das Hintergrundbild
canvas.create_image(10, 10, image=app_win.tk_turtle_image, anchor='nw',
    tag="Hintergrund")

app_win.mainloop()
Hier habe ich probiert ein JPG Bild als Hintergrund zu verwenden. Doch ich weiß nicht wie ich in dieser app meine Turtle verwenden kann.
Ich hoffe mir kann jmd weiterhelfen.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Was ist denn das konkrete Problem? Gibt es eine Fehlermeldung? Falls ja welche? Wird etwas nicht angezeigt von dem Du erwartet hättest, das es angezeigt wird?

Dem Schildkrötenbild würde man wohl eher ein anderes `tag` als 'Hintergrund' zuweisen wollen.

Und wenn Du etwas mit dem Schildkrötenbild machen möchtest, zum Beispiel seine Position verändern, dann solltest Du Dir dafür die ID merken die `create_image()` liefert. Oder eben einen eindeutigen `tag`-Wert verwenden.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Nun ja, also ich kenne mich nicht aus mit tkinter, tags und so weiter. Den tag muss ich wohl irgendwie verändert haben, der heisst natürlich anders also "Turtle". Ich habe leider wenig ahnung was du mit id meinst. Also was ich machen wollte ist das ich die Turtle mit dem turtle modul steuern kann. Kann ich das auch im Tkinter modul?
Ich brauche das TKinter modul, da ich da einen jpg hintergrund einfügen kann und von dem mit PIL den Pixelwert auslesen kann um ein nicht betretbares raster zu erstelle.
Ich hoffe das du mein Anliegen halbwegs verstanden hast. Icst vllt ein wenig unverständlich formuliert, Sorry.
LG Fredy
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wenn Du das `turtle`-Modul verwenden willst, dann brauchst Du das `create_image()` für die Schildkröte nicht, denn um die Schildkröten kümmert sich ja das `turtle`-Modul. Eventuell könnte man auch ganz auf das Tkinter-Modul verzichten wenn man das Hintergrundbild auch als Schildkröte umsetzt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Ok also benutze ich jetzt den Tag den ich für die Turtle verwende. Also ungefähr so oder (Tag = "Turtle"): Turtle = Turtle() Turtle.fd(10) ...
Aber wo schreibe ich jetzt weiter? Schreibe ich einfach in der TKinter app weiter oder erst später? Dann setze ich alles in die mainloop().
Und wie meinst du das, dass ich auf TKinter verzichten kann? Ich kann eine Gif benutzen aber wie ich bei einer gif die Pixelfarbe eindeutig auslesen kann ich mir schleierhaft, dazu wüsste ich nicht wie ich die gif im hintergrund arritieren kann. Vllt meinst du ja auch das ich ein Labyrinth mit den canvas zeichnen könnte, aber da weiß ich nicht wie ich z.B. die Farbe der canvas auslesen kann oder, ohne alle koordinaten anzugeben, den bereich begrenzen kann.
LG Freddy
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mit auf Tkinter verzichten meinte ich das Du das `turtle`-Modul verwenden solltest. Beziehungsweise willst Du das ja anscheinend sowieso. Dann ist aber das `turtle`-Modul eigentlich für das Hauptfenster zuständig, was Du aber selbst erstellst. Und auf jeden Fall wäre das `turtle`-Modul dann für die Schildkröten zuständig. Da musst Du dann schon die entsprechenden Klassen aus dem `turtle`-Modul für verwenden und nicht selbst auf einem `tkinter.Canvas` ein Bild mit `crate_image()` für die Schildkröte erstellen. Die kannst Du dann ja nicht mit den Methoden aus dem `turtle`-Modul steuern. Oder Du verzichtest auf das `turtle`-Modul und nimmst nur `tkinter`. Das kommt so ein bisschen darauf an was Du eigentlich letztendlich machen willst und ob Dir das `turtle`-Modul die Arbeit erleichtert oder ob Du eher gegen oder um dieses Modul herum programmieren musst.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Nun ja ich möchte eigentlich das Bild durch das Labyrinth steuern und zwar mit dem turtle modul. Wie ich die Turtle mit Tkinter steuern kann das wieß ich nicht. Aber wie kann ich jetzt meiner JPG Datei die ich per Tkinter auf den Bildschirm gelegt habe eine Turtle zuweisen bzw. mit Tkinter steuern. Das ist mir schleierhaft.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Freddyyy: Wenn Du das `turtle`-Modul verwenden willst, dann verwende das auch. Einer Schildkröte kann man mit `register_shape()` und dann dem Namen den man dort vergeben hat ein GIF zuweisen. JPG scheint nicht zu gehen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Das heisst ich soll den code weg lassen. Gut. Wie soll ich dann aber den Hintergrund hinbekommen? Ich möchte von verschiedenen Koordinaten des Bildes mit getpixel() den Farbcode auslesen.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wie gesagt könnte man den Hintergrund als Schildkröte machen. Ich sehe gerade das man über `Shape` anscheinend doch beliebige `PhotoImage`\s erstellen und dann mit `register_shape()` registrieren kann. Dann kannst Du also auch JPG verwenden und dir auch mit deren `get()`-Methode die RGB-Werte eines Pixels geben lassen, oder das `PIL.Image` aufheben und dort die Werte abfragen. Wobei man bei JPG berücksichtigen muss, das dieses Format verlustbehaftet komprimiert und daher die Farben von vor dem Speichern nach dem wieder einlesen leicht abweichen können.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Das man auch jpegs verwenden kann habe ich auch auf Trinket.io gelesen. Doch unter python 3.6.5 ist dies nicht möglich (zum. ists als Arugumen "name is the name of a gif-file and shape is None.") . Vllt in einer anderen Version? 2.7.X? Naja ansonsten muss ich wohl das Turtle-Modul umschreiben. Aber da muss ich ehrlich sagen habe ich so gar keine ahnung. Was ich machen will ist mehrere Definitionen schreiben und damit die Tastaen WASD belegen. Das in der while schleife in der die Turtle sich permanent nach dem wert X bewegt und in der die abfrage läuft ob sich die Turtle auf einem Schwarzen- oder Weißenfeld befindet. Um ehrlich zu sein währe ich überascht wenn das klappt bzw. habe ich das nirgendswo gefunden. Hier mal ein Code beispiel:

Code: Alles auswählen

end = False
while not end:
   
    speed(0)
    Turtle.fd(3)
    
    def obenW():
        Turtle.setheading(90)
    def rechtsD():
        Turtle.setheading(0)
    def untenS():
        Turtle.setheading(270)
    def linksA():
        Turtle.setheading(180)
    

    bs = Screen()
    bs.listen()
    
    bs.onkeypress(forward, "f")
    bs.onkeypress(obenW, "w")
    bs.onkeypress(rechtsD, "d")
    bs.onkeypress(untenS, "s")
    bs.onkeypress(linksA, "a")
    x = Turtle.xcor
    
    y = Turtle.ycor
    
    img = Image.open("07_Labyrinth.jpg")
    a = img.getpixel((x,y))
    print(a)
    if a == "(255, 255, 255)":
        ende = False
    elif a == "(0, 0, 0)":
        ende = True
Also das ende habe ich natürlich noch nicht fertig und konnte es also dementsprechend nicht testen.
LG Frddy
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das was man mit ``def`` schreibt sind *Funktionen* (ausserhalb von Klassen) oder *Methoden* (innerhalb von Klassen). Die werden nicht allgemein *Definitionen* genannt, denn das wäre deutlich mehr.

Mit `PIL.ImageTk.PhotoImage` sollten auch JPGs in Python 3.6.5 mit `turtle` möglich sein. Man muss ein `Shape`-Objekt damit erstellen und das mit `register_shape()` registrieren um es für eine Schildkröte auswählen zu können.

`def` ist eine ausführbare Anweisung. Es macht hier keinen Sinn die gleichen Funktionen in jedem Schleifendurchlauf immer wieder neu zu definieren und die Tastendrücke immer wieder erneut an diese immer neuen Funktionen zu binden.

Die namen der Funktionen sind komisch. Die sollten nicht die Tastennamen beinhalten, und wenn dann auch nicht als Grossbuchstaben.

`bs` ist kein guter Name. `screen` wäre hier naheliegend.

`Turtle` ist entweder falsch geschrieben, denn alles ausser Klassen und Konstanten sollte komplett_in_kleinbuchstaben geschrieben werden, oder Du versuchst das Methoden auf der `Turtle`-Klasse aufzurufen, statt auf einem Exemplar davon.

`Image.getpixel()` gibt Tupel zurück, die kann man nicht sinnvoll mit Zeichenketten einer Tupeldarstellung vergleichen — das ist *immer* `False`.

Zudem hatte ich ja schon geschrieben das JPGs verlustbehaftet komprimieren. Also auch wenn man ein Bild speichert das nur aus komplett schwarzen und komplett weissen Pixeln besteht, wird es ziemlich sicher Pixel mit leicht anderen Farben geben.

Die Schleifenvariable heisst `end` aber in der Schleife wird einer Variablen `ende` etwas zugewiesen‽

Ich würde mir das ganz sparen und einfach ``while True:`` schreiben und diese Schleife dann gegebenfalls mit ``break`` verlassen.

Letztlich ist das so nicht lauffähig. Da fehlen mindestens mal Importe.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich habe gerade mal die Dokumention des `turtle`-Moduls überflogen: Es gibt eine Funktion/Methode um sich den verwendeten Canvas geben zu lassen. Da lässt sich ein Hintergrundbild also auch direkt drauf erzeugen, ohne den Umweg über eine `Turtle`.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

PIL.ImageTK.PhotoImage würde ich dann wie folgt verstehen:

Code: Alles auswählen

from PIL import Image, ImageTK
from turtle import *
t = Turtle()
img = ImageTK.PhotoImage(image.open("Example.png"), X) #X hier als platzhalter
register_shape(img)
t.shape(img)
Ich denke mal das man anstelle von X die höhe und breite definieren soll aber wie habe ich noch nicht vertanden.
Dazu habe ich die Fehlermeldung das ImageTK nicht in PIL definiert sei.
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Und würdest du anstatt von JPG PNG oder was anderes benutzen? Bitmap oder sowas..
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`ImageTK` ist ja auch nicht in PIL defininiert. Aber `ImageTk` ist es. Python ist eine Programmiersprache bei der Gross- und Kleinbuchstaben unterschieden werden.

Wie kommst Du auf die Idee da für X etwas angeben zu müssen? Und warum die Höhe und Breite? Das Bild hat doch eine Höhe und Breite in Pixeln, was willst Du denn da noch zusätzlich angeben?

Ich würde PNG benutzen wenn exakte Farbwerte und/oder Transparenz gefordert sind. JPG für Bilder wo die exakten Farbwerte nicht wichtig sind, keine Transparenz benötigt wird, und die Bilddatei als PNG nicht kleiner ist. JPG auf keinen Fall für Bilder die noch bearbeitet werden sollen, denn bei jedem Speichern kann da wieder ein bisschen Information verloren gehen. Als Ausgangsmaterial ok, aber zwischenspeichern auf jeden Fall in einem verlustlosen Format.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das ganze mal in Hy, einem in Python implementierten Lisp-Dialekt. Die beiden Bilder die gebraucht werden sind 'test.png' was ein "Labyrinth" sein muss, wo Mauern weiss gemalt sind. Um das Bild muss keine Mauer sein, das Programm geht implizit von einer Mauer aus wenn man versucht das Bild zu verlassen. Und 'test2.png' was den Spieler darstellt. Sollte nicht zu gross sein, und kann Transparenz enthalten.

Code: Alles auswählen

#!/usr/bin/env hy
(import
  [functools [partial]]
  [turtle [*]]
  [PIL [Image ImageTk]])

(def *white* (, 255 255 255)
     *wall-color* *white*
     *move-distance* 3
     *fast-distance* 10
     *fast-key* "f"
     *move-delay* 100  ; In milliseconds.
     *background-image* (-> (Image.open "test.png") (.convert "RGB")))

(defn div2 [x]
  (/ x 2))

(defn get-image-position [image x y]
  (setv [half-width half-height] (map div2 (. image size)))
  (, (+ x half-width) (+ (- y) half-height)))

(defn is-wall? []
  (setv image-position (get-image-position *background-image* (xcor) (ycor)))
  (try
    (setv pixel (.getpixel *background-image* image-position))
    (except [IndexError]
      ; Implicit wall outside the image.
      True)
    (else
      (= pixel *wall-color*))))

(defn move-turtle []
  (forward *move-distance*)
  (if (is-wall?)
    (onkeypress None *fast-key*)
    (ontimer move-turtle *move-delay*)))

(defmain [&rest args]
  (setv [width height] (. *background-image* size))
  (setup width height)
  ; Keep reference to `PhotoImage` instance!
  (setv background-photo-image (ImageTk.PhotoImage *background-image*))
  (.create-image (getcanvas) 0 0 :image background-photo-image)

  (register-shape "player" (Shape "image" (-> (Image.open "test2.png")
                                              (ImageTk.PhotoImage))))
  (shape "player")
  
  (onkeypress bye "q")
  (onkeypress (partial forward *fast-distance*) *fast-key*)
  (for [[key angle] [["w" 90] ["a" 180] ["s" 270] ["d" 0]]]
    (onkeypress (partial setheading angle) key))
  (listen)
  
  (speed 0)
  (showturtle)
  (move-turtle)
  (exitonclick))
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Also bei dem Code kommt fdast überall Syntax error. Muss beim Kopieren vllt irgendwas beachten?
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Du musst vor allem beachten, dass das kein Python ist und sich damit auch nicht mit Python ausführen lässt. :-)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Freddyyy
User
Beiträge: 69
Registriert: Donnerstag 26. April 2018, 17:50

Naja ich brauche das aber für Python
Antworten