以前寫過界面,但是沒有記錄下來,以至於現在得從頭學習一次,論做好筆記的重要性。
現在學習的是怎么寫一個tabview出來,也就是用tkinter做一個界面切換的效果。參考鏈接:https://blog.csdn.net/yingshukun/article/details/89150105
tabview.py
import tkinter as tk import tkinter.ttk as ttk class TabView(tk.Frame): _tabs = [] _tab_view = [] _tab_text = [] _current = 0 # 當前選中tab的索引 _generate_func = None _select_listen = None _remove_listen = None ''' select_listen: tab選中事件回調函數,回調函數包含一個index參數 remove_listen: tab刪除事件回調函數,返回值必須是一個布爾值,True表示刪除,反之不刪除 generate_body: 生成body控件的回調函數,返回值應該是一個widget,用於添加到body中 ''' def __init__(self, master=None, select_listen=None, remove_listen=None, generate_body=None, cnf=None, **kw): super().__init__(master, cnf, **kw) # 選項卡 self._top = tk.Frame(self) self._top.bind("<Double-Button-1>", self._tab_add) self._top.pack(fill="x") # 分割線 ttk.Separator(self, orient=tk.HORIZONTAL).pack(fill="x") # 主體view self._bottom = tk.Frame(self) self._bottom.pack(fill="both", expand="yes") self._photo = tk.PhotoImage(file="remove.gif") # 事件回調 if select_listen: if callable(select_listen): self._select_listen = select_listen else: raise Exception("select_action is not callable") if remove_listen: if callable(remove_listen): self._remove_listen = remove_listen else: raise Exception("remove_action is not callable") if generate_body: if callable(generate_body): self._generate_func = generate_body else: raise Exception("generate_body is not callable") # 添加選項卡 def add_tab(self, view, text): self._add_body(view) self._create_tab(text) # 刪除選項卡 def remove_tab(self, index): self._tab_text.pop(index) self._tabs[index].destroy() self._tab_view[index].destroy() self._tabs.pop(index) self._tab_view.pop(index) if index > 0: self._current = index - 1 self._active() @property def body(self): return self._bottom def _create_tab(self, text): # 選項卡單元 tab_container = tk.Frame(self._top, relief=tk.RAISED, bd=1) # 標題、刪除按鈕 _tab_text_view = tk.Label(tab_container, text=text, padx=8) _tab_remove_view = tk.Label(tab_container, image=self._photo) _tab_text_view.bind("<Button-1>", self._tab_click) _tab_remove_view.bind("<Button-1>", self._tab_remove) _tab_text_view.pack(side=tk.LEFT) _tab_remove_view.pack(side=tk.LEFT) tab_container.pack(side=tk.LEFT) self._tab_text.append(_tab_text_view) self._tabs.append(tab_container) self._active() def _add_body(self, view): self._tab_view.append(view) view.place(relwidth=1.0, relheight=1.0) # 刷新當前激活狀態 def _active(self): for i, item in enumerate(self._tabs): if i == self._current: item.config(relief=tk.RAISED, bd=3) # lift方法,讓當前widget處於最頂層 self._tab_view[self._current].lift() else: item.config(bd=1) def _tab_add(self, event): self._current = len(self._tabs) if not self._generate_func: self.add_tab(tk.Frame(self.body), "Untitled") else: self.add_tab(self._generate_func(), "Untitled") # 刪除事件回調 def _tab_remove(self, event): current_widget = event.widget.winfo_parent() select_index = self._index(current_widget) is_remove = True if self._remove_listen: is_remove = self._remove_listen(select_index) if is_remove: if select_index != -1: self.remove_tab(select_index) # 選項卡點擊事件回調 def _tab_click(self, event): current_widget = event.widget.winfo_parent() select_index = self._index(current_widget) if select_index != -1: self._current = select_index self._active() if self._select_listen: self._select_listen(select_index) # 返回當前選項卡的索引 def _index(self, el): index = [i for i, x in enumerate(self._tabs) if str(x) == el] return index[0] if index else -1
對於上面tabview的類,或許會有不太明白的地方,一一解析。
1. Frame
frame其實就像一個布局,一個一個的分區,然后分別往上面添加控件。
2. Bind
綁定事件,比如鼠標單擊,雙擊時需要操作什么
這兩個詳細的可以參考:https://www.cnblogs.com/sunzebo/articles/9643620.html
3. callable()函數
callable() 函數用於檢查一個對象是否是可調用的。如果返回 True,object 仍然可能調用失敗;但如果返回 False,調用對象 object 絕對不會成功。鏈接:https://www.runoob.com/python/python-func-callable.html
