我一直在尝试制作一个程序,根据窗口的宽度有 3 种布局(使用 Tkinter)。
问题在于中等布局。每当我将鼠标放在左侧画布上并使用 MouseWheel 时,右侧画布就会滚动,而左侧画布应该滚动。当我的鼠标放在右侧画布上并使用鼠标滚轮时,右侧画布会滚动。我找不到任何解决方案。
import tkinter as tk
from tkinter import ttk
import random as rand
class App(tk.Tk):
def init(self, Geometry, Icon, MinimumSizesDictionary):
super().init()
self.title("Practise")
self.geometry(f"{Geometry[0]}x{Geometry[1]}")
self.minsize(Geometry[0], Geometry[1])
self.iconbitmap(Icon)
# variables
self.MinimumSizesDictionary = MinimumSizesDictionary
# widgets
self.LayoutNSizeChecker = LayoutNSizeChecker(self, self.MinimumSizesDictionary)
# run
self.mainloop()
class LayoutNSizeChecker(ttk.Frame):
def __init__(self, Parent, MinimumSizesDictionary):
super ().__init__(Parent)
self.pack(expand = True, fill = "both")
self.MinimumSizesDictionary = MinimumSizesDictionary
self.MinimumSize = self.CurrentMinimumSize = None
self.Layout = None
# binding an event to the main frame
self.bind("<Configure>", lambda event : self.Update())
# binding an event to the window
Parent.bind("<Configure>", lambda event : self.CheckScreenSize(event, Parent))
def CheckScreenSize(self, event, Window):
if event.widget == Window:
for Key, Value in self.MinimumSizesDictionary.items():
self.Delta = event.width - Key
if self.Delta >= 0: self.MinimumSize = Key
if self.CurrentMinimumSize != self.MinimumSize:
self.CurrentMinimumSize = self.MinimumSize
if self.CurrentMinimumSize == 300:
for Widget in self.winfo_children():
Widget.destroy()
self.Destroyed = True
print("small layout")
self.Layout = "Small"
# variables
self.NumberOfButtons = 20
self.SpaceEachRowTakes = 100
self.TotalHeight = self.NumberOfButtons * self.SpaceEachRowTakes
# canvas
self.Canvas = tk.Canvas(self, scrollregion = (0, 0, self.winfo_width(), self.TotalHeight))
self.Canvas.pack(expand = True, fill = "both")
# canvas frame
self.CanvasFrame = ttk.Frame(self)
# scroll bar
self.ScrollBar = ttk.Scrollbar(self, orient = "vertical", command = self.Canvas.yview)
self.ScrollBar.place(relx = 1, rely = 0, relheight = 1, anchor = "ne")
self.Canvas.config(yscrollcommand = self.ScrollBar.set)
# scroll using the mousewheel
self.Canvas.bind_all("<MouseWheel>", lambda event : self.Scroll(event))
for i in range(1, 21):
self.FramePortion = ttk.Frame(self.CanvasFrame)
# variables
self.TextData = ["hello!", "goodbye!", "cya", "innit", "lol", "xd", "alr", "bro", "dude", "wsg"]
# making the grid
self.FramePortion.rowconfigure(0, weight = 1, uniform = "z")
self.FramePortion.columnconfigure((0, 1, 2), weight = 1, uniform = "z")
# the widgets
self.Button1 = ttk.Button(self.FramePortion, text = i)
self.Button2 = ttk.Button(self.FramePortion, text = rand.choice(self.TextData))
self.Button3 = ttk.Button(self.FramePortion, text = rand.choice(self.TextData))
# placing the widgets onto the grid we created earlier
self.Button1.grid(row = 0, column = 0, sticky = "nesw", padx = 5, pady = 5)
self.Button2.grid(row = 0, column = 1, sticky = "nesw", padx = 5, pady = 5)
self.Button3.grid(row = 0, column = 2, sticky = "nesw", padx = 5, pady = 5)
self.FramePortion.pack(expand = True, fill = "both")
self.Destroyed = False
elif self.CurrentMinimumSize == 600:
print("medium layout")
self.Layout = "Medium"
for Widget in self.winfo_children():
Widget.destroy()
self.Destroyed = True
# grid for main frame
self.rowconfigure(0, weight = 1, uniform = "z")
self.columnconfigure((0, 2), weight = 6, uniform = "z")
self.columnconfigure((1, 3), weight = 1, uniform = "z")
# left side layout
self.LeftFrame = ttk.Frame(self)
self.LeftFrame.grid(row = 0, column = 0, sticky = "nesw")
self.LeftCanvas = tk.Canvas(self.LeftFrame, scrollregion = (0, 0, self.LeftFrame.winfo_width(), self.TotalHeight / 2))
self.LeftCanvas.pack(side = "left", pady = 10, expand = True, fill = "both")
self.LeftCanvasFrame = ttk.Frame(self.LeftCanvas)
# scroll bar
self.LeftScrollBar = ttk.Scrollbar(self, orient = "vertical", command = self.LeftCanvas.yview)
self.LeftScrollBar.grid(row = 0, column = 1, sticky = "ns")
self.LeftCanvas.config(yscrollcommand = self.LeftScrollBar.set)
# scroll using the mouse wheel
self.LeftCanvas.bind_all("<MouseWheel>", lambda event : self.LeftScroll(event))
#
for i in range(1, 11):
self.LeftFramePortion = ttk.Frame(self.LeftCanvasFrame)
self.Button4 = ttk.Button(self.LeftFramePortion, text = i)
self.Button5 = ttk.Button(self.LeftFramePortion, text = rand.choice(self.TextData))
self.Button6 = ttk.Button(self.LeftFramePortion, text = rand.choice(self.TextData))
self.Button4.pack(expand = True, fill = "both", padx = 2.5, pady = 2.5)
self.Button5.pack(expand = True, fill = "both", padx = 2.5, pady = 2.5)
self.Button6.pack(expand = True, fill = "both", padx = 2.5, pady = 2.5)
self.LeftFramePortion.pack(expand = True, fill = "both")
# right side layout
self.RightFrame = ttk.Frame(self)
self.RightFrame.grid(row = 0, column = 2, sticky = "nesw")
self.RightCanvas = tk.Canvas(self.RightFrame, scrollregion=(0, 0, self.RightFrame.winfo_width(), self.TotalHeight / 2))
self.RightCanvas.pack(side = "left", pady = 10, expand = True, fill = "both")
self.RightCanvasFrame = ttk.Frame(self.RightCanvas)
# scroll bar
self.RightScrollBar = ttk.Scrollbar(self, orient = "vertical", command = self.RightCanvas.yview)
self.RightScrollBar.grid(row = 0, column = 3, sticky = "ns")
self.RightCanvas.config(yscrollcommand = self.RightScrollBar.set)
# scroll using the mouse wheel
self.RightCanvas.bind_all("<MouseWheel>", lambda event : self.RightScroll(event))
for i in range(11, 21):
self.RightFramePortion = ttk.Frame(self.RightCanvasFrame)
self.Button7 = ttk.Button(self.RightFramePortion, text = i)
self.Button8 = ttk.Button(self.RightFramePortion, text = rand.choice(self.TextData))
self.Button9 = ttk.Button(self.RightFramePortion, text = rand.choice(self.TextData))
self.Button7.pack(expand = True, fill = "both", padx = 2.5, pady = 2.5)
self.Button8.pack(expand = True, fill = "both", padx = 2.5, pady = 2.5)
self.Button9.pack(expand = True, fill = "both", padx = 2.5, pady = 2.5)
self.RightFramePortion.pack(expand = True, fill = "both")
self.Destroyed = False
elif self.CurrentMinimumSize == 1000:
print("large layout")
self.Layout = "Large"
for Widget in self.winfo_children():
Widget.destroy()
self.Destroyed = True
def Update(self):
if not self.Destroyed and self.Layout == "Small":
self.Canvas.create_window(
(0, 0),
anchor = "nw",
window = self.CanvasFrame,
width = self.winfo_width(),
height = self.TotalHeight
)
elif not self.Destroyed and self.Layout == "Medium":
self.LeftCanvas.create_window(
(0, 0),
anchor = "nw",
window = self.LeftCanvasFrame,
width = self.LeftFrame.winfo_width(),
height = self.TotalHeight / 2
)
self.RightCanvas.create_window(
(0, 0),
anchor = "nw",
window = self.RightCanvasFrame,
width = self.RightFrame.winfo_width(),
height = self.TotalHeight / 2
)
def Scroll(self, event):
if not self.Destroyed and self.Layout == "Small":
self.Canvas.yview_scroll(-int(event.delta / 60), "units")
def LeftScroll(self, event): # left scroll bar function for medium layout
self.LeftCanvas.yview_scroll(-int(event.delta / 60), "units")
def RightScroll(self, event): # right scroll bar function for medium layout
self.RightCanvas.yview_scroll(-int(event.delta / 60), "units")
App = App([300, 300], "icon.ico", {300 : "Small", 600 : "Medium", 1000 : "Large"})
一如既往,在中等布局中,每当我使用鼠标滚轮时,无论如何它都会滚动右侧画布。
问题在于使用的是
bind_all
将
<MouseWheel>
事件绑定到
LeftScroll
和
RightScroll
方法。这意味着无论鼠标指针位于何处,都会触发这些绑定,导致右侧画布始终滚动。
要解决此问题,应该使用
bind
而不是
bind_all
,并将事件绑定到特定的画布。这将确保仅当鼠标指针位于相应的画布上方时,才会触发滚动事件。
以下是如何修改代码的方法:
# ... 其他代码 ...
# scroll using the mouse wheel
self.LeftCanvas.bind("<MouseWheel>", self.LeftScroll)
# ... 其他代码 ...
# scroll using the mouse wheel
self.RightCanvas.bind("<MouseWheel>", self.RightScroll)
# ... 其他代码 ...
通过将
bind_all
替换为
bind
,将滚动事件绑定到特定的画布,从而解决了问题并确保只有当鼠标位于目标画布上方时才会滚动。