欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ext grid隐藏的列不能修改_Tkinter组件scrollbar高级特性一:自动隐藏

程序员文章站 2022-07-13 23:04:33
...

Tkinter组件scrollbar高级特性一:自动隐藏

本文旨在实现 tk.Scrollbar(ttk..Scrollbar)本身没有且实用的特性:比如 自动隐藏和显示


简单示例:

示例1 简单滚动条的实现代码

# -*- coding:utf-8 -*-
# Date: 2020/3/13

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk
try:
    import ttk
except 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!n"*50)
hscrollbar.config(command=test_text.yview)

root.mainloop()

ext grid隐藏的列不能修改_Tkinter组件scrollbar高级特性一:自动隐藏

特性实现:

布局管理器grid的实现方式

实现的代码如下:

# -*- coding:utf-8 -*-

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk
try:
    import ttk
except ImportError:
    import tkinter.ttk as ttk

class 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!n"*30)
    yscrollbar.config(command=test_text.yview)
    root.mainloop()

注释❶:继承ttk.Scrollbar (tk.Scrollbar),重写覆盖父类的set()方法,实现自动隐藏滚动条。如下图所示:

ext grid隐藏的列不能修改_Tkinter组件scrollbar高级特性一:自动隐藏

滚动条可以看做一个在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_forget
def grid_remove(self):
    """Unmap this widget but remember the grid options."""
    self.tk.call('grid', 'remove', self._w)

效果GIF图展示

ext grid隐藏的列不能修改_Tkinter组件scrollbar高级特性一:自动隐藏

布局管理器pack的实现方式

如果你说你就喜欢使用 pack 方法实现这个功能,那么也是可以不过麻烦了一些。因为 pack 中没有类似于 grid.remove() 这样既可以移除组件同时又保存组件的位置信息的方法(可能之后的版本会有)。

如果使用之前的思路的话,效果如下:

ext grid隐藏的列不能修改_Tkinter组件scrollbar高级特性一:自动隐藏

很显然在这里是行不通的。


两种pack实现方法

一:在旁边放置一个 tk.Frame 组件来装 滚动条组件。

# -*- coding:utf-8 -*-

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk
try:
    import ttk
except ImportError:
    import tkinter.ttk as ttk

class 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!n"*26)


    root.mainloop()

二:使用canvas 组件来实现

# -*- coding:utf-8 -*-

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk
try:
    import ttk
except ImportError:
    import tkinter.ttk as ttk


class 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!n"*26)

    canvas.create_window(0, 0, anchor=tk.NW, window=frame)
    frame.update_idletasks()
    canvas.config(scrollregion=canvas.bbox("all"))

    root.mainloop()

使用 canvascanvas.create_window 来实现存在一些小问题,特别是内部使用 tk.Text 组件时。有机会再讲,毕竟和本文主题不搭。

推荐使用 grid 方式实现,如果就是要用 pack 实现的话建议使用 pack 的第一种实现方式。


结尾

有疑问欢迎留言询问

请不要转载,或者先询问我

请不要转载,或者先询问我