本文旨在实现 tk.Scrollbar(ttk.Scrollbar)本身没有且实用的特性:比如 自动隐藏和显示
简单示例:
示例1 简单滚动条的实现代码
# -*- coding:utf-8 -*-# Date: 2020/3/13try: import Tkinter as tkexcept ImportError: import tkinter as tktry: import ttkexcept ImportError: import tkinter.ttk as ttk root = tk.Tk()root.geometry("200x300+500+600")hscrollbar = tk.Scrollbar(root)hscrollbar.pack(side=tk.RIGHT, fill="y")test_text = tk.Text(root, wrap=tk.NONE, yscrollcommand=hscrollbar.set)test_text.pack(side=tk.TOP, fill=tk.BOTH, expand=True)test_text.insert(tk.END, "This is tkinter or Tkinter!"*50)hscrollbar.config(command=test_text.yview)root.mainloop()
特性实现:
布局管理器grid的实现方式
实现的代码如下:
# -*- coding:utf-8 -*-try: import Tkinter as tkexcept ImportError: import tkinter as tktry: import ttkexcept ImportError: import tkinter.ttk as ttkclass AutoHideScrollbar(ttk.Scrollbar): def set(self,upper,lower): # ❶ if float(upper) <= 0.0 and float(lower) >= 1.0: self.grid_remove() # ❷ else: self.grid() ttk.Scrollbar.set(self,upper,lower) if __name__ == '__main__': root = tk.Tk() root.geometry("200x300+500+600") root.rowconfigure(0, weight=1) root.columnconfigure(0, weight=1) yscrollbar = AutoHideScrollbar(root) yscrollbar.grid(row=0, column=1, sticky=tk.N + tk.S) test_text = tk.Text(root, wrap=tk.NONE, yscrollcommand=yscrollbar.set) test_text.grid(row=0, column=0, sticky=tk.N + tk.E + tk.W + tk.S) test_text.insert(tk.END, "This is tkinter or Tkinter!"*30) yscrollbar.config(command=test_text.yview) root.mainloop()
注释❶:继承ttk.Scrollbar (tk.Scrollbar),重写覆盖父类的set()方法,实现自动隐藏滚动条。如下图所示:
滚动条可以看做一个在0到1之间从上到下的单向坐标系,upper 起始值为0,表示滚动条上方在坐标系中的值(浮点值表示);lower 表示滚动条最下方在坐标系中对应的值,最大为1。
而当upper=0,lower=1时,就表示滚动条占据了整个空间,此时就可以触发他的隐藏方法。
注释❷:需要注意的是,隐藏滚动条组件的方法是用的grid_remove(),而不能使用grid_forget()方法。
具体原因Tkinter中源码写得很清楚:
def grid_forget(self): """Unmap this widget.""" self.tk.call('grid', 'forget', self._w)forget = grid_forgetdef grid_remove(self): """Unmap this widget but remember the grid options.""" self.tk.call('grid', 'remove', self._w)
效果GIF图展示
布局管理器pack的实现方式
如果你说你就喜欢使用 pack 方法实现这个功能,那么也是可以不过麻烦了一些。因为 pack 中没有类似于 grid.remove() 这样既可以移除组件同时又保存组件的位置信息的方法(可能之后的版本会有)。
如果使用之前的思路的话,效果如下:
很显然在这里是行不通的。
两种pack实现方法
一:在旁边放置一个 tk.Frame 组件来装 滚动条组件。
# -*- coding:utf-8 -*-try: import Tkinter as tkexcept ImportError: import tkinter as tktry: import ttkexcept ImportError: import tkinter.ttk as ttkclass AutoHideScrollbar(ttk.Scrollbar): def set(self,upper,lower): if float(upper) <= 0.0 and float(lower) >= 1.0: self.pack_forget() else: self.pack(side="right", fill="y") ttk.Scrollbar.set(self,upper,lower)if __name__ == '__main__': root = tk.Tk() root.geometry("200x300+500+600") frame = tk.Frame(root) # 用于放置scrollbar组件 frame.pack(side="right", fill="y") vscrollbar = AutoHideScrollbar(frame) vscrollbar.pack(side=tk.RIGHT, fill="y") test_text = tk.Text(root, wrap=tk.NONE, yscrollcommand=vscrollbar.set) test_text.pack(fill=tk.BOTH, expand=True) vscrollbar.config(command=test_text.yview) test_text.insert(tk.END, "This is tkinter or Tkinter!"*26) root.mainloop()
二:使用canvas 组件来实现
# -*- coding:utf-8 -*-try: import Tkinter as tkexcept ImportError: import tkinter as tktry: import ttkexcept ImportError: import tkinter.ttk as ttkclass AutoHideScrollbar(ttk.Scrollbar): def set(self,upper,lower): if float(upper) <= 0.0 and float(lower) >= 1.0: self.pack_forget() else: if self.cget("orient") == tk.HORIZONTAL: self.pack(fill=tk.X, side=tk.BOTTOM) else: self.pack(fill=tk.Y, side=tk.RIGHT) ttk.Scrollbar.set(self,upper,lower) def grid(self, **kw): # raise AttributeError("{} has no attribute {}".format(AutoHideScrollbar.__name__, "'grid'")) def place(self, **kw): raise AttributeError("{} has no attribute {}".format(AutoHideScrollbar.__name__, "'place'"))if __name__ == '__main__': root = tk.Tk() vscrollbar = AutoHideScrollbar(root) canvas = tk.Canvas(root, yscrollcommand=vscrollbar.set) canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) vscrollbar.config(command=canvas.yview) frame = tk.Frame(canvas) test_text = tk.Text(frame, wrap=tk.NONE) test_text.pack(fill=tk.BOTH, expand=True) test_text.insert(tk.END, "This is tkinter or Tkinter!"*26) canvas.create_window(0, 0, anchor=tk.NW, window=frame) frame.update_idletasks() canvas.config(scrollregion=canvas.bbox("all")) root.mainloop()
使用 canvas 、canvas.create_window 来实现存在一些小问题,特别是内部使用 tk.Text 组件时。有机会再讲,毕竟和本文主题不搭。
推荐使用 grid 方式实现,如果就是要用 pack 实现的话建议使用 pack 的第一种实现方式。
结尾
有疑问欢迎留言询问
请不要转载,或者先询问我请不要转载,或者先询问我