Hallo zusammen,
ich möchte eine Bildervorschau realisieren, quasi 'n' Thumbnails in Reihe nebeneinander in einem Container. Werden mehr Bilder eingefügt, als der Container breit ist, dann soll man per Scrollbar (horizontal) hin und her scrollen können. Ich habe diverse Beispiele gefunden, aber alle mit einem Canvas, Text oder Listbox-Widget. Dass kann ich ja nicht einsetzen für meine Wünsche. Ein Frame könnte ich als Container gut für die Bilder-Buttons nutzen, aber es lässt sich (von mir) leider kein Scroll-Event damit verbinden.
Was kann ich tuen, damit ich 'n' Bilderchen neben einander in ein Container bekomme, der scrollbar ist? Ich stelle mir ein Außen-Frame vor, welcher ein "main" als Parent hat. Darin kann/sollte dann der "Container?" sein, der die Bilder-Buttons beinhaltet, quasi parallel dazu gibt es die Scrollbar. Hat jemand ein Beispiel für die Vorschau oder kann mir sagen, wie ich das mit dem Frame (oder ein anderen passenden Container) hinbekommen kann?
Grüße,
Volker
Frame, als Container für Bilder-Buttons, mit Scrollbar?
@VolkerH: Von welchem GUI-Toolkit reden wir denn hier? Damit man das Thema ins passende Unterforum verschieben kann.
@VolkerH: Wenn man einem `Frame` Scrollbalken verpassen möchte, dann geht das über den Umweg eines `Canvas`. Dem verpasst man Scrollbalken. Und auf einem `Canvas` kann man beliebige Widgets platzieren. Zum Beispiel auch einen `Frame`.
@BlackJack: Moin. Das habe ich im Netz gelesen und ich hatte es auch versucht nachzubauen. Aber die Scrollbar hatte nicht reagiert, also der Slider wurde nicht angezeigt, obwohl das Canvas breiter war als das Grund-Frame(Parent). Gibt es dazu ein Beispiel? Ich werde es noch einmal nachbauen und hier den Code einfügen. Danke vorerst.
@VolkerH: Hast Du denn auch die `scrollregion` vom `Canvas` entsprechend dem Inhalt gesetzt?
@BlackJack: Ich habe das Script nachgebaut, so wie ich es wohl hatte. Wenn ich das laufen lasse, dann wird die Breite des Canvas auch erhöht, was die beiden Print-Commands ausgeben. Es
werden insgesamt 18 Bilder-Button erstellt und ins Canvas gehängt, was eine Mindesbreite dessen von 1800 Pixel ergibt. Die Anwendung ist auf 1050 Pixel festgelegt. Die Farben und Kommentare sind nur für Testzwecke eingefügt, wie auch die Prints. In allem sieht es nicht schlecht aus, die Bilder sind zu sehen, allerdings die Scrollbar nicht. Wo liegt der Fehler?
werden insgesamt 18 Bilder-Button erstellt und ins Canvas gehängt, was eine Mindesbreite dessen von 1800 Pixel ergibt. Die Anwendung ist auf 1050 Pixel festgelegt. Die Farben und Kommentare sind nur für Testzwecke eingefügt, wie auch die Prints. In allem sieht es nicht schlecht aus, die Bilder sind zu sehen, allerdings die Scrollbar nicht. Wo liegt der Fehler?
Code: Alles auswählen
intAppWidth = 1050 #Gesamte Breite er Anwendung
xpos=0 #Zaehler für die Breite des Containers der Bilder-Button-Anzeige
outerFrame = tkinter.Frame(main, width=intAppWidth, height=200, bd=1, \
relief=tkinter.SUNKEN)
outerFrame['background']="blue"
outerFrame.place(x=0, y=0)
preViewXScrollbar = tkinter.Scrollbar(outerFrame, orient=tkinter.HORIZONTAL)
preViewContainer = tkinter.Canvas(outerFrame, width=xpos, \
height=145, bg="red", bd=1, highlightthickness=0, \
xscrollcommand=preViewXScrollbar.set)
preViewContainer.place(x=0, y=0)
preViewXScrollbar.config(command=preViewContainer.xview)
preViewXScrollbar.place(x=0, y=180, width=outerFrame['width'])
# Create the galerie of pictures
galerie = Galerie().getGalerie(imgFolder)
# Show previews
for (key, value) in galerie.items():
print(key)
newPreView = ImgPreView(preViewContainer, value, key).getPreView()
print("old: {}".format(preViewContainer['width']))
preViewContainer['width']=xpos+newPreView['width']+10
print("new: {}".format(preViewContainer['width']))
newPreView.place(x=xpos, y=0)
newPreView['command']=lambda name=newPreView.config('text')[-1]:OnClick(name) #Verknüpfung mit Funktionsaufruf
xpos +=newPreView['width']
@VolkerH: Ich habe jetzt nur kurz drübergeschaut und habe nirgends gesehen wo die `scrollregion` vom Canvas festgelegt wird. Meine letzte Frage wäre dann also mit Nein beantwortet. Das fehlt halt. So ein Canvas ist ja ”unendlich” gross, darum muss man den Bereich festlegen der gescrollt werden soll.
Dein Einsatz von `place()` ist übrigens nicht gut. Für die Bilder-Schaltflächen kann man das gerade noch so rechtfertigen, auch wenn man dort besser `pack()` verwendet, aber der Rest der GUI wird auf diese weise unflexibel und bei anderen Rechnern eventuell sogar hässlich bis hin zu technisch unbenutzbar.
Die Namen weichen vom Style Guide for Python Code ab.
sieht nach einem „code smell” aus. Warum muss man ein Objekt erstellen dessen einzige Zweck der Aufruf *einer* Methode ist und dass dann gleich wieder verworfen wird? Ist `getGalerie()` tatsächlich eine Methode oder nur eine Funktion die grundlos in eine Klasse gesteckt wurde? Bei `ImgPreView` wiederholt sich dieses Muster. Zusammen mit der Schreibweise der Namen erinnert das eher an Java als an Python.
Dein Einsatz von `place()` ist übrigens nicht gut. Für die Bilder-Schaltflächen kann man das gerade noch so rechtfertigen, auch wenn man dort besser `pack()` verwendet, aber der Rest der GUI wird auf diese weise unflexibel und bei anderen Rechnern eventuell sogar hässlich bis hin zu technisch unbenutzbar.
Die Namen weichen vom Style Guide for Python Code ab.
Code: Alles auswählen
galerie = Galerie().getGalerie(imgFolder)
@BlackJack: Dann werde ich versuchen die 'scrollregion' einzurichten. Habe ich bis dato keine Info zu gelesen und hätte somit wahrscheinlich noch Jahre gesucht... Danke! Das Aussehen des Codes, also Formate bzgl. Namen und soweiter, ist sicherlich noch nicht perfekt. Ich bin ein Umsteiger, habe jetzt vielleicht drei bis vier Wochen mehr oder wenige mit Python zu tuen, nur in meiner Freizeit oder in der Mittagspause
Tatsächlich habe ich früher einige unterschiedliche Programmiersprachen beruflich genutzt, Java war auch dabei, gut erkannt. Die Klassen habe ich gebaut, um zum einen eine Wiederverwendbarkeit zu haben und zum anderen schien es mir geschickt, damit ich dann bei Änderungen nur in der Klasse hantieren muss. Mein Ziel beim Python-Programmieren ist in erster Linie die Sprache kennen zu lernen, und dann werde ich mich um einen besseren 'Python-Style' kümmern, naja, eigentlich läuft das ja aber auch schon parallel. Danke nochmals!
Tatsächlich habe ich früher einige unterschiedliche Programmiersprachen beruflich genutzt, Java war auch dabei, gut erkannt. Die Klassen habe ich gebaut, um zum einen eine Wiederverwendbarkeit zu haben und zum anderen schien es mir geschickt, damit ich dann bei Änderungen nur in der Klasse hantieren muss. Mein Ziel beim Python-Programmieren ist in erster Linie die Sprache kennen zu lernen, und dann werde ich mich um einen besseren 'Python-Style' kümmern, naja, eigentlich läuft das ja aber auch schon parallel. Danke nochmals!
@VolkerH: Eine Klasse ist ja nicht automatisch wiederverwendbar(er) als eine Funktion. So Sachen wie ``Galerie().getGalerie(imgFolder)`` sind einfach nur zusätzliche Schreibarbeit. Zumal das in diesem Fall auch sehr eigenartig aussieht, denn von einem `Galerie()`-Aufruf erwartet man ein Objekt vom Typ `Galerie` und von einer `getGalerie()`-Methode *ebenfalls*. Da fragt man sich beim Lesen warum da nicht ``Galerie(image_folder)`` steht oder ``Galerie.from_folder(image_folder)``. Wenn da letztendlich nur ein Wörterbuch (`dict`) bei rumkommt, hätte ich eine `get_galerie()`-Funktion erwartet.
Auf der anderen Seite ist der gezeigte Quelltext ganz schön viel Code auf Modulebene der nicht einmal in Funktionen steckt, sich aber geradezu für Klassen anbietet. Zum Beispiel das man so ein `Canvas` + `Frame` + Scrollbalken in einer Klasse zu einem eigenen Widget zusammenfasst.
Auf der anderen Seite ist der gezeigte Quelltext ganz schön viel Code auf Modulebene der nicht einmal in Funktionen steckt, sich aber geradezu für Klassen anbietet. Zum Beispiel das man so ein `Canvas` + `Frame` + Scrollbalken in einer Klasse zu einem eigenen Widget zusammenfasst.
Hi VolkerH
Hier eine Scroll-Variante auf Modulebene:
Gruß wuf
Hier eine Scroll-Variante auf Modulebene:
Code: Alles auswählen
import sys
try:
#~~ For Python 2.x
import Tkinter as tk
except ImportError:
#~~ For Python 3.x
import tkinter as tk
script_name = sys.argv[0]
MAIN_WIN_XPOS = 10
MAIN_WIN_YPOS = 10
MAIN_WIN_WIDTH = 500
MAIN_WIN_HEIGHT = 500
SCROLL_WIDTH = 1000
SCROLL_HEIGHT = 1000
app_win = tk.Tk()
app_win.geometry("%dx%d+%d+%d" % (MAIN_WIN_WIDTH, MAIN_WIN_HEIGHT,
MAIN_WIN_XPOS, MAIN_WIN_YPOS))
app_win['bg'] = 'khaki'
app_win.title(script_name)
app_frame = tk.Frame(app_win, bd=0, relief='sunken')
app_frame.grid_rowconfigure(0, weight=1)
app_frame.grid_columnconfigure(0, weight=1)
app_frame.pack(fill='both', expand='yes')
xscrollbar = tk.Scrollbar(app_frame, orient='horizontal')
xscrollbar.grid(row=1, column=0, sticky='ew')
yscrollbar = tk.Scrollbar(app_frame)
yscrollbar.grid(row=0, column=1, sticky='ns')
scroll_geometry = (0, 0, SCROLL_WIDTH, SCROLL_HEIGHT)
plane = tk.Canvas(app_frame, bd=0, scrollregion=scroll_geometry,
bg='steelblue3', xscrollcommand=xscrollbar.set, highlightthickness=0,
yscrollcommand=yscrollbar.set)
plane.grid(row=0, column=0, sticky='nsew')
xscrollbar.config(command=plane.xview)
yscrollbar.config(command=plane.yview)
plane.create_rectangle(100, 50, 800, 500, fill='yellow')
app_win.mainloop()
Take it easy Mates!
@wuf: Vielen Dank für Dein Beispiel. Ein paar Unterschiede zwischen Deiner Lösung und meiner habe ich schon gefunden. Meine Lösung läuft zwar, man kann scrollen per Buttons, aber der Schieberegler hat noch ein Problemchen. Ich werde Dein Script mit einbauen und vor allem werde ich meinen Code verbessern. Hinweise habe ich mittlererweile viele bekommen (@BlackJack ), die ich nun nach und nach umsetzen werde. Nach dem ich nun die Sachen geschaft habe, die auf meiner Liste oben standen, werde ich mich nun erst einmal in den 'Style Guide for Python Code' vergraben.