简体   繁体   English

tkinter canvas 带鼠标滚轮

[英]tkinter canvas with mousewheel

I'm trying to make a canvas scrollable with a mousewheel.我正在尝试使用鼠标滚轮使 canvas 可滚动。 I tried this to see if I could at least print something with the action of the mousewheel:我试过这个看看我是否至少可以通过鼠标滚轮的动作打印一些东西:

from tkinter import *
from tkinter import ttk
import platform

class MainWindow:
    def __init__(self):
        self.metrics = []
        self.content = ttk.Frame(root)
        self.content.grid_rowconfigure(0, weight = 1)
        self.content.grid_columnconfigure(0, weight = 1)
        self.scrollable_canvas = Canvas(self.content)
        self.vscrollbar = ttk.Scrollbar(self.content, orient = VERTICAL, command = self.scrollable_canvas.yview)
        self.hscrollbar = ttk.Scrollbar(self.content, orient = HORIZONTAL, command = self.scrollable_canvas.xview)
        self.scrollable_canvas.configure(yscrollcommand=self.vscrollbar.set, xscrollcommand = self.hscrollbar.set)
        self.scrollable_canvas.bind('<Configure>',
            lambda e: self.scrollable_canvas.configure(scrollregion = self.scrollable_canvas.bbox("all")))
        self.inner_frame = Frame(self.scrollable_canvas)
        self.scrollable_canvas.create_window((0, 0), window = self.inner_frame, anchor = "nw", width = 1000)

        self.scrollable_canvas.xview_moveto(0)
        self.scrollable_canvas.yview_moveto(0)

        self.class_label = Label(self.inner_frame, text = "labels")

        self.A_label = Label(self.inner_frame, text = "A")
        self.A_entry = Entry(self.inner_frame, width = 5)
        self.A_input = self.A_entry.get()
        self.A_hint = Label(self.inner_frame, text = "A")

        self.B_label = Label(self.inner_frame, text = "B")
        self.B_entry = Entry(self.inner_frame, width = 5)
        self.B_input = self.B_entry.get()
        self.B_hint = Label(self.inner_frame, text = "B")

        self.C = Label(self.inner_frame, text = "C")

        self.space = Label(self.inner_frame, text = "")

        self.D_label = Label(self.inner_frame, text = "D")
        self.D_entry = Entry(self.inner_frame, width = 5)
        self.D_hint = Label(self.inner_frame, text = "D")

        self.E_label = Label(self.inner_frame, text = "E")
        self.E_entry = Entry(self.inner_frame, width = 5)
        self.E_hint = Label(self.inner_frame, text = "D")

        self.F_label = Label(self.inner_frame, text = "F")
        self.F_entry = Entry(self.inner_frame, width = 5)
        self.F_hint = Label(self.inner_frame, text = "F")

        self.G_label = Label(self.inner_frame, text = "G")
        self.G_entry = Entry(self.inner_frame, width = 5)
        self.G_hint = Label(self.inner_frame, text = "G")

        self.H_label = Label(self.inner_frame, text = "H")
        self.H_entry = Entry(self.inner_frame, width = 5)
        self.H_hint = Label(self.inner_frame, text = "H")

        self.I_label = Label(self.inner_frame, text = "I")
        self.I_entry = Entry(self.inner_frame, width = 5)
        self.I_hint = Label(self.inner_frame, text = "I")

        self.J_label = Label(self.inner_frame, text = "J")
        self.J_entry = Entry(self.inner_frame, width = 5)
        self.J_hint = Label(self.inner_frame, text = "J")

        self.K_label = Label(self.inner_frame, text = "K")
        self.K_entry = Entry(self.inner_frame, width = 5)
        self.K_hint = Label(self.inner_frame, text = "K")

        self.space2 = Label(self.inner_frame, text = "")

        self.L_label = Label(self.inner_frame, text = "L")
        self.L_entry = Entry(self.inner_frame, width = 5)

        self.content.pack(fill = BOTH, expand = 1)

        self.scrollable_canvas.grid(row = 0, column = 0, sticky = "nsew")
        self.vscrollbar.grid(row = 0, column = 1, sticky = "ns")
        self.hscrollbar.grid(row = 1, column = 0, sticky = "ew")

        self.class_label.grid(row = 0, column = 0)

        self.A_label.grid(row = 1, column = 0)
        self.A_entry.grid(row = 1, column = 1)
        self.A_hint.grid(row = 1, column = 3, sticky = "w")

        self.B_label.grid(row = 2, column = 0)
        self.B_entry.grid(row = 2, column = 1)
        self.B_hint.grid(row = 2, column = 3, sticky = "w")

        self.C.grid(row = 3, column = 3, sticky = "w")

        self.space.grid(row = 4, column = 0)

        self.D_label.grid(row = 6, column = 0)
        self.D_entry.grid(row = 6, column = 1)
        self.D_hint.grid(row = 6, column = 3, sticky = "w")

        self.E_label.grid(row = 7, column = 0)
        self.E_entry.grid(row = 7, column = 1)
        self.E_hint.grid(row = 7, column = 3, sticky = "w")

        self.F_label.grid(row = 8, column = 0)
        self.F_entry.grid(row = 8, column = 1)
        self.F_hint.grid(row = 8, column = 3, sticky = "w")

        self.G_label.grid(row = 9, column = 0)
        self.G_entry.grid(row = 9, column = 1)
        self.G_hint.grid(row = 9, column = 3, sticky = "w")

        self.H_label.grid(row = 10, column = 0)
        self.H_entry.grid(row = 10, column = 1)
        self.H_hint.grid(row = 10, column = 3, sticky = "w", columnspan = 2)

        self.I_label.grid(row = 11, column = 0)
        self.I_entry.grid(row = 11, column = 1)
        self.I_hint.grid(row = 11, column = 3, sticky = "w", columnspan = 2)

        self.J_label.grid(row = 12, column = 0)
        self.J_entry.grid(row = 12, column = 1)
        self.J_hint.grid(row = 12, column = 3, sticky = "w", columnspan = 2)

        self.K_label.grid(row = 13, column = 0)
        self.K_entry.grid(row = 13, column = 1)
        self.K_hint.grid(row = 13, column = 3, sticky = "w", columnspan = 2)

        self.space2.grid(row = 14, column = 0)

        self.L_label.grid(row = 19, column = 0)
        self.L_entry.grid(row = 19, column = 1)

        root.mainloop()

def mouse_wheel(event):
    print("test mouse wheel event")
    global count
    if event.num == 5 or event.delta < 0:
        count -= 1
    if event.num == 4 or event.delta > 0:
        count += 1
    print(count)

if __name__ == '__main__':
    root = Tk()
    count = 0
    if platform.system() == "Windows":
        print("line 276")
        root.bind("<MouseWheel>", mouse_wheel)
        print("line 278")
    else:
        print("line 280")
        root.bind("<Button-4>", mouse_wheel)
        print("line 282")
        root.bind("<Button-5>", mouse_wheel)
        print("line 284")
    root.title("title")
    new_window = MainWindow()

However, the function mouse_weel is never called.但是,永远不会调用 function mouse_weel How come I get "line 280", "line 282" and "line 284" but not "test mouse wheel event".为什么我得到“第 280 行”、“第 282 行”和“第 284 行”而不是“测试鼠标滚轮事件”。

I can get the mouse wheel to work with a non-OO program.我可以让鼠标滚轮与非 OO 程序一起使用。

I found this solution but couldn't adapt it to my problem.我找到了这个解决方案,但无法适应我的问题。

Here is the solution I found:这是我找到的解决方案:

from tkinter import *
from tkinter import ttk
import platform

class MainWindow:
    def __init__(self):
        self.metrics = []
        self.content = ttk.Frame(root)
        self.content.grid_rowconfigure(0, weight = 1)
        self.content.grid_columnconfigure(0, weight = 1)
        self.scrollable_canvas = Canvas(self.content)
        self.vscrollbar = ttk.Scrollbar(self.content, orient = VERTICAL, command = self.scrollable_canvas.yview)
        self.hscrollbar = ttk.Scrollbar(self.content, orient = HORIZONTAL, command = self.scrollable_canvas.xview)

        self.scrollable_canvas.configure(yscrollcommand=self.vscrollbar.set, xscrollcommand = self.hscrollbar.set)
        self.scrollable_canvas.bind('<Configure>',
            lambda e: self.scrollable_canvas.configure(scrollregion = self.scrollable_canvas.bbox("all")))
        self.inner_frame = Frame(self.scrollable_canvas)
        self.scrollable_canvas.create_window((0, 0), window = self.inner_frame, anchor = "nw", width = 1000)

        self.scrollable_canvas.xview_moveto(0)
        self.scrollable_canvas.yview_moveto(0)

        if platform.system() == "Linux":
            self.inner_frame.bind("<Button-4>", self.mouse_wheel)
            self.inner_frame.bind("<Button-5>", self.mouse_wheel)
        else:
            self.inner_frame.bind("<MouseWheel>", self.mouse_wheel)

        self.class_label = Label(self.inner_frame, text = "labels")

        self.A_label = Label(self.inner_frame, text = "A")
        self.A_entry = Entry(self.inner_frame, width = 5)
        self.A_input = self.A_entry.get()
        self.A_hint = Label(self.inner_frame, text = "A")

        self.B_label = Label(self.inner_frame, text = "B")
        self.B_entry = Entry(self.inner_frame, width = 5)
        self.B_input = self.B_entry.get()
        self.B_hint = Label(self.inner_frame, text = "B")

        self.C = Label(self.inner_frame, text = "C")

        self.space = Label(self.inner_frame, text = "")

        self.D_label = Label(self.inner_frame, text = "D")
        self.D_entry = Entry(self.inner_frame, width = 5)
        self.D_hint = Label(self.inner_frame, text = "D")

        self.E_label = Label(self.inner_frame, text = "E")
        self.E_entry = Entry(self.inner_frame, width = 5)
        self.E_hint = Label(self.inner_frame, text = "D")

        self.F_label = Label(self.inner_frame, text = "F")
        self.F_entry = Entry(self.inner_frame, width = 5)
        self.F_hint = Label(self.inner_frame, text = "F")

        self.G_label = Label(self.inner_frame, text = "G")
        self.G_entry = Entry(self.inner_frame, width = 5)
        self.G_hint = Label(self.inner_frame, text = "G")

        self.H_label = Label(self.inner_frame, text = "H")
        self.H_entry = Entry(self.inner_frame, width = 5)
        self.H_hint = Label(self.inner_frame, text = "H")

        self.I_label = Label(self.inner_frame, text = "I")
        self.I_entry = Entry(self.inner_frame, width = 5)
        self.I_hint = Label(self.inner_frame, text = "I")

        self.J_label = Label(self.inner_frame, text = "J")
        self.J_entry = Entry(self.inner_frame, width = 5)
        self.J_hint = Label(self.inner_frame, text = "J")

        self.K_label = Label(self.inner_frame, text = "K")
        self.K_entry = Entry(self.inner_frame, width = 5)
        self.K_hint = Label(self.inner_frame, text = "K")

        self.space2 = Label(self.inner_frame, text = "")

        self.L_label = Label(self.inner_frame, text = "L")
        self.L_entry = Entry(self.inner_frame, width = 5)

        self.content.pack(fill = BOTH, expand = 1)

        self.scrollable_canvas.grid(row = 0, column = 0, sticky = "nsew")
        self.vscrollbar.grid(row = 0, column = 1, sticky = "ns")
        self.hscrollbar.grid(row = 1, column = 0, sticky = "ew")

        self.class_label.grid(row = 0, column = 0)

        self.A_label.grid(row = 1, column = 0)
        self.A_entry.grid(row = 1, column = 1)
        self.A_hint.grid(row = 1, column = 3, sticky = "w")

        self.B_label.grid(row = 2, column = 0)
        self.B_entry.grid(row = 2, column = 1)
        self.B_hint.grid(row = 2, column = 3, sticky = "w")

        self.C.grid(row = 3, column = 3, sticky = "w")

        self.space.grid(row = 4, column = 0)

        self.D_label.grid(row = 6, column = 0)
        self.D_entry.grid(row = 6, column = 1)
        self.D_hint.grid(row = 6, column = 3, sticky = "w")

        self.E_label.grid(row = 7, column = 0)
        self.E_entry.grid(row = 7, column = 1)
        self.E_hint.grid(row = 7, column = 3, sticky = "w")

        self.F_label.grid(row = 8, column = 0)
        self.F_entry.grid(row = 8, column = 1)
        self.F_hint.grid(row = 8, column = 3, sticky = "w")

        self.G_label.grid(row = 9, column = 0)
        self.G_entry.grid(row = 9, column = 1)
        self.G_hint.grid(row = 9, column = 3, sticky = "w")

        self.H_label.grid(row = 10, column = 0)
        self.H_entry.grid(row = 10, column = 1)
        self.H_hint.grid(row = 10, column = 3, sticky = "w", columnspan = 2)

        self.I_label.grid(row = 11, column = 0)
        self.I_entry.grid(row = 11, column = 1)
        self.I_hint.grid(row = 11, column = 3, sticky = "w", columnspan = 2)

        self.J_label.grid(row = 12, column = 0)
        self.J_entry.grid(row = 12, column = 1)
        self.J_hint.grid(row = 12, column = 3, sticky = "w", columnspan = 2)

        self.K_label.grid(row = 13, column = 0)
        self.K_entry.grid(row = 13, column = 1)
        self.K_hint.grid(row = 13, column = 3, sticky = "w", columnspan = 2)

        self.space2.grid(row = 14, column = 0)

        self.L_label.grid(row = 19, column = 0)
        self.L_entry.grid(row = 19, column = 1)

        root.mainloop()

    def mouse_wheel(self, event):
        print(str(event.delta) + " is event.delta")
        print(str(event.state) + " is event.state")
        if event.state == 1:
            self.scrollable_canvas.xview_scroll(int(-1*(event.delta)/scrollable_malus), "units")
        elif event.state == 0:
            self.scrollable_canvas.yview_scroll(int(-1*(event.delta)/scrollable_malus), "units")

if __name__ == '__main__':
    root = Tk()
    count = 0
    if platform.system() == "Windows":
        global scrollable_malus = 120
    else:
        global scrollable_malus = 1
    root.title("title")
    new_window = MainWindow()

In mouse_wheel , xview_scroll and yview_scroll were already used for the scrollbars.mouse_wheel中, xview_scrollyview_scroll已经用于滚动条。 These commands can scroll by page or unit.这些命令可以按页面或单位滚动。 In this case, I chose unit.在这种情况下,我选择了单位。

event.state is 1 when scrolling horizontally and 0 when scrolling vertically. event.state水平滚动时为1 ,垂直滚动时为0 When scrolling up, event.delta is positive but it is also positive when scrolling left so event.state is required to know the direction.向上滚动时, event.delta为正,但向左滚动时 event.delta 也为正,因此需要event.state才能知道方向。

On Windows, event.delta is a multiple of 120 so I had to create a malus that would be worth 120 on Windows.在 Windows 上, event.delta是 120 的倍数,所以我必须创建一个在 Windows 上等于 120 的 malus。

Depending on whether or not you want to invert the scrolling direction, you may want to delete the -1 multiplier.根据您是否要反转滚动方向,您可能想要删除 -1 乘数。

I both cases of mouse_wheel , I should have written:我都是mouse_wheel的情况,我应该写:

if event.num == 5 or event.delta < 0:
        self.scrollable_canvas.xview_scroll(int(-1*(event.delta)/scrollable_malus), "units")
if event.num == 4 or event.delta > 0:
        self.scrollable_canvas.xview_scroll(int(-1*(event.delta)/scrollable_malus), "units")

Since it is the same formula on both cases, I refactored it.由于这两种情况下的公式相同,因此我对其进行了重构。

I left event.delta and event.state to show the scrolling direction so that other users can use it and understand why I did what I did.我留下event.deltaevent.state来显示滚动方向,以便其他用户可以使用它并理解我为什么这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM