【问题标题】:Bind mousewheel to two canvas but only one works将鼠标滚轮绑定到两个画布但只有一个有效
【发布时间】:2018-05-25 11:21:37
【问题描述】:

我尝试将鼠标滚轮绑定到两个框架中的滚动画布。但我做不到!仅在一帧中鼠标滚轮被正确绑定。

我在哪里犯错了?给每个,让我称之为 CustomWidget 并自己绑定到 MouseWheel 不是很常见吗?

我必须以任何方式解除绑定吗?如果是,我怎样才能将它与我的“MyFirstGUI”类解除绑定?我很难找到合适的“自我”。

绑定通常适用于一个类。如果我在窗口中显示 SystemsGUI 时滚动鼠标滚轮,则 MainGUI 会滚动。

这是我的代码的摘录:

from tkinter import *
import tkinter.ttk as ttk

class MyFirstGUI(object):
    def __init__(self, master):
        self.master = master

        self.gui_control = ttk.Notebook(master)

        self.main_gui = ttk.Frame(self.gui_control, borderwidth=0) 
        self.systems_gui = ttk.Frame(self.gui_control, borderwidth=0)

        self.gui_control.add(self.main_gui, text='Main') 
        self.gui_control.add(self.systems_gui, text='Systems')

        self.gui_control.grid(column=1,row=1, columnspan=9, rowspan=50,sticky=N+E+S+W)  

        self.test_1 = Main.MainFrame(self.main_gui)
        self.test_1.grid(row=0, column=0, sticky="NESW") 

        self.test_2 = Systems.SystemFrame(self.systems_gui)
        self.test_2.grid(row=0, column=0, sticky="NESW") 

        #[...]

master.mainloop()

主界面:

class MainFrame(tk.Frame):    

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)        

        self.main_canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0)
        self.main_canvas.grid(row=0,column=0, sticky="NESW")  

        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.main_canvas.yview)
        self.vsb.grid(row=0,column=1, sticky="NS") 

        self.main_canvas.bind_all("<MouseWheel>", self._on_mousewheel)

    def _on_mousewheel(self, event):
        self.main_canvas.yview_scroll(int(-1*(event.delta/120)), "units")

    #[...]

系统 GUI(基本相同):

class SystemFrame(tk.Frame):    

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)        

        self.system_canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0)
        self.system_canvas.grid(row=0,column=0, sticky="NESW")  

        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.system_canvas.yview)
        self.vsb.grid(row=0,column=1, sticky="NS") 

        self.system_canvas.bind_all("<MouseWheel>", self._on_mousewheel)

    def _on_mousewheel(self, event):
        self.system_canvas.yview_scroll(int(-1*(event.delta/120)), "units")

    #[...]

【问题讨论】:

  • 你不应该使用bind_all,bind 在你想要的小部件的实例中工作,bind_class 在类的所有实例上工作,bind_all 在你的任何地方都工作应用
  • 感谢您的回答。不幸的是,当我使用 bind_class 时,两个画布都不会滚动了。
  • 我特别告诉你,你应该使用bind 我把其余的放在那里解释为什么它们不同。
  • 为什么要定义 2 个相同的类?您应该定义 1 个类,并创建它的 2 个实例。
  • 与绑定结果相同。仅当我使用 bind_all 时才有效。我不明白。任何地方都必须有另一个错误。

标签: python python-3.x class tkinter widget


【解决方案1】:

这是一个使用您的代码的完整示例:

import tkinter as tk
import tkinter.ttk as ttk

class MainFrame(tk.Frame):    

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)        

        self.main_canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0)
        self.main_canvas.grid(row=0,column=0, sticky="NESW")  

        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.main_canvas.yview)
        self.vsb.grid(row=0,column=1, sticky="NS") 

        # must configure canvas to update scrollbar when scrolled
        self.main_canvas.configure(yscrollcommand=self.vsb.set)

        # add some content so can see scrolling
        self.main_canvas.create_line(0,0,200,500, fill='red')

        # tell canvas the scrollable region (used bbox(tk.ALL) to get everything)
        self.main_canvas.configure(scrollregion=self.main_canvas.bbox(tk.ALL))

        self.main_canvas.bind("<MouseWheel>", self._on_mousewheel)
        self.main_canvas.bind("<Button-4>", self._onmousewheel)
        self.main_canvas.bind("<Button-5>", self._onmousewheel)

    def _on_mousewheel(self, event):
        if event.num == 4 or event.delta == 120:
            self.main_canvas.yview_scroll(-1, "units")
        elif event.num == 5 or event.delta == -120:
            self.main_canvas.yview_scroll(1, "units")

class SystemFrame(tk.Frame):    

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)        

        self.system_canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0)
        self.system_canvas.grid(row=0,column=0, sticky="NESW")  

        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.system_canvas.yview)
        self.vsb.grid(row=0,column=1, sticky="NS") 

        self.system_canvas.configure(yscrollcommand=self.vsb.set)

        self.system_canvas.create_line(0,0,200,500, fill='red')
        self.system_canvas.configure(scrollregion=self.system_canvas.bbox(tk.ALL))

        self.system_canvas.bind("<MouseWheel>", self._on_mousewheel)
        self.system_canvas.bind("<Button-4>", self._onmousewheel)
        self.system_canvas.bind("<Button-5>", self._onmousewheel)

    def _on_mousewheel(self, event):
        if event.num == 4 or event.delta == 120:
            self.system_canvas.yview_scroll(-1, "units")
        elif event.num == 5 or event.delta == -120:
            self.system_canvas.yview_scroll(1, "units")

class MyFirstGUI(object):
    def __init__(self, master):
        self.master = master

        self.gui_control = ttk.Notebook(master)

        self.main_gui = ttk.Frame(self.gui_control, borderwidth=0) 
        self.systems_gui = ttk.Frame(self.gui_control, borderwidth=0)

        self.gui_control.add(self.main_gui, text='Main') 
        self.gui_control.add(self.systems_gui, text='Systems')

        self.gui_control.grid(column=1,row=1, columnspan=9, rowspan=50,sticky=tk.N+tk.E+tk.S+tk.W)  

        self.test_1 = MainFrame(self.main_gui)
        self.test_1.grid(row=0, column=0, sticky="NESW") 

        self.test_2 = SystemFrame(self.systems_gui)
        self.test_2.grid(row=0, column=0, sticky="NESW") 

master = tk.Tk()
gui = MyFirstGUI(master)
master.mainloop()

请注意,我添加了调用来告诉画布更新滚动条(您只告诉滚动条更新画布) 我还添加了一个调用,告诉画布哪个区域是可滚动的,如果您进行任何更改/添加更改您想要可见的区域的小部件,您需要再次更新它(每次内部内容更改大小时) 我还添加了一些内容,以便您可以看到滚动

【讨论】:

  • 对我来说看起来不错,但我无法正确测试它,因为我运行的 Linux 不支持&lt;MouseWheel&gt;,我们必须使用&lt;Button-4&gt; 和&lt;Button-5&gt;。
  • 您最终是在寻找可滚动的框架吗?如果是这样,我可以为您省点麻烦:github.com/JamesGKent/python-tkwidgets/blob/master/…
  • ahhh 这很简单,在编写 python 模块时,您可以控制导出哪些名称,如果 __all__ 字典不存在,则所有名称都可用于导出,如果存在则仅字典中的名称可以导出/导入到您的脚本中
  • 你真的把它当作任何其他框架,所以:root = tk.Tk();f=ScrolledFrame(root);f.pack();for i in range(0, 100):tk.Label(f, text=str(i)).grid(column=1, row=i);root.mainloop()
  • 因为画布通常没有任何类型的边框,你需要设置粗细和样式,你还需要添加像relief='sunken'这样的东西,因为它是如何写的框架将始终覆盖整个画布内部,因此更改的背景颜色将被框架隐藏
猜你喜欢
  • 1970-01-01
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多