Seite 1 von 1

muss mainloop() für geändertes Canvas immer neu aufrufen

Verfasst: Dienstag 4. März 2008, 15:01
von Barabbas
Hallo zusammen,

ich habe folgendes Problem: Ich möchte innerhalb meines Tk- Fensters ein Canvas- Image einbinden. Durch Benutzerinteraktion wird immer wieder ein anderes Bild geladen.

Nun wird aber, wenn ich ein Canvas- Image lade immer nur der gelbe Hintergrund angezeigt. Das eigentliche Bild wird nur angezeigt, wenn ich mainloop() neu aufrufe (Zeile 32). Dies führt dazu, dass ich dann mehrere Mainloops laufen habe. Wenn man z.B. 10 mal die Fkt. Change() aufruft, muss man danach auch 10 mal auf "Beenden" klicken, bis das Fenster schließt.
Um das zu umgehen rufe ich nach jedem Aufruf von mainloop() auch quit() auf, so dass der vorherige mainloop() beendet wird (Zeile 33).

Ich kann mir wirklich nicht vorstellen, dass das eine akzeptable und performante Lösung ist.

Hier mal der Code:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
sys.path.append("..")

from Tkinter import *


class tkApp:


    
    def __init__(self):
        self.mainWindow=Tk()
        self.mainWindow.protocol("WM_DELETE_WINDOW", self.quit)
        self.make_ui()
                      
    def run( self ):
        #ereignisverarbeitung
        self.mainWindow.mainloop()

    def quit( self ):
        #beenden
        self.mainWindow.destroy()
        self.mainWindow.quit()

    def change(self):
        img = PhotoImage(file='bilder/4D Stunts.gif')        
        self.can.itemconfig(self.bild, image=img, anchor=NW)
        self.run()
        self.quit()

    def make_ui(self):
        self.can = Canvas(self.mainWindow, bg="yellow")
        img = PhotoImage(file='bilder/4D Stunts.gif')        
        self.can.config(width=img.width(), height=img.height())
        self.bild = self.can.create_image(0, 0, image=img, anchor=NW)
        self.can.grid(row=1, column=0)     #(expand=YES, fill=BOTH)        
            
        self.button = Button(self.mainWindow, text = "Beenden", command=self.mainWindow.quit)
        self.button.grid(row=0, column=0, sticky=E)
        
        self.button2 = Button(self.mainWindow, text = "Change", command=self.change)
        self.button2.grid(row=0, column=0, sticky=W)        
        
        self.run()
        
if __name__ == "__main__":
    applikation = tkApp()


Ich gehe davon aus, dass der Fehler irgendwo bei mir liegt, habe aber gerade keine Idee und wäre für jeden Hinweis dankbar. Selbst wenn ich allen Objekten ein "mainWindow" voranstelle, bleibt das Problem bestehen (es ist also egal, ob da nun steht self.can = XXX oder self.mainWindow.can = XXX)

vielen Dank schonmal,

Barabbas

Verfasst: Dienstag 4. März 2008, 15:30
von numerix
Ersetze doch mal Zeile 35/36 durch ein

Code: Alles auswählen

self.can.update()
(Da ich das Modul clGames nicht installiert habe, konnte ich es nicht ausprobieren.)

Verfasst: Dienstag 4. März 2008, 15:37
von Barabbas
hi pütone,

danke für den Hinweis, mit update läuft es aber leider auch nicht (wieder wird nur der Hintergrund des Canvas angezeigt, nicht aber das Bild). Ich habe das Beispiel mal so geändert, dass clGames nicht benötigt wird, letztendlich geht es nur darum, dass irgendein Bild reingeladen wird.

Verfasst: Dienstag 4. März 2008, 15:49
von BlackJack
@Barabbas: Du musst eine Referenz auf das Bild-Objekt behalten. Sobald Du keine mehr hast, wird das Objekt nämlich freigegeben. Das das Bild von Tk noch zur Anzeige benötigt wird, bekommt man auf der Python-Seite nämlich nicht mit.

Verfasst: Dienstag 4. März 2008, 15:51
von numerix
Habe es jetzt ausprobiert. Es muss heißen:

self.update()

statt

self.can.update()

dann funktioniert es (jedenfalls bei mir).

Verfasst: Dienstag 4. März 2008, 16:03
von Barabbas
Ha, genial, es funktioniert!

Seltsamerweise meldet mir die Konsole jetzt immer: "AttributeError: tkApp instance has no attribute 'update'"

Probeweise habe ich einfach mal die Zeile self.dhajosdhba() reingesetzt: Damit funktioniert es auch, obwohl die Funktion gar nicht vorhanden ist und der Python- Interpreter ordentlich rumschimpft.

Kann es sein, dass ich so eine art "doevents" brauche, also irgendwas, das die Ereignisverarbeitung anstößt? mainWindow(also Tk) hat zwar eine Methode update, wenn ich die aufrufe, habe ich aber wieder das alte Problem, dass das Bild nicht angezeigt wird.

Naja, wie auch immer, so läuft es ersteinmal, ohne dass ich andauernd quit() aufrufen muss, vielen Dank auf alle Fälle!

Verfasst: Dienstag 4. März 2008, 19:34
von numerix
BlackJack hat geschrieben:@Barabbas: Du musst eine Referenz auf das Bild-Objekt behalten. Sobald Du keine mehr hast, wird das Objekt nämlich freigegeben. Das das Bild von Tk noch zur Anzeige benötigt wird, bekommt man auf der Python-Seite nämlich nicht mit.
Ja, so sollte man es machen.
Ersetze die Variable img z.B. durchgängig durch self.img, dann bleibt eine Referenz erhalten und alles funktioniert so, wie du es gerne hättest.
(Ein update() braucht es dann nicht mehr - war auch ohnehin nicht korrekt, wie die Fehlermeldung ja gezeigt hat.)

Verfasst: Dienstag 4. März 2008, 23:13
von Barabbas
Ah, danke, habe den Beitrag von BlackJack überlesen.
Ärgerlicher Fehler, wenn man alle Objekte in die Klasse aufnimmt und dann beim Bild schlampt.

Vielen Dank für eure Hilfe und dass ihr euch die Mühe gemacht habt, einen Blick auf meinen Code zu werfen. Versuche mich gerade in Python einzufuchsen und ihr habt mir wahrscheinlich ein paar Tage Frust erspart...

lG

brb