2013-06-28 31 views
14

mam ten zwój-stanie ramki (ramki wewnątrz płótnie faktycznie).Python tkinter mouseWheel wiązania się pasek przewijania

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) 

chciałbym związać kółka myszy do przewijania, dzięki czemu użytkownik może przewijać ramki bez konieczności korzystania z przycisków strzałek na pasku przewijania. Po rozglądając się, dodałem wiążący do mojego canvas1 jak ten

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

Jest to funkcja:

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

Ale pasek przewijania nie ruszy, kiedy mogę używać kółka myszy. Czy ktoś może mi w tym pomóc? Wszystko, czego chcę, to gdy użytkownik używa koła myszy (w obszarze ramki/na pasku przewijania), płótno powinno automatycznie przewijać w górę lub w dół.

Odpowiedz

35

Być może najprostszym rozwiązaniem jest utworzenie globalnego powiązania dla koła myszy. Nastąpi wtedy ogień bez względu na to, który widżet znajduje się pod myszą lub który widżet jest skupiony na klawiaturze. Możesz wtedy bezwarunkowo przewijać płótno, albo możesz być sprytny i dowiedzieć się, które z okien powinno się przewijać.

Na przykład w oknach byś zrobił coś takiego:

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

Zauważ, że self.canvas.bind_all jest nieco mylący - Ci bardziej prawidłowo powinien nazywać root.bind_all ale nie wiem co i jak można zdefiniować swoje okno główne. Bez względu na to, oba połączenia są synonimami.

różnice Platforma:

  • W systemie Windows, należy wiązać <MouseWheel> i trzeba podzielić event.delta przez 120 (lub jakiś inny czynnik w zależności od tego jak szybko chcesz zwój)
  • na OSX, zwiążesz do <MouseWheel> i trzeba użyć event.delta bez modyfikacji
  • systemów X11 trzeba wiązać <Button-4> i <Button-5> i trzeba podzielić event.delta 120 (lub jakiś inny czynnik w zależności od tego, jak szybko chcesz przewinąć)

Są bardziej wyrafinowane rozwiązania obejmujące zdarzenia wirtualnych i określenia, które okno ma fokus lub jest pod mysz, lub przekazując odwołanie okno płótno poprzez wiązania, ale mam nadzieję, że będzie to dobry początek.

+0

Doskonała odpowiedź dla początkujących, takich jak ja. dzięki –

+2

Próbowałem użyć tego (Linux tutaj), ale couldnt to działa, aż zauważyłem, że - Zastanawiam się, dlaczego - event.delta było zawsze zero. Rozwiązano, nazywając po prostu yview_scroll (kierunek, "jednostki") – alessandro

+0

@Bryan Oakley - Powyższe działa dobrze, jeśli w aplikacji jest tylko jedno przewijane płótno. Ale jeśli są dwa lub więcej, w jaki sposób można ograniczyć przewijanie do jednego lub drugiego? – JDM

5

Ten link daje przykład co do sposobu korzystania z scrollwheel.

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

Mam nadzieję, że to pomoże!

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

Dobry, działający przykład. Po prostu zamień 'Tkinter' na' tkinter' na Py3 – Nils

+1

Jeśli ten link miałby spaść, odpowiedź byłaby bezużyteczna. ["Zawsze cytuj najważniejszą część ważnego linku, na wypadek, gdyby strona docelowa była nieosiągalna lub została trwale wyłączona."] (Http://stackoverflow.com/help/how-to-answer) Edytuj swoje pytanie, aby uniknąć to. – joejoe31b

0

Opierając się na @ odpowiedź BrayanOakley za mogę zaproponować udoskonalenia:

można powiązać do <Enter> i <Leave> wydarzeniach z funkcją przewijania ramki wewnątrz płótnie dwa różne owijarki następujący sposób (scrollwindow jest w moim przypadku ramce zostanie wstawiony płótnie):

.... 

    self.scrollwindow.bind('<Enter>', self._bound_to_mousewheel) 
    self.scrollwindow.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") 

Tak, tylko skoncentrowany widżet (jeden masz kursor obecnie), będzie przewijane. Możesz poprosić o wyjaśnienie:

1

Aby pozbyć się dziwnego współczynnika 120, wystarczy spojrzeć na znak wartości event.delta. Ułatwia to korzystanie z tego samego programu obsługi w systemach Windows, Linux i 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()