Python Tkinter привязка mousewheel к полосе прокрутки

у меня есть эта прокручиваемая Рамка (Рамка внутри холста на самом деле).

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)

Я хотел бы привязать колесо мыши к полосе прокрутки, чтобы пользователь мог прокручивать кадр без использования кнопок со стрелками на полосе прокрутки. Осмотревшись, я добавил привязку к своему canvas1 такой

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

это функция:

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

но полоса прокрутки не будет двигаться, когда я использую mousewheel. Кто-нибудь может мне помочь? Все, что я хочу, когда пользователь используйте mousewheel (внутри области рамки/на полосе прокрутки), холст должен автоматически прокручиваться вверх или вниз.

4 ответов


возможно, самое простое решение - сделать глобальную привязку для колесика мыши. Затем он будет стрелять независимо от того, какой виджет находится под мышью или какой виджет имеет фокус клавиатуры. Затем вы можете безоговорочно прокручивать холст, или вы можете быть умным и выяснить, какой из ваших окон должен прокручиваться.

например, в windows вы бы сделали что-то вроде этого:

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")

отметим, что self.canvas.bind_all немного вводит в заблуждение-вы более правильно следует называть root.bind_all но я не знаю, что или как вы определяете свое корневое окно. Несмотря на это, эти два вызова являются синонимами.

платформы отличия:

  • в Windows вы привязываетесь к <MouseWheel> и вам нужно разделить event.delta на 120 (или какой-то другой фактор в зависимости от того, насколько быстро вы хотите прокрутки)
  • на OSX, вы привязываетесь к <MouseWheel> и нужно использовать event.delta без изменений
  • в системах X11 вам нужно привязать к <Button-4> и <Button-5>, и вам нужно разделяй!--4--> на 120 (или какой-то другой фактор в зависимости от того, насколько быстро вы хотите прокрутки)

есть более изысканные решения, связанные с виртуальными событиями и определяющие, какое окно имеет фокус или находится под мышью, или передача ссылки на окно холста через привязку, но, надеюсь, это поможет вам начать.


эта ссылка дает пример того, как использовать колесо прокрутки.

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

надеюсь, это поможет!

# 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()

на основе ответа @BryanOakley, вот способ прокрутки только сфокусированного виджета (т. е. тот, который у вас есть курсор мыши в настоящее время).

привязать к <Enter> и <Leave> события, происходящие на вашем прокручиваемом кадре, который находится внутри холста, следующим образом (scrollframe Это рамка, которая находится внутри холста):

    ....

    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")

чтобы избавиться от странного фактора 120, мы могли бы просто посмотреть на знак события.Дельта значение. Это позволяет легко использовать один и тот же обработчик под Windows, Linux и 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()