1. 程式人生 > 其它 >ext grid隱藏的列不能修改_Tkinter元件scrollbar高階特性一:自動隱藏

ext grid隱藏的列不能修改_Tkinter元件scrollbar高階特性一:自動隱藏

技術標籤:ext grid隱藏的列不能修改

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()

5ac82d4dc2c58b68801422efe91eb0ca.png

特性實現:

佈局管理器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()方法,實現自動隱藏滾動條。如下圖所示:

fd1e0aabe29bf2c4f2d99c54d800ca1e.png

滾動條可以看做一個在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圖展示

6b2365faf6f973b604c6e14985d1afdf.png

佈局管理器pack的實現方式

如果你說你就喜歡使用 pack 方法實現這個功能,那麼也是可以不過麻煩了一些。因為 pack 中沒有類似於 grid.remove() 這樣既可以移除元件同時又儲存元件的位置資訊的方法(可能之後的版本會有)。

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

346861cc483531a99035cc5b75d5d60b.gif

很顯然在這裡是行不通的。


兩種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 的第一種實現方式。


結尾

有疑問歡迎留言詢問

請不要轉載,或者先詢問我

請不要轉載,或者先詢問我