Bildgröße anpassen und im Frame anzeigen

Fragen zu Tkinter.
Antworten
suk
User
Beiträge: 17
Registriert: Sonntag 17. Dezember 2017, 01:18

Hallo,

ich habe mir schon diverse Beiträge zum Thema angesehen, jedoch immer noch nicht verstanden, wo mein Problem liegt.

Ich möchte einen Dialog für eine Bildauswahl zur Verfügung stellen. Das ausgewählte Bild soll auf eine bestimmte Größe angepasst und in einem Frame dargestellt werden.
Ich bekomme jedoch das Bild nicht angezeigt?! Es wird immer nur der graue Hintergrund darstellt.
Hinweis: Den Auswahldialog habe ich mal weggelassen und nur versucht, den Code auf die Bildumwandlung und -darstellung zu reduzieren.

Könnt Ihr mal bitte den Fehler erklären und auf ein Lösungsbeispiel anpassen.
Danke.

Code: Alles auswählen

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

### Import der erforderlichen Module ###
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
    
from functools import partial
import tkinter.font as tkf
from PIL import ImageTk, Image

### Fensterdefinition ###
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300

### Inhalt Canvas-Applikation ###
class App_Canvas():
    def __init__(self, canvasmaster):
        self.mycanvas = canvasmaster


### Inhalt Frame-Applikation ###
class App_Frame():
    def __init__(self, framemaster):
        self.myframe = framemaster
        self.myframe.pack()
        self.obj_image = Image.open("/home/pi/python_scripts/python-GUI/Images/person1.gif")
        self.obj_image = self.obj_image.resize((200, 200), Image.ANTIALIAS)
        self.myimage = ImageTk.PhotoImage(self.obj_image)
        self.mylabel = tk.Label(self.myframe, image=self.myimage, width=200, height=200, relief="groove")
        self.mylabel.pack()


### Applikationsstart ###
def main():
    win_master = tk.Tk()
    win_master.title(APP_TITLE)
    app_canvas = tk.Canvas(win_master, width=APP_WIDTH, height=APP_HEIGHT, relief="groove", bg="white", bd=5)
#    app_canvas.pack()
    app_frame = tk.Frame(win_master, width=APP_WIDTH, height=APP_HEIGHT, relief="sunken", bg="gray", bd=3)
    app_frame.pack()
    button1 = tk.Button(win_master, text="close", command=win_master.destroy)
    button1.pack()
#    App_Canvas(app_canvas)
    App_Frame(app_frame)
    win_master.mainloop()

if __name__ == '__main__':
    main()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi suk

Kannst du das folgende Skript einmal ausprobieren?:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
### Import der erforderlichen Module ###
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
   
from functools import partial
import tkinter.font as tkf
from PIL import ImageTk, Image
 
### Fensterdefinition ###
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300
 
### Inhalt Canvas-Applikation ###
class App_Canvas():
    def __init__(self, canvasmaster):
        self.mycanvas = canvasmaster
 
 
### Inhalt Frame-Applikation ###
class App_Frame():
    def __init__(self, framemaster):
        self.myframe = framemaster
        self.myframe.pack()
        self.obj_image = Image.open("/home/pi/python_scripts/python-GUI/Images/person1.gif")
        #self.obj_image = Image.open("person1.gif")
        self.obj_image = self.obj_image.resize((200, 200), Image.ANTIALIAS)
        self.myimage = ImageTk.PhotoImage(self.obj_image)
        self.mylabel = tk.Label(self.myframe, image=self.myimage, width=200, height=200, relief="groove")
        self.mylabel.pack()
 
 
### Applikationsstart ###
def main():
    win_master = tk.Tk()
    win_master.title(APP_TITLE)
    app_canvas = tk.Canvas(win_master, width=APP_WIDTH, height=APP_HEIGHT, relief="groove", bg="white", bd=5)
#    app_canvas.pack()
    app_frame = tk.Frame(win_master, width=APP_WIDTH, height=APP_HEIGHT, relief="sunken", bg="gray", bd=3)
    app_frame.pack()
    button1 = tk.Button(win_master, text="close", command=win_master.destroy)
    button1.pack()
#    App_Canvas(app_canvas)
    app = App_Frame(app_frame)
    win_master.mainloop()
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi suk

Dein Applikationsskript würde ich wie folgt gestalten:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
### Import der erforderlichen Module ###
from functools import partial

try:
# Tkinter for Python 2.xx
    import Tkinter as tk
    import tkFont as tkf
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
    import tkinter.font as tkf
       
from PIL import ImageTk, Image
 
### Fensterdefinition ###
APP_TITLE = "Personal Images"
APP_WIDTH = 600
APP_HEIGHT = 300
 
 
### Inhalt Canvas-Applikation ###
class App_Canvas(tk.Canvas):
    def __init__(self, canvas_master, **kwargs):
        self.canvas_master = canvas_master
        
        tk.Canvas.__init__(self, canvas_master, **kwargs)
 
 
### Inhalt Frame-Applikation ###
class App_Frame(tk.Frame):
    def __init__(self, frame_master, **kwargs):
        self.frame_master = frame_master
        tk.Frame.__init__(self, frame_master, **kwargs)
        
        self.obj_image = Image.open("/home/pi/python_scripts/python-GUI/Images/person1.gif")
        #self.obj_image = Image.open("person1.gif")
        self.obj_image = self.obj_image.resize((200, 200), Image.ANTIALIAS)
        self.myimage = ImageTk.PhotoImage(self.obj_image)
        self.mylabel = tk.Label(self, image=self.myimage, width=200,
            height=200, relief="groove")
        self.mylabel.pack()
 
 
### Applikationsstart ###
def main():
    win_master = tk.Tk()
    win_master.title(APP_TITLE)
    
    app_canvas = App_Canvas(win_master, width=APP_WIDTH, height=APP_HEIGHT,
        relief="groove", bg="white", bd=5)
    app_canvas.pack()
    
    app_frame = App_Frame(win_master, width=APP_WIDTH, height=APP_HEIGHT,
        relief="sunken", bg="gray", bd=3)
    app_frame.pack()
    
    button1 = tk.Button(win_master, text="close", command=win_master.destroy)
    button1.pack()

    win_master.mainloop()
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
suk
User
Beiträge: 17
Registriert: Sonntag 17. Dezember 2017, 01:18

@Wuf: Danke für die Antwort.
Ich habe Deine erste Version übernommen und geht. Jetzt ist die Frage, warum. Entweder bin ich blind oder ich konnte den Unterschied nicht finden. Oder beides ;)
Hilf mir mal bitte auf die Sprünge, wo Dein erstes Script abweicht.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi suk

Du glaubst es nicht aber ich habe einzig die Zeile 50 in deinem Skript:

Code: Alles auswählen

App_Frame(app_frame)
abgeändert auf (in meinem Skript ist es übrigens die Zeile 51:

Code: Alles auswählen

app = App_Frame(app_frame)
Wenn du dich mit Tkinter beschäftigt wirst du mit der Zeit ein Zauberer.

Gruss wuf :wink:
Take it easy Mates!
suk
User
Beiträge: 17
Registriert: Sonntag 17. Dezember 2017, 01:18

gute Show :o :K :D
Kannst Du mir den "Trick" auch erklären?
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi suk
Kannst Du mir den "Trick" auch erklären?
Kann ich dir leider nicht. Ich möchte mich nicht als Experten bezeichnen. Komme selber eher aus der Sparte der Tüftler. Weicht man von einer gängigen Skriptgestaltung ab offenbaren sich manchmal Dinge die jemand so nicht erwartet. Da brauche ich auch die Hilfe von unseren Forumexperten. Habe dein Skript auf das wesentliche reduziert. So entstanden die drei folgenden Varianten. Die ersten zwei davon funktionieren bei mir nicht.

Variante-1:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
 
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300
 
 
class App_Frame(object):
    
    def __init__(self, frame):
        self.myimage = tk.PhotoImage(file="person1.gif")
        self.mylabel = tk.Label(frame, image=self.myimage, width=200, bg='red',
            height=200, relief="groove")
        self.mylabel.pack()
 

def main():
    win_master = tk.Tk()
    win_master.title(APP_TITLE)

    app_frame = tk.Frame(win_master)
    app_frame.pack()
    
    App_Frame(app_frame)

    button1 = tk.Button(win_master, text="close", command=win_master.destroy)
    button1.pack()

    win_master.mainloop()
 
if __name__ == '__main__':
    main()
Variante-2:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
 
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300
 
 
class App_Frame(object):
    
    def __init__(self, master):
        frame = tk.Frame(master)
        frame.pack()

        self.myimage = tk.PhotoImage(file="person1.gif")
        self.mylabel = tk.Label(frame, image=self.myimage, width=200, bg='red',
            height=200, relief="groove")
        self.mylabel.pack()
 

def main():
    win_master = tk.Tk()
    win_master.title(APP_TITLE)
    
    App_Frame(win_master)

    button1 = tk.Button(win_master, text="close", command=win_master.destroy)
    button1.pack()

    win_master.mainloop()
 
if __name__ == '__main__':
    main()
Variante-3:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
 
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300
 
 
class App_Frame(tk.Frame):
    
    def __init__(self, master):
        
        tk.Frame.__init__(self, master)

        self.myimage = tk.PhotoImage(file="person1.gif")
        self.mylabel = tk.Label(self, image=self.myimage, width=200, bg='red',
            height=200, relief="groove")
        self.mylabel.pack()
 

def main():
    win_master = tk.Tk()
    win_master.title(APP_TITLE)
    
    App_Frame(win_master).pack()

    button1 = tk.Button(win_master, text="close", command=win_master.destroy)
    button1.pack()

    win_master.mainloop()
 
if __name__ == '__main__':
    main()
Kannst du diese drei Varianten auch bei dir ausprobieren. Wie gesagt bei mir läuft nur die Variante-3 korrekt.

Gruss wuf :wink:
Take it easy Mates!
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@wuf: Deine Klassen in den ersten beiden Varianten sind eigentlich keine. Eine einfache Funktion hätte den selben Effekt:

Code: Alles auswählen

def App_Frame(frame):
    myimage = tk.PhotoImage(file="person1.gif")
    mylabel = tk.Label(frame, image=myimage, width=200, bg='red',
            height=200, relief="groove")
    mylabel.pack()
Dadurch, dass Du keine Referenz auf die Instanz der Klasse speicherst, wird sie sofort wieder vom Speichermanagement abgeräumt, und damit auch die Referenz auf das Bild.

Im letzten Fall hast Du einen Frame, der durch ›pack‹ eine Referenz in den internen Strukturen behält.

Am einfachsten zu Verstehen ist immer noch, die Imagereferenz direkt im Label zu speichern:

Code: Alles auswählen

def label_with_image(frame, filename):
    image = tk.PhotoImage(file=filename)
    label = tk.Label(frame, image=image, width=200, bg='red',
            height=200, relief="groove")
    label.image = image
    return label

def main():
    win_master = tk.Tk()
    label_with_image(win_master, "person1.gif").pack()
    tk.Button(win_master, text="close", command=win_master.destroy).pack()
    win_master.mainloop()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Sirius3

Besten Dank für deine klärenden Worte. Habe mein Variante-2 Skript noch weiter reduziert auf:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
 
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300
 
 
class App_Frame(object):
    
    def __init__(self, master):

        self.myimage = tk.PhotoImage(file="person1.gif")
        self.mylabel = tk.Label(master, image=self.myimage, width=200, bg='red',
            height=200, relief="groove")
        self.mylabel.pack()
 

def main():
    win_master = tk.Tk()
    win_master.title(APP_TITLE)
    
    App_Frame(win_master)

    button1 = tk.Button(win_master, text="close", command=win_master.destroy)
    button1.pack()

    win_master.mainloop()
 
if __name__ == '__main__':
    main()
Welche immer noch nicht funktioniert. Erst wenn von der Klasse App_Frame eine Instanz app wie folgt erzeugt wird klapp es:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
 
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300
 
 
class App_Frame(object):
    
    def __init__(self, master):

        self.myimage = tk.PhotoImage(file="person1.gif")
        self.mylabel = tk.Label(master, image=self.myimage, width=200, bg='red',
            height=200, relief="groove")
        self.mylabel.pack()
 

def main():
    win_master = tk.Tk()
    win_master.title(APP_TITLE)
    
    app = App_Frame(win_master)

    button1 = tk.Button(win_master, text="close", command=win_master.destroy)
    button1.pack()

    win_master.mainloop()
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Ergänzend noch das folgende Skript, welches auch funktioniert:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
 
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300
 
 
class App_Frame(tk.Tk):
    
    def __init__(self):

        tk.Tk.__init__(self)
        self.title(APP_TITLE)
        
        self.myimage = tk.PhotoImage(file="person1.gif")
        self.mylabel = tk.Label(self, image=self.myimage, width=200, bg='red',
            height=200, relief="groove")
        self.mylabel.pack()

        button1 = tk.Button(self, text="close", command=self.destroy)
        button1.pack()
        
        self.mainloop()
 

App_Frame()
Gruss wuf :wink:
Take it easy Mates!
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@wuf: wenn man eine Instanz erzeugt, dann aber nichts damit macht, deutet das immer auf einen Fehler hin, zumindest in der Logik. ›__init__‹ ist zum Initialisieren da und nicht, dass sie unbegrenzt läuft.

Das Programm sollte also zumindest so aussehen:

Code: Alles auswählen

class App_Frame(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title(APP_TITLE)
       
        self.myimage = tk.PhotoImage(file="person1.gif")
        self.mylabel = tk.Label(self, image=self.myimage, width=200, bg='red',
            height=200, relief="groove")
        self.mylabel.pack()
 
        tk.Button(self, text="close", command=self.destroy).pack()

app = App_Frame()
app.mainloop()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Sirius3

OK. Währe das folgende Skript dann besser?:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
try:
# Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
    import tkinter as tk
 
APP_TITLE = "Template"
APP_WIDTH = 600
APP_HEIGHT = 300
 
 
class App_Frame(tk.Tk):
    
    def __init__(self):

        tk.Tk.__init__(self)
        self.title(APP_TITLE)
        
        self.build()
        
    def build(self):
        self.myimage = tk.PhotoImage(file="person1.gif")
        self.mylabel = tk.Label(self, image=self.myimage, width=200, bg='red',
            height=200, relief="groove")
        self.mylabel.pack()

        button1 = tk.Button(self, text="close", command=self.destroy)
        button1.pack()
        
        self.mainloop()
 

App_Frame()
Gruss wuf :wink:
Take it easy Mates!
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein, denn du rufst doch einfach nur eine Methode auf, immer noch aus dem __init__.

Das haben wir doch aber neulich schon alles mal durchdekliniert: viewtopic.php?f=18&t=41785&start=30#p319571
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Das haben wir doch aber neulich schon alles mal durchdekliniert: viewtopic.php?f=18&t=41785&start=30#p319571
Danke für deinen Hinweis.
Take it easy Mates!
Antworten