PIL+Canvas: Anfägerproblem

Fragen zu Tkinter.
Antworten
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

Hallo!

Da mein Orbit Fraktal Painter recht langsam war und immer langsamer wurde. (tk.Canvas is halt recht ungeeignet um >10.000 Punkte einzeln zu zeichnen...)
Deswegen wollt ich das jezt mal mit der PIL probieren, aber PIL ist ja recht mächtig und da ich bis jetzt noch nix damit gemacht hab, wollt ich erst mal langsam anfangen, da ich erstmal nur zeichnen will.

Meine Hilfsklasse zum einfachen zeichen mit PIL:

Code: Alles auswählen

import Image, ImageDraw, ImageTk

# Klasse, um einfach mit pil auf ein tk.Canvas zu zeichnen
class PILCanvas(tk.Canvas): 
    def __init__(self,master,pilx,pily, width, height,pilw, pilh,  bg):
        self.pilx, self.pily = pilx, pily
        tk.Canvas.__init__(self,master, width = width, height = height, bg = bg)
        self.im =  Image.new("1", size = (pilw,pilh), color = bg)
        self.draw = ImageDraw.Draw(self.im)
        image = ImageTk.PhotoImage(self.im) 
        self.create_image(pilx,pily,image=image,tags="image1", anchor = "nw") 
    def pilpoint(self, pos, fill):
        self.draw.point(pos, fill = fill)

    def _update(self):
        print "update"
        self.delete("image1")
        image = ImageTk.PhotoImage(self.im)
        self.create_image(self.pilx, self.pily,image=image,tags="image1", anchor = "nw")
        self.update()
#        self.im.show()
der Abschnitt des Hauptprogramms:

Code: Alles auswählen

# in der __init__:
self.can=PILCanvas(self.mf,height=300,width=300,bg="black", pilx = 0, pily = 0, pilw = 300, pilh = 300)
        self.can.grid(row=1,column=1,rowspan=3)

#später:

def calculate(self):   
        a,b,c = float(self.entrys["a"].get()), float(self.entrys["b"].get()), float(self.entrys["c"].get())
        n=int( self.entrys["num"].get())
        if self.x  and self.y:
            x,y=self.x,self.y
        else:
            x,y=0,0
        self.color="red"
        ci=2500
        for i in range(n):
            if not (i%10):
                self.nvar.set(("%i"% (int(self.nvar.get())+10)).rjust(5))
                if 2*ci > i >= 1*ci:
                    self.color='#ff4242'
                elif 3*ci > i >= 2*ci:
                    self.color='#f5ff42'
                elif 4*ci > i >= 3*ci:
                    self.color='#4bff42'
                elif 5*ci > i >= 4*ci:
                    self.color='#42f5ff'
                elif 6*ci > i >= 5*ci:
                    self.color='#4448fd'
                elif 8*ci > i >= 6*ci:
                    self.color='#d943fe'
                elif 9*ci > i >= 7*ci:
                    self.color='#fe4356'                  
            self.can.pilpoint((self.f(x),self.f(y)), fill=self.color)
#            self.can.update()
            if self.algoname.get() == "1. Hopalong":
                xx=y-sign(x)*(abs(b*x-c))**0.5
                yy=a-x
            elif self.algoname.get()== "2. Gingerbreadman":
                xx=1-y+abs(x)
                yy=x
            elif self.algoname.get() == "3. Kamtor3D":
                xx=x*cos(a)+(x*x-y)*sin(a)
                yy=x*sin(a)-(x*x-y)*cos(a)
            else:
                xx=eval(self.algox)
                yy=eval(self.algoy)
            x,y=xx,yy
        self.x,self.y=x,y
        self.can._update()

    def f(self,x):
        return ((x*10)+150)
Am restlichen Code hab ich nix gemacht (is also getestet).

So, nun meine Probleme:
  • Punkte sind nicht farbig
  • Darstellen auf Canvas funzt nicht
1. Versteh ich gar nicht, da ich daran eigentlich nix gemacht hab, außer die Farben in "#rrggbb" zu "übersetzen".

2. Find ich ganz komisch, denn wenn ich in der _update-Methode das self.im.show() auskommentiere, erscheint kurz vor dem von ´´show()´´ erzeugten Bild, eins im Canvas, was jedoch nachher wieder weg ist. Ebenso, wenn self.im.show() auskommentiert ist...

Ich hoffe, ihr könnt mir helfen.
LG, jj
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

Kann mir denn keiner helfen? :cry:
Oder ist das nur das falsche Forum, und die ganzen PIL-Experten gucken nicht ins Tkinterforum? Wenn ja, bitte verschieben.
LG, jj
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi LG,

ja, alles spricht dafür, dass es das älteste Anfängerproblem ist, das ich kenne. ;-)

Code: Alles auswählen

image = ImageTk.PhotoImage(self.im)
Wenn Du dieses PhotoImage der Zeile 11 nicht irgendwo extra referenzierst, verschwindet es mit dem Ende der Methode im Nirvana. Dass es während der Update-Methode kurz aufblitzt ist ein sehr eindeutiges Indiz für diese Ursache.

2. Sieh Dir doch mal die Abkürzungen für die Farbtiefen der PIL-Images an, siehe Zeile 9 in Deinem Code:

Code: Alles auswählen

        self.im =  Image.new("1", size = (pilw,pilh), color = bg)

Sobald ich mich recht erinnere (ist schon 2 Jahre her, dass ich mich damit beschäftigte) steht
"1" für schwarz/weiß Images
"L" für Graustufen
"I" für indizierte 8-Bit Farben
"RGB" für 24-Bit rgb Farben
"RGBA" für 32-Bit rgb Farben + Alpha

Also versuch es doch mal mit "RGB", aber ungetestet und keine Garantie für nix. ;-)

Grüße,
Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

Hi Michel,
also mit den Farben klappts jetzt...hätt vlt. mal etwas gründlicher lesen sollen :lol:
Michael Schneider hat geschrieben: ja, alles spricht dafür, dass es das älteste Anfängerproblem ist, das ich kenne. ;-)

Code: Alles auswählen

image = ImageTk.PhotoImage(self.im)
Wenn Du dieses PhotoImage der Zeile 11 nicht irgendwo extra referenzierst, verschwindet es mit dem Ende der Methode im Nirvana. Dass es während der Update-Methode kurz aufblitzt ist ein sehr eindeutiges Indiz für diese Ursache.
Das versteh ich nicht. ´´image´´ wird doch mit create_image gezeichet und dann wieder über das Canvas (also self) wider gelöscht und erneuert.

Danke schon mal für 1, jetzt hoff ich noch auf 2. (oder andersrum?)
Gruß, jj
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

schlangenbeschwörer hat geschrieben:
Michael Schneider hat geschrieben: ja, alles spricht dafür, dass es das älteste Anfängerproblem ist, das ich kenne. ;-)

Code: Alles auswählen

image = ImageTk.PhotoImage(self.im)
Wenn Du dieses PhotoImage der Zeile 11 nicht irgendwo extra referenzierst, verschwindet es mit dem Ende der Methode im Nirvana. Dass es während der Update-Methode kurz aufblitzt ist ein sehr eindeutiges Indiz für diese Ursache.
Das versteh ich nicht. ´´image´´ wird doch mit create_image gezeichet und dann wieder über das Canvas (also self) wider gelöscht und erneuert.
Hi JJ,

das ist ja gerade der fiese Trick, den man hier und da nur im Kleingedruckten findet: der Canvas speichert eben KEINE Referenz auf das PhotoImage!! Wenn man das nicht beachtet, verschwindet es mit dem einen und einzigen Namen am Ende des Namensbereichs. Mach daraus einfach mal ein self.image und es sollte funzen (im Konstruktor und in der _update-Methode). :-)

Edit: Nachtrag
Zur Info: der Canvas ist keine Rastergrafik ansich sondern eher eine Sammlung von Vektor- und Rastergrafiken gepaart mit Methoden, die diese Objekte anordnen und darstellen. Die Rastergrafiken werden hier nur indiziert, aber nicht als Objekte referenziert.

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Antworten