本文介绍另一个控件Scrollbar,在tkinter-Text详解一文中有提到过Scrollbar,但是没有做过多的说明。因此本文将详解Scrollbar及其使用场景。
文章目录
- Scrollbar
- element
- orient
- activebackground
- background
- cursor
- jump
- repeatdelay
- repeatinterval
- takefocus
- command
- set()
- 什么是可滚动控件?
- scrollbar和可滚动控件的关系?
- scrollbar与可滚动控件的绑定
Scrollbar
Scrollbar 一般和其他控件联合使用,当被显示的控件的内容大于可显示区域时,使用Scrollbar可显示更多的内容。一般垂直滚动条(vertical scrollbar)和Listbox, Text and Canvas联合使用;水平滚动条(horizontal scrollbar)也可作用于Entry。
首先还是介绍Scrollbar的常用属性和方法,最后再举几个结合其他控件的实例。
element
scrollbar的5个elements
arrow1,arrow2 指滚动条两端的箭头
slider 指scrollbar中的滑块
trough1,trough2 指非slider区域,可以称为槽
可通过slider拖动来改变视图,也可点击 arrow1或arrow2来改变视图,也可点击 trough1或trough2来改变视图。所谓视图,简单讲就是滑块的位置发生了改变,相应的显示内容也跟着变化。
orient
滚动条方向属性,通常有两个值"vertical"(默认值)和"horizontal"。即垂直滚动条和水平滚动条。
# bar = Scrollbar(main_win, orient=VERTICAL)
bar = Scrollbar(main_win, orient=HORIZONTAL)
bar.pack()
activebackground
当鼠标在滑块(slider)或箭头(arrowhead)上时,显示的背景颜色。windows上实测无效。
bar = Scrollbar(main_win, activebackground='red')
bar.pack()
background
指定背景颜色。window上实测无效
bar = Scrollbar(main_win, background='red')
bar.pack()
cursor
指定光标样式
bar = Scrollbar(main_win, cursor='cross')
bar.pack()
jump
控制用户拖动滑块时发生的动作。默认(jump=0)每拖动一次滑块,就会使command指定的回调函数被调用。如果jump=1,回调函数只在用户放开鼠标按键时被调用一次,在拖动过程中不会被触发。windows上实测无效。
repeatdelay
延迟x秒移动滑块。鼠标左键按下x秒数后,滑块在某个方向开始持续移动。通常用于滚动条中的向上和向下的箭头。windows上实测无效。
repeatinterval
一旦滑块在某方向的持续移动开始,repeatinterval决定了相邻两次移动动作的时间间隔, 一般和repeatdelay联合使用。windows上实测无效。
takefocus
可以使用tab键将焦点切换到scrollbar。如果takefocus=0,那么将关闭该功能。
command
对于scrollbar非常重要的交互属性。通常用于指定可滚动控件(scrollable widget)的xview或yview函数。
因为滚动条有两种动作: ‘moveto’和’scroll’,'moveto’对应slider的拖动,'scroll’对应arrow或trough的点击。我们来看看怎样指定command对应的回调函数。
from tkinter import (Tk, Text, Scrollbar)
from tkinter.constants import (HORIZONTAL, VERTICAL, RIGHT, LEFT, X, Y, BOTH, BOTTOM, YES)
def cb():
print('first cb')
main_win = Tk()
main_win.title('渔道的Scrollbar控件')
main_win.geometry(f'{800}x{800}')
# create Scrollbar
scrollbar_v = Scrollbar(main_win)
scrollbar_v.pack(side=RIGHT, fill=Y)
scrollbar_h = Scrollbar(main_win, orient=HORIZONTAL)
scrollbar_h.pack(side=BOTTOM, fill=X)
text = Text(main_win, width=40, height=40)
text.config(yscrollcommand=scrollbar_v.set)
text.pack(expand=YES,fill=BOTH)
for i in range(1, 1000):
text.insert(f'{i}.0', f'line:{str(i)}\n')
scrollbar_v.config(command=cb)
main_win.mainloop()
运行上面的代码会出现如下界面:
当我拖动slider时,报错TypeError: cb() takes 0 positional arguments but 2 were given
当我点击arrow或trough时,报错TypeError: cb() takes 0 positional arguments but 3 were given
说明scrollbar内部在调用回调函数cb()时,会给它传递参数。拖动slider时,传递了两个参数;点击arrow或trough时,传递了三个参数。显然,要想使用一个回调函数来处理这两种事件,那么就需要给回调函数指定可变参数(即可传入2个参数也可传入3个参数),我们知道python的函数时支持这种语法的,实现起来非常容易。
可以将cb()改成如下代码:
def cb(*args):
argc = len(args)
if argc == 2:
print(f'{args[0]}, {args[1]},drag slider...')
elif argc == 3:
print(f'{args[0]}, {args[1]}, {args[2]},hit arrow...')
else:
print('invalid parameters number')
再次运行修改后的程序,
拖动slider,可以看到如下打印信息moveto, 0.0235,drag slider...
点击arrow或trough,可以看到如下打印信息scroll, 1, units,hit arrow...
通过上述实践过程,可以得到如下结论:
- 拖动slider(对应’moveto’事件)时,触发command指定的回调函数,该回调函数有2个参数cb1(action, fraction)
- 点击arrow或trough(对应’scroll’事件)时,触发command指定的回调函数,该回调函数有3个参数cb2(action,number,pages)
- 可以通过可变参数将回调函数接口统一
已知scrollbar.config(command=text.yview)支持对slider、arrow、trough的响应,为什么呢?原因就在于类XView,YView
为了接口统一,在tkinter中 创建了类XView,YView, 在YView中,定义了函数yview(*args),这样text就可以支持’moveto’和’scroll’。与我们前面定义的cb(*args)本质上是一样的。
set()
set(first, last)
设置scrollbar的slider的位置,通常作为可滚动控件的回调函数。first和last的值的范围是[0,1]的小数,first到last的区间指定了与scrollbar绑定的可滚动控件的可视内容的范围。
在tkinter-Text详解一文的给Text加上滚动条一节的实例中,细心的同学可能发现了这样一个问题:无论是拖动slider还是点击arrow1、arrow2还是点击trough1、trough2,视图都没有发生变化;但是将鼠标放在Text区域,上下滚动鼠标滚轮,发现视图发生变化而且slider也跟着变化。接下来,会细品该问题背后的原因。
什么是可滚动控件?
class Text(Widget, XView, YView)
class Listbox(Widget, XView, YView)
class Entry(Widget, XView)
class Canvas(Widget, XView, YView)
class Spinbox(Widget, XView)
Text,Listbox,Entry,Canvas,Spinbox都是可滚动控件。也就是说继承于XView和(或)YView的控件类都是可滚动控件。
scrollbar和可滚动控件的关系?
scrollbar控件不是作为其他可滚动控件的一部分,两者之间只是组合关系,而不是包含关系。
scrollbar与可滚动控件的绑定
scrollbar和可滚动控件 之间的绑定是相互的,scrollbar既要主动绑定可滚动控件的相关函数,可滚动控件也要主动绑定scrollbar的相关函数。
例如,scrollbar.config(command=text.yview),text.config(yscrollcommand=scrollbar.set)
如果只绑定了scrollbar.config(command=text.yview),那么只有对滚动条进行操作(drag slider,点击arrow,trough)时,text的视图才会随着变动;而对text进行操作(滚动鼠标滚轮)时,滚动条视图(slider)不会跟着变化
如果只绑定了text.config(yscrollcommand=scrollbar.set),那么只有对text进行操作(滚动鼠标滚轮)时,滚动条视图才会跟着变化;而对滚动条(scrollbar)进行操作(drag slider,点击arrow,trough)时,text的视图不会随着变动
所以,只有对 scrollbar和可滚动控件 相互绑定,才能实现操作任一种控件,两者视图都会同步变化.
from tkinter import (Tk, Text, Scrollbar)
from tkinter.constants import (HORIZONTAL, VERTICAL, RIGHT, LEFT, X, Y, BOTH, BOTTOM, YES)
main_win = Tk()
main_win.title('渔道的Scrollbar控件')
main_win.geometry(f'{800}x{800}')
scrollbar_v = Scrollbar(main_win)
scrollbar_v.pack(side=RIGHT, fill=Y)
scrollbar_h = Scrollbar(main_win, orient=HORIZONTAL)
scrollbar_h.pack(side=BOTTOM, fill=X)
text = Text(main_win, width=40, height=40)
text.config(yscrollcommand=scrollbar_v.set) # text绑定垂直滚动条
text.config(xscrollcommand=scrollbar_h.set) # text绑定水平滚动条
text.pack(expand=YES,fill=BOTH)
for i in range(1, 1000):
text.insert(f'{i}.0', f'line:{str(i)}\n')
scrollbar_v.config(command=text.yview) # 垂直滚动条绑定text
scrollbar_h.config(command=text.xview) # 水平滚动条绑定text
main_win.mainloop()
读者可以执行上述代码来 体验实际的效果。无法用语言描述。