Anzeige von 12 Bildern zyklisch erfolgen lassen

Fragen zu Tkinter.
wilhelmO
User
Beiträge: 34
Registriert: Mittwoch 17. August 2011, 14:40

Hallo Hyperion - Danke für die Beantwortung

Unterschied sehe ich - mit self.after(2000,self.bilder()) rufe ich die methode self.bilder
nochmals ( immer wieder ) auf.

Den Unterschied , den self.bilder verursacht, sehe ich nicht bzw. verstehe ich nicht.
Finde auch in meinen python - büchern so schnell keine Erklärung.
Habe z.B. "Python" von Ernesti und Kaiser. Erster grundlegender Teil hat mir auch beim
Einstieg geholfen, den Rest kann ich als Anfänger aus meiner Sicht "vergessen".

Gibt es überhaupt ein gutes Buch ( Schwerpunkt OOP mit Python ) mit verständlichen
Beispielen. Also ein Buch, daß sich nicht gerade an Informatiker wendet.

Vielen Dank für jede Hilfe !
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

wilhelmO hat geschrieben: Unterschied sehe ich - mit self.after(2000,self.bilder()) rufe ich die methode self.bilder
nochmals ( immer wieder ) auf.
Quasi in der Art.
wilhelmO hat geschrieben: Den Unterschied , den self.bilder verursacht, sehe ich nicht bzw. verstehe ich nicht.
Du übergibst einer Funktion eben eine andere Funktion. In Python ist alles ein Objekt - und Objekte kann ich als Parameter übergeben.

Hier mal ein begrenzt sinnvolles Beispiel:

Code: Alles auswählen

In [32]: def calculate(a, b, func):
   ....:     return func(a, b)
   ....: 

In [33]: def add(a, b):
   ....:     return a + b
   ....: 

In [35]: calculate(1, 4, add)
Out[35]: 5

In [36]: def mul(a, b):
   ....:     return a * b
   ....: 

In [37]: calculate(1, 4, mul)
Out[37]: 4
Meine Funktion `calculate` nimmt neben zwei Datenparametern auch ein Funktionsobjekt entgegen. Dieses wird innerhalb meiner Funktion aufgerufen. Somit kann ich das Verhalten meiner Funktion von außen leicht verändern.

Gute Beispiele für solche Übergaben finden sich auch in den Built-In Funktionen, z.B. `filter` oder `sorted`.
wilhelmO hat geschrieben: Habe z.B. "Python" von Ernesti und Kaiser. Erster grundlegender Teil hat mir auch beim
Einstieg geholfen, den Rest kann ich als Anfänger aus meiner Sicht "vergessen".
Das Ding solltest Du in die Tonne kloppen - diese Autoren haben keine Ahnung von Python. gibt im Forum genügend Warnungen und auch inhaltliche Begründungen dafür. (SuFu)
Es gibt so einige gute Tutorials... musst Du mal hier suchen und antesten. Es gibt hier ja Threads zu hauf bezüglich dieses Themas.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo wilhelmO
wilhelmO hat geschrieben:Das Programm von wuf habe ich ausprobiert. Es zeigt nur einen leeren Frame.
Kannst du einmal einige Bilddateien mit der Endung .gif oder .png, eventuell Icon-Bildchen in diesem Format, in dein Arbeitsverzeichnis dort wo du mein Programmskript abgelegt hast und startest, kopieren. Dann probier es noch einmal aus. Es sollte Bild um Bild mit der Verzögerung DELAY in das Frame kopiert werden.

Edit:
Habe mein Skript nur unter Linux-Kubuntu & Python 2.6 getestet. Du arbeitest unter Windows. Dann kannst du einmal versuchen:

Code: Alles auswählen

self.label.update_idletasks()
durch

Code: Alles auswählen

self.label.update()
zu ersetzen und

Code: Alles auswählen

root.update_idletasks()
weglassen.

Gruß wuf :wink:
Take it easy Mates!
wilhelmO
User
Beiträge: 34
Registriert: Mittwoch 17. August 2011, 14:40

Guten Morgen wuf
Vielen Dank für Deinen Beitrag, habe die vorgeschlagenen Änderungen vorgenommen.
Um zu sehen was geschieht, habe ich zwei print Anweisungen hinzugefügt.
In load_images habe mir den Inhalt von files ( files=os.list.dir(IMAGE_PATH ) ausdrucken lassen.
Ich erhalte : files = ['AVT000001.GIF','AVT000002.GIF',.......,'AVT000042.GIF']
Bis hier scheint alles ok.

Jedoch nach dem sortieren erhalte ich eine leere Liste.
images = sorted(images,reverse=TRUE)
print "images nach sort"

ergibt der Ausdruck : [] eine leere Liste
Ich sehe nicht die Ursache.
wilhelmO
User
Beiträge: 34
Registriert: Mittwoch 17. August 2011, 14:40

Guten Morgen Hyperion
Beispiel meine ich verstanden zu haben. Eine methode names calculate hat als parameter
zwei Werte mit denen es 'rechnen' soll. Wie es damit rechnen soll entscheidet der dritte
Parameter ( wiederum eine komplette methode ) . Es wird somit eine methode als parameter
übergeben. Oder allgemein , wie weiter oben von Hyperion beschrieben , ein Object.
Und da in python wohl alles ( alles ? ) ein object ist , bin ich als gewohnheits - prozedural -
programmier ohne Erfahrung mit Klassen und OOP ziemlich verwirrt. Wird wohl lange dauern
bis dieser Zustand sich bessert.

Programmchen geht inzwischen wie gewünscht. Jedoch habe ich ein Verständnisproblem bei
folgenden zeilen der methode ( function ? ) def bilder(self)

Code: Alles auswählen

for row, image in enumerate(self.images):
                for column, image in enumarate(images):
Warum wird in der zweiten zeile enumarate nicht auf self.images angewendet ?
Da das Programm bei Änderung auf self.images abstürzt ist dies wohl korrekt , aber warum ?
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo wilhelmO

Ich sehe, dass bei deinen Bilddateien die Endung gross geschrieben ist. Also x.gif ist x.GIF. Damit die diese Dateien akzeptiert werden musst du die Konstante 'IMAGE_FORMAT_FILTER' wie folgt erweitern:

Code: Alles auswählen

IMAGE_FORMAT_FILTER = ['.gif', '.png', '.GIF', '.PNG']
Gruß wuf :wink:
Take it easy Mates!
wilhelmO
User
Beiträge: 34
Registriert: Mittwoch 17. August 2011, 14:40

Hallo wuf
Vermutung war korrekt ! Habe filter geändert. Jetzt ist die sortierte liste sorted_images
vollständig und korrekt.

:?: Programm stürzt trotzdem ab mit einer für mich völlig unverständlichen Fehlermeldung :

IOError : [Errno 2] no such file or directory: 'AVT000000001.GIF'

Der Fehler tritt in der folgenden zeile auf :
row_list.append(ImageTk.PhotoImage(Image.open(images.pop()).resize(RESIZE_IMAGE_WIDTH,RESIZE_IMAGE_HEIGHT)))

Das 'Bild' AVT000000001.GIF ist jedoch in der sorted_images vorhanden , was der vorher er-
folgte Kontrollausdruck des Listeninhalts zeigt. Also ist vielleicht die Fehlermeldung falsch/irre-
führend ?
wilhelmO
User
Beiträge: 34
Registriert: Mittwoch 17. August 2011, 14:40

Hallo wuf ERGAENZUNG :
habe zeile sorted_images = list()
auf sorted_images = images
geändert. Daraufhin ist die sorted_images mit den Bildnamen des Verzeichnisses gefüllt. Mit obiger Anweisung bleibt die list leer .
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi wilhelmO

Die Zeile:

Code: Alles auswählen

sorted_images = list()[b]
sollte

Code: Alles auswählen

sorted_images = list()
heissen.
Das '' hatte sich vermutlich bei einer copy and paste Aktion eingeschlichen :)

N.B. Bei mir wird die Datei AVT000000001.GIF ohne Exception zu werfen erkannt.

Gruß wuf :wink:
Take it easy Mates!
BlackJack

@wilhelmO: Alles was an einen Namen gebunden werden kann ist in Python ein Objekt. Man könnte statt „Objekt” auch „Wert” sagen, und dann hat das auch nicht per se etwas mit OOP zu tun, denn man kann auch in prozeduraler Programmierung bei vielen Sprachen Funktionen (beziehungsweise Zeiger darauf) als Argumente übergeben. Bei C und Pascal ist das zum Beispiel möglich. Umgekehrt geht das nicht in jeder Sprache mit OOP-Unterstützung. Bei Java geht es beispielsweise nicht. Dort bastelt man sich in der Regel anonyme innere Klassen mit einer einzigen Methode, um eine „Funktion” übergeben zu können.

Warum sollte sich ``enumerate(images)`` auf `self.images` beziehen? Das wäre sehr magisch und komisch.

Wenn die Datei ``AVT000000001.GIF`` angeblich nicht existiert, dann solltest Du mal über den implizierten Pfad bei diesem Dateinamen nachdenken.
wilhelmO
User
Beiträge: 34
Registriert: Mittwoch 17. August 2011, 14:40

Sorry my fault
sorted_images = images lautet es in im programm. "" habe ich versehentlich von
Hand eingefügt , als mich mit den Formatierungen vertippt hatte.
Da mein Verzeichnis auch keine Umlaute oder Sonderzeichen enthält , kann ich die Fehler-
meldung eben nicht nachvollziehen.

Im Kopf des Programms lasse ich mir zur Kontrolle nochmals den Inhalt von IMAGE_PATH
ausdrucken.
Er lautet dann korrekt : 'fpad = C:/Python26/AVTGIF

:?
BlackJack

@wilhelmO: Die Fehlermeldung enthält keinen Pfad. Das impliziert das Arbeitsverzeichnis des Prozesses und nicht ``C:/Python26/AVTGIF``. Da steht ja nicht das ``C:/Python26/AVTGIF/AVT000000001.GIF`` nicht gefunden werden konnte. So einen Dateinamen versuchst Du auch gar nicht zu öffnen.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi wilhelmO

Hier das überarbeitete Skript:

Code: Alles auswählen

import Tkinter as tk
from PIL import Image, ImageTk
import os

ROWS = 3
COLUMNS = 4
TITLE = "TK 5 FormenScan"
#IMAGE_PATH = os.getcwd() # wuf's Pfad
IMAGE_PATH = "C:/Python26/AVTGIF/" # wilhelmO's Pfad
IMAGE_FORMAT_FILTER = ['.gif', '.png', '.GIF', '.PNG']
RESIZE_IMAGE_WIDTH = 48 #200
RESIZE_IMAGE_HEIGHT = 48 #130
DELAY = 1000


class Image_Viewer(tk.Frame):
    
    def __init__(self, root):
        
        tk.Frame.__init__(self, root)
        self.pack()
          
        self.bilder()
       
    def bilder(self):
            
        self.images = self.load_images()
        
        for row, images in enumerate(self.images):
            for column, image in enumerate(images):
                self.label = tk.Label(self, image=image)
                self.label.grid(row=row, column=column)
                self.label.update() #_idletasks()
                self.label.after(DELAY, None)
                    
    def load_images(self):
        
        files = os.listdir(IMAGE_PATH)
        
        images = list()
        for file in files:
            for image_format in IMAGE_FORMAT_FILTER:
                if image_format in file:
                    images.append(file)

        images = sorted(images,reverse=True)
        
        sorted_images = list()
        for row in xrange(ROWS):
            row_list = list()
            for column in xrange(COLUMNS):
                try:
                    row_list.append(ImageTk.PhotoImage(Image.open(
                    os.path.join(IMAGE_PATH, images.pop())).resize(
                    (RESIZE_IMAGE_WIDTH, RESIZE_IMAGE_HEIGHT)
                    )))
                except IndexError:
                    break
            sorted_images.append(row_list)
            
        return sorted_images
     
if __name__ == '__main__':
    root = tk.Tk()
    #root.update() #_idletasks()
    root.title(TITLE)
    image_viewer = Image_Viewer(root)
    #image_viewer.pack()  
    root.mainloop()
Da ich unter Linux arbeite und mir nicht deine Windows-Datei-Baumstruktur zur Verfügung stand habe ich den Bildpfad mit:

Code: Alles auswählen

IMAGE_PATH = os.getcwd()
auf mein Arbeitsverzeichnis gesetzt wo ich auch die Bilder für den Test abgelegt habe. So funktionier das einlesen der Bilddateien aus dem Arbeitsverzeichnis korrekt mit der Anweisung:

Code: Alles auswählen

row_list.append(ImageTk.PhotoImage(Image.open(
images.pop()).resize(
(RESIZE_IMAGE_WIDTH, RESIZE_IMAGE_HEIGHT)
)))
Dass es auchin deinem Fall funktioniert muss dein Bilderpfad:

Code: Alles auswählen

IMAGE_PATH = "C:/Python26/AVTGIF/" # wilhelmO's Pfad
noch mit dem Namen der Bilddatei wie folgt zusammengehängt werden:

Code: Alles auswählen

 row_list.append(ImageTk.PhotoImage(Image.open(
os.path.join(IMAGE_PATH, images.pop())).resize(
(RESIZE_IMAGE_WIDTH, RESIZE_IMAGE_HEIGHT)
 )))
Jetzt aber sollte dein Skript zum laufen kommen.

Gruß wuf :wink:
Take it easy Mates!
wilhelmO
User
Beiträge: 34
Registriert: Mittwoch 17. August 2011, 14:40

Hallo wuf
Vielen Dank für Überarbeitung !
Den IMAGE_PATH hatte ich schon abgeändert, da ich durch Kontrollausdruck des Pfades sah,
daß IMAGE_PATH = os.getcwd() mir das python-Installations und nicht mein Arbeitsverzeichnis
liefert.
Mit os.path.join wird python anscheinend auf das korrekte Verzeichnis hingewiesen , bzw.
das Verzeichnis wird hinzugefügt.

soweit sogut -- Programm meckert aber trotzdem -- folgende Fehlermeldung erhalte ich :

File "D:\Eclipse_Python\TK5\src\test15.py", line 56, in load_images
row_list.append(ImageTk.PhotoImage(Image.open(os.path.join(IMAGE_PATH,images.pop())).resize(RESIZE_IMAGE_WIDTH,RESIZE_IMAGE_HEIGHT)))
File "C:\Python26\Lib\site-packages\PIL\Image.py", line 1288, in resize
raise ValueError("unknown resampling filter")
ValueError: unknown resampling filter

Ich hab in PIL nachgesehen und finde keine Erklärung , da im.resize(size) auch ohne Filteran-
gabe genutzt werden. Wenn ich nun als dritten Parameter einen Filter hinzufüge wird mit
'unkown filter' gemeckert.

Nochmals das Programm , wie nun in eclipse vorhanden und gestartet :

Code: Alles auswählen

import Tkinter as tk
from PIL import Image, ImageTk
import os

ROWS = 3
COLUMNS = 4
TITLE ="TK 5 Formenscan"
IMAGE_PATH = "C:\Python26\AVTGIF" #os.getcwd()
print 'fpad =',IMAGE_PATH
IMAGE_FORMAT_FILTER = ['.gif','.png','.GIF','.PNG']
RESIZE_IMAGE_WIDTH = 80
RESIZE_IMAGE_HEIGHT = 60
DELAY = 1000

class Image_Viewer(tk.Frame):
    
    def __init__(self,root):
        
        tk.Frame.__init__(self,root)
        self.pack()
        self.bilder()
        print '1'
        
    def bilder(self):
        
        self.images = self.load_images()
        
        for row , images in enumerate(self.images):
            for column, image in enumerate(images):
                self.label = tk.Label(self,image=image)
                self.label.grid(row=row, column=column)
                self.label.update()
                self.label.after(DELAY,None)
        print '2'
                
    def load_images(self):
        
        files = os.listdir(IMAGE_PATH)
        print '3'
        print 'files=',files
        images = list()
        for file in files:
            for image_format in IMAGE_FORMAT_FILTER:
                if image_format in file:
                    images.append(file)
        print '4'            
        images = sorted(images,reverse=False)
        print '5'
        print'images nach sort',images
        sorted_images = list()
        print 'sortes_images=',sorted_images
        for row in xrange(ROWS):
            row_list = list()
            for column in xrange(COLUMNS):
                try:
                    row_list.append(ImageTk.PhotoImage(Image.open(os.path.join(IMAGE_PATH,images.pop())).resize(RESIZE_IMAGE_WIDTH,RESIZE_IMAGE_HEIGHT)))
                except IndexError:
                    break
            sorted_images.append(row_list)
            
        return sorted_images
    
if __name__ == '__main__':
    root = tk.Tk()
    #root.update_idletasks()
    root.title(TITLE)
    image_viewer = Image_Viewer(root)
    #image_viewer.pack()
    root.mainloop()
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo wilhelmO !

Code: Alles auswählen

import Tkinter as tk
from PIL import Image, ImageTk
import os
ROW = 3
COLUMN = 4
TITLE = "TK 5 FormenScan"
IMAGE_PATH = "/home/kaytec/Dokumente/images/"
RESIZE_IMAGE_WIDTH = 250
RESIZE_IMAGE_HEIGHT = 130
UPDATE_TIME = 2000


class Image_Viewer(tk.Frame):
    def __init__(self, root):
        tk.Frame.__init__(self, root)
        self.root = root
        self.current_images = self.load_images()
        self.labels = list()
        for row, images in enumerate(self.current_images):
            labels = list()
            for column, (image, file_name) in enumerate(images):
                label = tk.Label(self, image = image)
                label.grid(row = column, column = row)
                labels.append(label)
            self.labels.append(labels)
        
    def load_images(self):
        images = sorted(os.listdir(IMAGE_PATH))
        sorted_images = list()
        for i in xrange(ROW):
            l = list()
            for i in xrange(COLUMN):
                file_name = images.pop()
                l.append((ImageTk.PhotoImage(Image.open("%s%s" %(IMAGE_PATH, 
                    file_name)).resize((RESIZE_IMAGE_WIDTH,
                    RESIZE_IMAGE_HEIGHT))), file_name))
            sorted_images.append(l)
        return sorted_images
        
    def update(self):
        current_images = list()
        self.new_images = self.load_images()
        for cur_imgs, new_imgs, labels in zip(self.current_images, 
            self.new_images, self.labels):
            image_row= list()
            for cur_img, nw_img, label in zip(cur_imgs, new_imgs, labels):
                current_img, current_file_name = cur_img
                new_img, new_file_name = nw_img
                if current_file_name != new_file_name:
                    label.config(image = new_img)
                    image_row.append(nw_img)
                else:
                    image_row.append(cur_img)
            current_images.append(image_row)
        self.current_images = current_images
        self.root.after(UPDATE_TIME, self.update)
    
if __name__ == '__main__':
    root = tk.Tk()
    image_viewer = Image_Viewer(root)
    image_viewer.pack()
    image_viewer.update()
    root.title(TITLE) 
    root.mainloop()
Probiere mal diese Version.

Gruß Frank
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi wilhelmO

In deinem Skript fehlt ein Klammernpaar. Die folgende Zeile:

Code: Alles auswählen

row_list.append(ImageTk.PhotoImage(Image.open(os.path.join(IMAGE_PATH,images.pop())).resize(RESIZE_IMAGE_WIDTH,RESIZE_IMAGE_HEIGHT)))
muss wie folgt aussehen:

Code: Alles auswählen

row_list.append(ImageTk.PhotoImage(Image.open(os.path.join(IMAGE_PATH, images.pop())).resize((RESIZE_IMAGE_WIDTH,RESIZE_IMAGE_HEIGHT))))
Ich würde veruchen die Funktionen weniger tief zu verschachteln. Eventuell in mehrere Zeilen unterteilen.

Gruß wuf :wink:
Take it easy Mates!
wilhelmO
User
Beiträge: 34
Registriert: Mittwoch 17. August 2011, 14:40

Guten Morgen wuf und vielen Dank !!
Programm funktioniert - Fehler war fehlendes Klammerpaar
In meinem Fall war der Fehler vor dem Monitor ( Klammerpaar übersehen ).
Nun habe zwei funktionierende Versionen ( erste von kaytec - nochmals vielen Dank ) , die
sich im Aufbau etwas unterscheiden. Werde bei noch eingehend untersuchen.

:D Allen Beteiligten wünsche ich ein schönes Wochenende und nochmals vielen Dank an
alle ! :D
Antworten