Python Tkinter Scrollbar:如何设置箭头按钮单次滚动像素偏移量?
自定义ScrollbarFrame滚动步长实现单行滚动
问题描述
我使用ScrollbarFrame(tk.Frame)类展示表格,希望点击滚动条的向上/向下箭头时,表格刚好滚动1行(每行高度为21像素),但目前单次点击箭头会滚动约28像素。发现点击箭头是滚动1个单位,但找不到设置单位或修改滚动长度的配置,需要解决这个问题。
原代码如下:
import tkinter as tk class ScrollbarFrame(tk.Frame): """ Extends class tk.Frame to support a scrollable Frame This class is independent from the widgets to be scrolled and can be used to replace a standard tk.Frame """ def __init__(self, parent, width=0, height=0, **kwargs): tk.Frame.__init__(self, parent, **kwargs) # The Scrollbar, layout to the right vsb = tk.Scrollbar(self, orient="vertical") vsb.pack(side="right", fill="y") # The Canvas which supports the Scrollbar Interface, layout to the left self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff") self.canvas.configure(width=width, height=height) self.canvas.pack(side="left", fill="both", expand=True) # Bind the Scrollbar to the self.canvas Scrollbar Interface self.canvas.configure(yscrollcommand=vsb.set) vsb.configure(command=self.canvas.yview) # The Frame to be scrolled, layout into the canvas # All widgets to be scrolled have to use this Frame as parent self.scrolled_frame = tk.Frame(self.canvas, background=self.canvas.cget('bg')) self.canvas.create_window((0, 0), window=self.scrolled_frame, anchor="nw") # Configures the scrollregion of the Canvas dynamically self.scrolled_frame.bind("<Configure>", self.on_configure) def on_configure(self, event): """Set the scroll region to encompass the scrolled frame""" self.canvas.configure(scrollregion=self.canvas.bbox("all"))
解决方案
方法一:设置Canvas滚动增量(推荐)
直接给Canvas设置yscrollincrement参数,指定每次滚动1单位对应的像素值为21,这样点击滚动条箭头时就会精确滚动单行高度。
修改Canvas初始化代码:
self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff", yscrollincrement=21)
方法二:自定义滚动回调(精准控制)
如果方法一不生效,可自定义滚动条的回调方法,手动控制每次滚动的像素量:
- 在
ScrollbarFrame类中添加自定义滚动方法:
def _on_scroll(self, action, delta, type=None): if action == "scroll": # delta=1向下滚动,delta=-1向上滚动,每次滚动21像素 self.canvas.yview_scroll(delta, "units") elif action == "moveto": # 处理拖动滚动条滑块的情况 self.canvas.yview_moveto(delta)
- 修改Scrollbar的
command绑定,替换为自定义方法:
vsb.configure(command=self._on_scroll)
修改后的完整代码
import tkinter as tk class ScrollbarFrame(tk.Frame): """ Extends class tk.Frame to support a scrollable Frame This class is independent from the widgets to be scrolled and can be used to replace a standard tk.Frame """ def __init__(self, parent, width=0, height=0, row_height=21, **kwargs): tk.Frame.__init__(self, parent, **kwargs) self.row_height = row_height # The Scrollbar, layout to the right vsb = tk.Scrollbar(self, orient="vertical") vsb.pack(side="right", fill="y") # The Canvas which supports the Scrollbar Interface, layout to the left self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff", yscrollincrement=self.row_height) self.canvas.configure(width=width, height=height) self.canvas.pack(side="left", fill="both", expand=True) # Bind the Scrollbar to the self.canvas Scrollbar Interface self.canvas.configure(yscrollcommand=vsb.set) # 若方法一不生效,替换为下面一行注释的代码,使用自定义滚动回调 # vsb.configure(command=self._on_scroll) vsb.configure(command=self.canvas.yview) # The Frame to be scrolled, layout into the canvas # All widgets to be scrolled have to use this Frame as parent self.scrolled_frame = tk.Frame(self.canvas, background=self.canvas.cget('bg')) self.canvas.create_window((0, 0), window=self.scrolled_frame, anchor="nw") # Configures the scrollregion of the Canvas dynamically self.scrolled_frame.bind("<Configure>", self.on_configure) def on_configure(self, event): """Set the scroll region to encompass the scrolled frame""" self.canvas.configure(scrollregion=self.canvas.bbox("all")) def _on_scroll(self, action, delta, type=None): if action == "scroll": self.canvas.yview_scroll(delta, "units") elif action == "moveto": self.canvas.yview_moveto(delta)
内容的提问来源于stack exchange,提问作者KNUT
相关产品推荐
相关产品推荐

