python - barra - tkinter scrollbar
Python tkinter enlace mousewheel to scrollbar (4)
Tengo este marco con capacidad de desplazamiento (marco dentro del lienzo en realidad).
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)
Me gustaría unir la rueda del mouse a la barra de desplazamiento para que el usuario pueda desplazarse hacia abajo en el marco sin tener que usar los botones de flecha en la barra de desplazamiento. Después de mirar alrededor, agregué un enlace a mi canvas1
como este
self.frame1.bind("<MouseWheel>", self.OnMouseWheel)
Esta es la función:
def OnMouseWheel(self,event):
self.scrollbar1.yview("scroll",event.delta,"units")
return "break"
Pero la barra de desplazamiento no se mueve cuando uso la rueda del ratón. Puede alguien ayudarme con esto? Todo lo que quiero es que cuando el usuario usa la rueda del mouse (dentro del área del marco / en la barra de desplazamiento), el lienzo se desplace hacia arriba o hacia abajo automáticamente.
Este enlace le da un ejemplo de cómo usar la rueda de desplazamiento.
¡Espero que esto ayude!
# 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()
Para deshacernos del factor 120 extraño, solo podemos mirar el signo del valor event.delta. Esto facilita el uso del mismo controlador en Windows, Linux y 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()
Quizás la solución más simple es hacer un enlace global para la rueda del ratón. Entonces se activará sin importar qué widget esté bajo el mouse o qué widget tenga el foco del teclado. Luego puede desplazar incondicionalmente el lienzo, o puede ser inteligente y averiguar cuál de sus ventanas debe desplazarse.
Por ejemplo, en windows harías algo como esto:
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")
Tenga en cuenta que self.canvas.bind_all
es un poco engañoso: más bien debería llamar root.bind_all
pero no sé qué o cómo define su ventana raíz. En cualquier caso, las dos llamadas son sinónimos.
Diferencias de plataforma:
- En Windows, se une a
<MouseWheel>
y necesita dividirevent.delta
por 120 (o algún otro factor dependiendo de qué tan rápido quiera el desplazamiento) - en OSX, se enlaza con
<MouseWheel>
y necesita usarevent.delta
sin modificación - en los sistemas X11, debe enlazar a
<Button-4>
y<Button-5>
, y debe dividirevent.delta
por 120 (o algún otro factor dependiendo de qué tan rápido quiera desplazarse)
Hay soluciones más refinadas que involucran eventos virtuales y determinan qué ventana tiene el foco o está debajo del mouse, o pasando la referencia de la ventana del lienzo a través del enlace, pero esperamos que esto le ayude a comenzar.
Sobre la base de la respuesta de @ BryanOakley, aquí hay una forma de desplazar solo el widget enfocado (es decir, el cursor sobre el que se encuentra el cursor).
Enlazar a <Enter>
y <Leave>
eventos que ocurren en su marco desplazable que se encuentra dentro de un lienzo, de la siguiente manera (el marco de scrollframe
es el marco que está dentro del lienzo):
....
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")