web-dev-qa-db-fra.com

Python tkinter liant la souris à la barre de défilement

J'ai ce cadre défilable (cadre à l'intérieur de la toile en fait).

import Tkinter as tk
class Scrollbarframe():
    def __init__(self, parent,xsize,ysize,xcod,ycod):
        def ScrollAll(event):
                canvas1.configure(scrollregion=canvas1.bbox("all"),width=xsize,height=ysize,bg='white')
        self.parent=parent
        self.frame1=tk.Frame(parent,bg='white')
        self.frame1.place(x=xcod,y=ycod)
        canvas1=tk.Canvas(self.frame1)
        self.frame2=tk.Frame(canvas1,bg='white',relief='groove',bd=1,width=1230,height=430)
        scrollbar1=tk.Scrollbar(self.frame1,orient="vertical",command=canvas1.yview)
        canvas1.configure(yscrollcommand=scrollbar1.set)
        scrollbar1.pack(side="right",fill="y")
        canvas1.pack(side="left")
        canvas1.create_window((0,0),window=self.frame2,anchor='nw')
        self.frame2.bind("<Configure>",ScrollAll)

Je voudrais lier la molette de la souris à la barre de défilement afin que l'utilisateur puisse faire défiler le cadre sans avoir à utiliser les boutons fléchés de la barre de défilement. Après avoir regardé autour de moi, j'ai ajouté une liaison à mon canvas1 comme ça

self.frame1.bind("<MouseWheel>", self.OnMouseWheel)

Voici la fonction:

def OnMouseWheel(self,event):
    self.scrollbar1.yview("scroll",event.delta,"units")
    return "break" 

Mais la barre de défilement ne bouge pas lorsque j'utilise la molette de la souris. Est-ce que quelqu'un peut m'aider avec ça? Tout ce que je veux, c'est que lorsque l'utilisateur utilise la molette de la souris (à l'intérieur de la zone du cadre/sur la barre de défilement), la toile doit automatiquement défiler vers le haut ou vers le bas.

30
Chris Aung

La solution la plus simple est peut-être de créer une liaison globale pour la roue de la souris. Il se déclenchera alors quel que soit le widget sous la souris ou quel widget a le focus clavier. Vous pouvez ensuite faire défiler la toile sans condition, ou vous pouvez être intelligent et déterminer laquelle de vos fenêtres doit défiler.

Par exemple, sur Windows, vous feriez quelque chose comme ceci:

self.canvas = Canvas(...)
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
...
def _on_mousewheel(self, event):
    self.canvas.yview_scroll(-1*(event.delta/120), "units")

Notez que self.canvas.bind_all est un peu trompeur - vous devriez plus correctement appeler root.bind_all mais je ne sais pas quoi ni comment vous définissez votre fenêtre racine. Quoi qu'il en soit, les deux appels sont synonymes.

Différences de plate-forme:

  • Sous Windows, vous vous liez à <MouseWheel> et vous devez diviser event.delta par 120 (ou un autre facteur selon la vitesse à laquelle vous souhaitez faire défiler)
  • sous OSX, vous vous liez à <MouseWheel> et vous devez utiliser event.delta sans modification
  • sur les systèmes X11, vous devez vous lier à <Button-4> et <Button-5>, et vous devez diviser event.delta par 120 (ou un autre facteur selon la vitesse à laquelle vous souhaitez faire défiler)

Il existe des solutions plus raffinées impliquant des événements virtuels et déterminant quelle fenêtre a le focus ou se trouve sous la souris, ou en passant la référence de la fenêtre de canevas à travers la liaison, mais j'espère que cela vous aidera à démarrer.

47
Bryan Oakley

Sur la base de la réponse de @ BryanOakley, voici un moyen de faire défiler uniquement le widget focalisé (c'est-à-dire celui sur lequel vous avez actuellement le curseur de la souris).

Lier à <Enter> et <Leave> événements se produisant sur votre cadre défilant qui se trouve à l'intérieur d'un canevas, de la manière suivante (scrollframe est le cadre qui se trouve à l'intérieur du canevas):

    ....

    self.scrollframe.bind('<Enter>', self._bound_to_mousewheel)
    self.scrollframe.bind('<Leave>', self._unbound_to_mousewheel)

    return

def _bound_to_mousewheel(self, event):
    self.canv.bind_all("<MouseWheel>", self._on_mousewheel)   

def _unbound_to_mousewheel(self, event):
    self.canv.unbind_all("<MouseWheel>") 

def _on_mousewheel(self, event):
    self.canv.yview_scroll(int(-1*(event.delta/120)), "units")
13
Mikhail T.

Pour se débarrasser du facteur étrange 120, nous pourrions simplement regarder le signe de la valeur event.delta. Cela facilite l'utilisation du même gestionnaire sous Windows, Linux et Mac OS.

# Mouse wheel handler for Mac, Windows and Linux
# Windows, Mac: Binding to <MouseWheel> is being used
# Linux: Binding to <Button-4> and <Button-5> is being used

def MouseWheelHandler(event):
    global count

    def delta(event):
        if event.num == 5 or event.delta < 0:
            return -1 
        return 1 

    count += delta(event)
    print(count)

import tkinter
root = tkinter.Tk()
count = 0
root.bind("<MouseWheel>",MouseWheelHandler)
root.bind("<Button-4>",MouseWheelHandler)
root.bind("<Button-5>",MouseWheelHandler)
root.mainloop()
8
Marvo

Ce lien vous donne un exemple d'utilisation de la molette de défilement.

http://www.daniweb.com/software-development/python/code/217059/using-the-mouse-wheel-with-tkinter-python

J'espère que ça aide!

# explore the mouse wheel with the Tkinter GUI toolkit
# Windows and Linux generate different events
# tested with Python25
import Tkinter as tk
def mouse_wheel(event):
    global count
    # respond to Linux or Windows wheel event
    if event.num == 5 or event.delta == -120:
        count -= 1
    if event.num == 4 or event.delta == 120:
        count += 1
    label['text'] = count
count = 0
root = tk.Tk()
root.title('turn mouse wheel')
root['bg'] = 'darkgreen'
# with Windows OS
root.bind("<MouseWheel>", mouse_wheel)
# with Linux OS
root.bind("<Button-4>", mouse_wheel)
root.bind("<Button-5>", mouse_wheel)
label = tk.Label(root, font=('courier', 18, 'bold'), width=10)
label.pack(padx=40, pady=40)
root.mainloop()
8
Joe Michail

Si vous êtes intéressé

Comment faire défiler 2 listbox en même temps

#listbox scrollbar

from tkinter import *
root = Tk()

def scrolllistbox2(event):
    listbox2.yview_scroll(int(-1*(event.delta/120)), "units")


scrollbar = Scrollbar(root)
#scrollbar.pack(side=RIGHT, fill=Y)
listbox = Listbox(root)
listbox.pack()
for i in range(100):
    listbox.insert(END, i)
# attach listbox to scrollbar
listbox.config(yscrollcommand=scrollbar.set)
listbox.bind("<MouseWheel>", scrolllistbox2)

listbox2 = Listbox(root)
listbox2.pack()
for i in range(100):
    listbox2.insert(END, i+100)
listbox2.config(yscrollcommand=scrollbar.set)

#scrollbar.config(command=listbox.yview)

root.mainloop()
1
Giovanni Python