3
votes

Afficher une grande image à l'aide de la barre de défilement en Python

Je voudrais afficher une image en utilisant tkinter (Python 3). L'image est très longue. Par conséquent, je voudrais ajouter une barre de défilement verticale. Voici ce que j'ai essayé:

(basé sur cette question: Scrollbars pour une image .jpg sur un Tkinter Canvas en Python )

import tkinter
import PIL.Image, PIL.ImageTk

# Create a window
window = tkinter.Tk()

frame = tkinter.Frame(window, bd=2) # relief=SUNKEN)

frame.grid_rowconfigure(0, weight=1)
frame.grid_columnconfigure(0, weight=1)

xscrollbar = tkinter.Scrollbar(frame, orient=tkinter.HORIZONTAL)
xscrollbar.grid(row=1, column=0, sticky=tkinter.E+tkinter.W)

yscrollbar = tkinter.Scrollbar(frame)
yscrollbar.grid(row=0, column=1, sticky=tkinter.N+tkinter.S)

canvas = tkinter.Canvas(frame, bd=0, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set)
canvas.grid(row=0, column=0, sticky=tkinter.N+tkinter.S+tkinter.E+tkinter.W)
canvas.config(scrollregion=canvas.bbox(tkinter.ALL))

File = "FILEPATH"
img = PIL.ImageTk.PhotoImage(PIL.Image.open(File))
canvas.create_image(0,0,image=img, anchor="nw")

xscrollbar.config(command=canvas.xview)
yscrollbar.config(command=canvas.yview)

frame.pack()
window.mainloop()

J'obtiens ce qui suit:

Je suis capable de tracer l'image, mais les barres de défilement ne fonctionnent pas. Ils sont simplement gris et ne fonctionnent pas.

 entrez la description de l'image ici


0 commentaires

3 Réponses :


3
votes

Mettez la ligne:

canvas.create_image(0,0,image=img, anchor="nw")

après:

canvas.config(scrollregion=canvas.bbox(tkinter.ALL))

ou le canevas n'inclut pas l'image dans scrollregion.

p>


0 commentaires

3
votes

Définissez la zone de défilement du canevas après avoir dessiné l'image:

canvas.create_image(0, 0, image=img, anchor="nw")
canvas.config(scrollregion=canvas.bbox(tkinter.ALL))


3 commentaires

Question rapide: sauriez-vous comment augmenter la taille de la figure tkinter?


@henry - Si vous vouliez dire PhotoImage, vous pouvez utiliser PIL.ImageTk.PhotoImage (PIL.Image.open (File) .resize ((width, height)))


Génial. Merci !



5
votes

Si vous voulez un widget d'image défilante, le meilleur moyen serait de créer une classe d'image défilante qui arrangera et ressemblera mieux à votre code. J'ai donc créé une classe pour le même et également ajouté bind afin que l'on puisse faire défiler leur souris pour voir l'image plus facilement.


Voici l'exemple de code

import tkinter as tk
# Import the package if saved in a different .py file else paste 
# the ScrollableImage class right after your imports.
from scrollimage import ScrollableImage   

root = tk.Tk()

# PhotoImage from tkinter only supports:- PGM, PPM, GIF, PNG format.
# To use more formats use PIL ImageTk.PhotoImage
img = tk.PhotoImage(file="logo.png")

image_window = ScrollableImage(root, image=img, scrollbarwidth=6, 
                               width=200, height=200)
image_window.pack()

root.mainloop()

Comment utiliser la classe?

Traitez la classe ScrollableImage comme un widget de Tkinter et utilisez comme vous utilisez n'importe quel autre widget Tkinter car tous les autres widgets sont une classe à eux seuls si vous voyez le code source de tkinter .

Vous pouvez utiliser ScrollableImage de différentes manières.

  1. Enregistrez le code ci-dessus dans un nouveau fichier .py (par exemple: "scrollimage.py") en tant que package dans le même répertoire puis importez dans votre classe principale comme from scrollimage import ScrollableImage puis utilisez-le comme un widget normal.

  2. Ou vous pouvez garder la classe ScrollableImage en haut après les importations de votre fichier principal et l'utiliser comme d'habitude.

import tkinter

class ScrollableImage(tkinter.Frame):
    def __init__(self, master=None, **kw):
        self.image = kw.pop('image', None)
        sw = kw.pop('scrollbarwidth', 10)
        super(ScrollableImage, self).__init__(master=master, **kw)
        self.cnvs = tkinter.Canvas(self, highlightthickness=0, **kw)
        self.cnvs.create_image(0, 0, anchor='nw', image=self.image)
        # Vertical and Horizontal scrollbars
        self.v_scroll = tkinter.Scrollbar(self, orient='vertical', width=sw)
        self.h_scroll = tkinter.Scrollbar(self, orient='horizontal', width=sw)
        # Grid and configure weight.
        self.cnvs.grid(row=0, column=0,  sticky='nsew')
        self.h_scroll.grid(row=1, column=0, sticky='ew')
        self.v_scroll.grid(row=0, column=1, sticky='ns')
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        # Set the scrollbars to the canvas
        self.cnvs.config(xscrollcommand=self.h_scroll.set, 
                           yscrollcommand=self.v_scroll.set)
        # Set canvas view to the scrollbars
        self.v_scroll.config(command=self.cnvs.yview)
        self.h_scroll.config(command=self.cnvs.xview)
        # Assign the region to be scrolled 
        self.cnvs.config(scrollregion=self.cnvs.bbox('all'))
        self.cnvs.bind_class(self.cnvs, "<MouseWheel>", self.mouse_scroll)

    def mouse_scroll(self, evt):
        if evt.state == 0 :
            self.cnvs.yview_scroll(-1*(evt.delta), 'units') # For MacOS
            self.cnvs.yview_scroll(int(-1*(evt.delta/120)), 'units') # For windows
        if evt.state == 1:
            self.cnvs.xview_scroll(-1*(evt.delta), 'units') # For MacOS
            self.cnvs.xview_scroll(int(-1*(evt.delta/120)), 'units') # For windows

La liaison nécessite quelques modifications sur fenêtres comme diviser event.delta par 120. Sur macOS, aucune modification n'est nécessaire. Et sur X11, vous devez lier à la fois , et également diviser event.delta par 120.

  • Tkinter Mousewheel Binding

    Pour plus de détails sur bind et comment cela fonctionne sur différentes plates-formes, vous pouvez consulter le lien ci-dessus.

  • Meilleur moyen de structurer l'application Tkinter.

    Vous pouvez vous référer au lien ci-dessus pour lire en détail comment vous pouvez appliquer correctement Oops dans Tkinter. Lorsque vous utilisez les POO, vous pouvez toujours hériter de n'importe quel widget de Tkinter et le modifier pour créer de nouveaux widgets et des classes utiles qui vous aideront à améliorer votre application avec Tkinter.


9 commentaires

Hou la la ! Merci beaucoup pour votre classe! Cela semble très utile. Je suis assez nouveau sur tkinter. Comment l'utiliseriez-vous? Pourriez-vous ajouter un petit exemple? Merci.


@Henry: J'ai ajouté des informations plus utiles qui vous aideront à mieux apprendre.


Merci beaucoup ! C'est très gentil de votre part et très utile!


J'obtiens l'erreur suivante: Exception dans Tkinter callback Traceback (dernier appel en dernier): Fichier "C: \ Users \ Anaconda3 \ lib \ tkinter_ init_ .py", ligne 1702, dans appel renvoie self.func (* args) Fichier "", ligne 31, dans mouse_scroll self.yview_scroll (-1 * (evt.delta/120), 'units') # Pour Windows Fichier "C: \ Users \ Anaconda3 \ lib \ tkinter_ init_ .py", ligne 1748, dans yview_scroll self.tk.call (self._w, 'yview', 'scroll', number , quoi) _tkinter.TclError: entier attendu mais a obtenu "1.0"


@henry: c'est parce que scroll prend une valeur entière et "1.0" est une valeur flottante, le correctif est simple, il suffit de le convertir en entier. J'ai cependant édité mon message et l'ai corrigé. Je n'ai pas pu tester cela car je suis sur Macos. J'espère que cela fonctionnera maintenant.


Hmm .. comment changeriez-vous la taille de la fenêtre?


Tout comme vous modifiez la taille d'un widget avec les paramètres width et height , voir le code à la ligne 42 ScrollableImage (root, image = img, width = 200, hauteur = 200) .pack ()


Merci beaucoup pour votre patience et votre aide! J'apprécie beaucoup. Peut-être, si vous avez le temps, voudriez-vous jeter un œil à mon autre question: stackoverflow.com/questions/56056054/...


Pas de problème, et j'y reviendrai plus tard.