(八)Python 圖形化界面設計

  • 1、圖形化界面設計的基本理解

    當前流行的計算機桌面應用程序大多數為圖形化用戶界面(Graphic User Interface,GUI),即通過鼠標對菜單、按鈕等圖形化元素觸發指令,并從標簽、對話框等圖型化顯示容器中獲取人機對話信息。
    Python自帶了tkinter 模塊,實質上是一種流行的面向對象的GUI工具包 TK 的Python編程接口,提供了快速便利地創建GUI應用程序的方法。其圖像化編程的基本步驟通常包括:

    • 導入 tkinter 模塊
    • 創建 GUI 根窗體
    • 添加人機交互控件并編寫相應的函數。
    • 在主事件循環中等待用戶觸發事件響應。
  • 2、窗體控件布局

    • 2.1、根窗體是圖像化應用程序的根控制器,是tkinter的底層控件的實例。當導入tkinter模塊后,調用 Tk()方法可初始化一個根窗體實例 root ,用 title() 方法可設置其標題文字,用geometry()方法可以設置窗體的大小(以像素為單位)。將其置于主循環中,除非用戶關閉,否則程序始終處于運行狀態。執行該程序,一個窗體就呈現出來了。在這個主循環的根窗體中,可持續呈現中的其他可視化控件實例,監測事件的發生并執行相應的處理程序。下面是根窗體呈現示例:

      from tkinter import *
      root= Tk()
      root.title('我的第一個Python窗體')
      root.geometry('240x240') # 這里的乘號不是 * ,而是小寫英文字母 x
      root.mainloop()
      
      根窗體呈現示例
    • 2.2、tkinter 常用控件

      • 常用控件:常用的10 多種,如下:
      控件 名稱 作用
      Button 按鈕 單擊觸發事件
      Canvas 畫布 繪制圖形或繪制特殊控件
      Checkbutton 復選框 多項選擇
      Entry 輸入框 接收單行文本輸入
      Frame 框架 用于控件分組
      Label 標簽 單行文本顯示
      Lisbox 列表框 顯示文本列表
      Menu 菜單 創建菜單命令
      Message 消息 多行文本標簽,與Label 用法類似
      Radiobutton 單選按鈕 從互斥的多個選項中做單項選擇
      Scale 滑塊 默認垂直方向,鼠標拖動改變數值形成可視化交互
      Scrollbar 滑動條 默認垂直方向,課鼠標拖動改變數值,可與 Text、Lisbox、Canvas等控件配合移動可視化空間
      Text 文本框 接收或輸出顯示多行文本
      Toplevel 新建窗體容器 在頂層創建新窗體
      • 控件的共同屬性:在窗體上呈現的可視化控件,通常包括尺寸、顏色、字體、相對位置、浮雕樣式、圖標樣式和懸停光標形狀等共同屬性。不同的控件由于形狀和功能不同,又有其特征屬性。在初始化根窗體和根窗體主循環之間,可實例化窗體控件,并設置其屬性。父容器可為根窗體或其他容器控件實例。常見的控件共同屬性如下表:

        屬性 說明 取值
        anchor 文本起始位置 CENTER(默認),E,S,W,N,NE,SE,SW,NW
        bg 背景色
        bd 加粗(默認 2 像素)
        bitmap 黑白二值圖標 網上查找
        cursor 鼠標懸停光標 網上查找
        font 字體
        fg 前景色
        height 高(文本控件的單位為行,不是像素)
        image 顯示圖像
        justify 多行文本的對其方式 CENTER(默認),LEFT,RIGHT,TOP,BOTTOM
        padx 水平擴展像素
        pady 垂直擴展像素
        relief 3D浮雕樣式 FLAT,RAISED,SUNKEN,GROOVE,RIDGE
        state 控件實例狀態是否可用 NORMAL(默認),DISABLED
        width 寬(文本控件的單位為行,不是像素)

        標簽及常見屬性示例:

        from  tkinter import *
        root = Tk()
        lb = Label(root,text='我是第一個標簽',\
                bg='#d3fbfb',\
                fg='red',\
                font=('華文新魏',32),\
                width=20,\
                height=2,\
                relief=SUNKEN)
        lb.pack()
        root.mainloop()
        


        其中,標簽實例lb 在父容器root中實例化,具有代碼中所示的text(文本)、bg(背景色)、fg(前景色)、font(字體)、width(寬,默認以字符為單位)、height(高,默認以字符為單位)和 relief(浮雕樣式)等一系列屬性。
        在實例化控件時,實例的屬性可以“屬性=屬性值”的形式枚舉列出,不區分先后次序。例如:“ text='我是第一個標簽' ”顯示標簽的文本內容,“bg='#d3fbfb'”設置背景色為十六進制數RGB色 #d3fbfb等等。屬性值通常用文本形式表示。
        當然如果這個控件實例只需要一次性呈現,也可以不必命名,直接實例化并布局呈現出來,例如:

        Label(root,text='我是第一個標簽',font='華文新魏').pack()
        

屬性 relief 為控件呈現出來的3D浮雕樣式,有 FLAT(平的)、RAISED(凸起的)、SUNKEN(凹陷的)、GROOVE(溝槽狀邊緣)和 RIDGE(脊狀邊緣) 5種。


控件呈現的5種浮雕樣式
  • 2.2、控件布局
    控件的布局通常有pack()grid()place() 三種方法。

    • 2.2.1、pack()方法:是一種簡單的布局方法,如果不加參數的默認方式,將按布局語句的先后,以最小占用空間的方式自上而下地排列控件實例,并且保持控件本身的最小尺寸。如下的例子:

      • 用pack() 方法不加參數排列標簽。為看清楚各控件所占用的空間大小,文本用了不同長度的中英文,并設置relief=GROOVE的凹陷邊緣屬性。如下所示:
        from tkinter import  *
        root = Tk()
        
        lbred = Label(root,text="Red",fg="Red",relief=GROOVE)
        lbred.pack()
        lbgreen = Label(root,text="綠色",fg="green",relief=GROOVE)
        lbgreen.pack()
        lbblue = Label(root,text="藍",fg="blue",relief=GROOVE)
        lbblue.pack()
        root.mainloop()
        
      • 使用pack()方法可設置 fill、side 等屬性參數。其中,參數fill 可取值:fill=X,fill=Y或fill=BOTH,分別表示允許控件向水平方向、垂直方向或二維伸展填充未被占用控件。參數 side 可取值:side=TOP(默認),side=LEFT,side=RIGHT,side=BOTTOM,分別表示本控件實例的布局相對于下一個控件實例的方位。如下例子:


        用pack()方法加參數排列標簽
        from tkinter import  *
        root = Tk()
        
        lbred = Label(root,text="Red",fg="Red",relief=GROOVE)
        lbred.pack()
        lbgreen = Label(root,text="綠色",fg="green",relief=GROOVE)
        lbgreen.pack(side=RIGHT)
        lbblue = Label(root,text="藍",fg="blue",relief=GROOVE)
        lbblue.pack(fill=X)
        root.mainloop()
        
    • 2.2.2、grid()方法:是基于網格的布局。先虛擬一個二維表格,再在該表格中布局控件實例。由于在虛擬表格的單元中所布局的控件實例大小不一,單元格也沒有固定或均一的大小,因此其僅用于布局的定位。pack()方法與grid()方法不能混合使用。
      grid()方法常用布局參數如下:

      • column: 控件實例的起始列,最左邊為第0列。
      • columnspan: 控件實例所跨越的列數,默認為1列。
      • ipadx,ipady: 控件實例所呈現區域內部的像素數,用來設置控件實例的大小。
      • padx,pady: 控件實例所占據空間像素數,用來設置實例所在單元格的大小。
      • row: 控件實例的起始行,最上面為第0行。
      • rowspan: 控件實例的起始行數,默認為1行。

      看下面的例子:用grid()方法排列標簽,設想有一個3x4的表格,起始行、列序號均為0.將標簽lbred 至于第2列第0行;將標簽lbgreen置于第0列第1行;將標簽lbblue置于第1列起跨2列第2行,占20像素寬。


      pack()方法排列標簽
      from tkinter import  *
      root = Tk()
      
      lbred = Label(root,text="Red",fg="Red",relief=GROOVE)
      lbred.grid(column=2,row=0)
      lbgreen = Label(root,text="綠色",fg="green",relief=GROOVE)
      lbgreen.grid(column=0,row=1)
      lbblue = Label(root,text="藍",fg="blue",relief=GROOVE)
      lbblue.grid(column=1,columnspan=2,ipadx=20,row=2)
      root.mainloop()
      
    • 2.2.3、place()方法:根據控件實例在父容器中的絕對或相對位置參數進行布局。其常用布局參數如下:

      • x,y:控件實例在根窗體中水平和垂直方向上的其實位置(單位為像素)。注意,根窗體左上角為0,0,水平向右,垂直向下為正方向。

      • relx,rely:控件實例在根窗體中水平和垂直方向上起始布局的相對位置。即相對于根窗體寬和高的比例位置,取值在0.0~1.0之間。

      • height,width:控件實例本身的高度和寬度(單位為像素)。

      • relheight,relwidth:控件實例相對于根窗體的高度和寬度比例,取值在0.0~1.0之間。

      • 利用place()方法配合relx,rely和relheight,relwidth參數所得的到的界面可自適應根窗體尺寸的大小。place()方法與grid()方法可以混合使用。如下例子:利用place()方法排列消息(多行標簽)。


        place()方法排列消息
        from tkinter import *
        root = Tk()
        root.geometry('320x240')
        
        msg1 = Message(root,text='''我的水平起始位置相對窗體 0.2,垂直起始位置為絕對位置 80 像素,我的高度是窗體高度的0.4,寬度是200像素''',relief=GROOVE)
        msg1.place(relx=0.2,y=80,relheight=0.4,width=200)
        root.mainloop()
        
  • 3、tkinter常見控件的特征屬性

    • 3.1、文本輸入和輸出相關控件:文本的輸入與輸出控件通常包括:標簽(Label)、消息(Message)、輸入框(Entry)、文本框(Text)。他們除了前述共同屬性外,都具有一些特征屬性和功能。

      • 標簽(Label)和 消息(Message):除了單行與多行的不同外,屬性和用法基本一致,用于呈現文本信息。值得注意的是:屬性text通常用于實例在第一次呈現時的固定文本,而如果需要在程序執行后發生變化,則可以使用下列方法之一實現:1、用控件實例的configure()方法來改變屬性text的值,可使顯示的文本發生變化;2、先定義一個tkinter的內部類型變量var=StringVar() 的值也可以使顯示文本發生變化。
        看下面的一個例子:制作一個電子時鐘,用root的after()方法每隔1秒time模塊以獲取系統當前時間,并在標簽中顯示出來。

        • 方法一:利用configure()方法或config()來實現文本變化。


          import tkinter
          import time
          
          def gettime():
                timestr = time.strftime("%H:%M:%S") # 獲取當前的時間并轉化為字符串
                lb.configure(text=timestr)   # 重新設置標簽文本
                root.after(1000,gettime) # 每隔1s調用函數 gettime 自身獲取時間
          
          root = tkinter.Tk()
          root.title('時鐘')
          
          lb = tkinter.Label(root,text='',fg='blue',font=("黑體",80))
          lb.pack()
          gettime()
          root.mainloop()
          
        • 方法二:利用textvariable變量屬性來實現文本變化。

          import tkinter
          import time
          
          def gettime():
                var.set(time.strftime("%H:%M:%S"))   # 獲取當前時間
                root.after(1000,gettime)   # 每隔1s調用函數 gettime 自身獲取時間
          
          root = tkinter.Tk()
          root.title('時鐘')
          var=tkinter.StringVar()
          
          lb = tkinter.Label(root,textvariable=var,fg='blue',font=("黑體",80))
          lb.pack()
          gettime()
          root.mainloop()
          
      • 文本框(Text)

        文本框的常用方法如下:

        方法 功能
        delete(起始位置,[,終止位置]) 刪除指定區域文本
        get(起始位置,[,終止位置]) 獲取指定區域文本
        insert(位置,[,字符串]...) 將文本插入到指定位置
        see(位置) 在指定位置是否可見文本,返回布爾值
        index(標記) 返回標記所在的行和列
        mark_names() 返回所有標記名稱
        mark_set(標記,位置) 在指定位置設置標記
        mark_unset(標記) 去除標記

        上表位置的取值可為整數,浮點數或END(末尾),例如0.0表示第0列第0行
        如下一個例子:每隔1秒獲取一次當前日期的時間,并寫入文本框中,如下:本例中調用 datetime.now()獲取當前日期時間,用insert()方法每次從文本框txt的尾部(END)開始追加文本。

        獲取當前日期的時間并寫入文本中

        from tkinter import *
        import time
        import datetime
        
        def gettime():
               s=str(datetime.datetime.now())+'\n'
               txt.insert(END,s)
               root.after(1000,gettime)  # 每隔1s調用函數 gettime 自身獲取時間
        
        root=Tk()
        root.geometry('320x240')
        txt=Text(root)
        txt.pack()
        gettime()
        root.mainloop()
        
      • 輸入框(Entry):通常作為功能比較單一的接收單行文本輸入的控件,雖然也有許多對其中文本進行操作的方法,但通常用的只有取值方法get()和用于刪除文本的delete(起始位置,終止位置),例如:清空輸入框為delete(0,END)。

    • 3.2、按鈕(Button):主要是為響應鼠標單擊事件觸發運行程序所設的,故其除控件共有屬性外,屬性command是最為重要的屬性。通常,將按鈕要觸發執行的程序以函數形式預先定義,然后可以用一下兩種方法調用函數。Button按鈕的狀態有:'normal','active','disabled'

      • 直接調用函數。參數表達式為“command=函數名”,注意函數名后面不要加括號,也不能傳遞參數。如下面的command=run1:

      • 利用匿名函數調用函數和傳遞參數。參數的表達式為“command=lambda”:函數名(參數列表)。例如下面的:"command=lambda:run2(inp1.get(),inp2.get())"。

      • 看下面的例子:1.從兩個輸入框去的輸入文本后轉為浮點數值進行加法運算,要求每次單擊按鈕產生的算是結果以文本的形式追加到文本框中,將原輸入框清空。2.按鈕方法一不傳參數調用函數run1()實現,按鈕“方法二”用lambda調用函數run2(x,y)同時傳遞參數實現。


        簡單加法器
        from tkinter import *
        
        def run1():
             a = float(inp1.get())
             b = float(inp2.get())
             s = '%0.2f+%0.2f=%0.2f\n' % (a, b, a + b)
             txt.insert(END, s)   # 追加顯示運算結果
             inp1.delete(0, END)  # 清空輸入
             inp2.delete(0, END)  # 清空輸入
        
        def run2(x, y):
             a = float(x)
             b = float(y)
             s = '%0.2f+%0.2f=%0.2f\n' % (a, b, a + b)
             txt.insert(END, s)   # 追加顯示運算結果
             inp1.delete(0, END)  # 清空輸入
             inp2.delete(0, END)  # 清空輸入
        
        root = Tk()
        root.geometry('460x240')
        root.title('簡單加法器')
        
        lb1 = Label(root, text='請輸入兩個數,按下面兩個按鈕之一進行加法計算')
        lb1.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.1)
        inp1 = Entry(root)
        inp1.place(relx=0.1, rely=0.2, relwidth=0.3, relheight=0.1)
        inp2 = Entry(root)
        inp2.place(relx=0.6, rely=0.2, relwidth=0.3, relheight=0.1)
        
        # 方法-直接調用 run1()
        btn1 = Button(root, text='方法一', command=run1)
        btn1.place(relx=0.1, rely=0.4, relwidth=0.3, relheight=0.1)
        
        # 方法二利用 lambda 傳參數調用run2()
        btn2 = Button(root, text='方法二', command=lambda: run2(inp1.get(), inp2.get()))
        btn2.place(relx=0.6, rely=0.4, relwidth=0.3, relheight=0.1)
        
        # 在窗體垂直自上而下位置60%處起,布局相對窗體高度40%高的文本框
        txt = Text(root)
        txt.place(rely=0.6, relheight=0.4)
        
        root.mainloop()
        
    • 3.3、單選按鈕:(Radiobutton)是為了響應故鄉排斥的若干單選項的單擊事件以觸發運行自定義函數所設的,該控件排除具有共有屬性外,還具有顯示文本(text)、返回變量(variable)、返回值(value)、響應函數名(command)等重要屬性。響應函數名“command=函數名”的用法與Button相同,函數名最后也要加括號。返回變量variable=var通常應預先聲明變量的類型var=IntVar()或var=StringVar(),在所調用的函數中方可用var.get()方法獲取被選中實例的value值。例如下面:

      單選按鈕

      from tkinter import *
      def Mysel():
            dic = {0:'甲',1:'乙',2:'丙'}
            s = "您選了" + dic.get(var.get()) + "項"
            lb.config(text = s)
      
      root = Tk()
      root.title('單選按鈕')
      lb = Label(root)
      lb.pack()
      
      var = IntVar()
      rd1 = Radiobutton(root,text="甲",variable=var,value=0,command=Mysel)
      rd1.pack()
      
      rd2 = Radiobutton(root,text="乙",variable=var,value=1,command=Mysel)
      rd2.pack()
      
      rd3 = Radiobutton(root,text="丙",variable=var,value=2,command=Mysel)
      rd3.pack()
      
      root.mainloop()
      
    • 3.4、復選框:(Checkbutton) 是為了返回多個選項值的交互控件,通常不直接觸發函數的執行。該控件除具有共有屬性外,還具有顯示文本(text)、返回變量(variable)、選中返回值(onvalue)和未選中默認返回值(offvalue)等重要屬性。返回變量variable=var 通常可以預先逐項分別聲明變量的類型var=IntVar() (默認)或 var=StringVar(), 在所調用的函數中方可分別調用 var.get()方法 取得被選中實例的 onvalue或offvalue值。復選框實例通常還可分別利用 select()、deselect()和 toggle() 方法對其進行選中、清除選中和反選操作。

      • 如下的例子: 利用復選框實現,單擊OK,可以將選中的結果顯示在標簽上。效果如下:


        復選框的應用
        • 方法:利用函數中的 if-else 分支實現多項顯示

          from tkinter import *
          import tkinter
          
          def run():
               if(CheckVar1.get()==0 and CheckVar2.get()==0 and CheckVar3.get()==0 and CheckVar4.get()==0):
                   s = '您還沒選擇任何愛好項目'
               else:
                   s1 = "足球" if CheckVar1.get()==1 else ""
                   s2 = "籃球" if CheckVar2.get() == 1 else ""
                   s3 = "游泳" if CheckVar3.get() == 1 else ""
                   s4 = "田徑" if CheckVar4.get() == 1 else ""
                   s = "您選擇了%s %s %s %s" % (s1,s2,s3,s4)
               lb2.config(text=s)
          
          root = tkinter.Tk()
          root.title('復選框')
          lb1=Label(root,text='請選擇您的愛好項目')
          lb1.pack()
          
          CheckVar1 = IntVar()
          CheckVar2 = IntVar()
          CheckVar3 = IntVar()
          CheckVar4 = IntVar()
          
          ch1 = Checkbutton(root,text='足球',variable = CheckVar1,onvalue=1,offvalue=0)
          ch2 = Checkbutton(root,text='籃球',variable = CheckVar2,onvalue=1,offvalue=0)
          ch3 = Checkbutton(root,text='游泳',variable = CheckVar3,onvalue=1,offvalue=0)
          ch4 = Checkbutton(root,text='田徑',variable = CheckVar4,onvalue=1,offvalue=0)
          
          ch1.pack()
          ch2.pack()
          ch3.pack()
          ch4.pack()
          
          btn = Button(root,text="OK",command=run)
          btn.pack()
          
          lb2 = Label(root,text='')
          lb2.pack()
          root.mainloop()
          
    • 3.5、列表框 與 組合框

      • 3.5.1、列表框:(Listbox) 可供用戶單選或多選所列條目以形成人機交互。列表框控件的主要方法見下面的表:
      方法 功能描述
      curselection() 返回光標選中項目編號的元組,注意并不是單個的整數
      delete(起始位置,終止位置) 刪除項目,終止位置可省略,全部清空為delete(0,END)
      get(起始位置,終止位) 返回范圍所含項目文本的元組,終止位置可忽略
      insert(位置,項目元素) 插入項目元素(若有多項,可用列表或元組類型賦值),若位置為END,則將項目元素添加在最后
      size() 返回列表框行數

      執行自定義函數時,通常使用“實例名.surselection()” 或 “selected” 來獲取選中項的位置索引。由于列表框實質上就是將Python 的列表類型數據可視化呈現,在程序實現時,也可直接對相關列表數據進行操作,然后再通過列表框展示出來,而不必拘泥于可視化控件的方法。看下面的一個例子:實現列表框的初始化、添加、插入、修改、刪除和清空操作,如下:

      列表框的應用

      from tkinter import *
      def ini():
            Lstbox1.delete(0,END)
            list_items = ["數學","物理","化學","語文","外語"]
            for item in list_items:
                 Lstbox1.insert(END,item)
      
      def clear():
            Lstbox1.delete(0,END)
      
      def ins():
            if entry.get() != '':
                if Lstbox1.curselection() == ():
                    Lstbox1.insert(Lstbox1.size(),entry.get())
                else:
                    Lstbox1.insert(Lstbox1.curselection(),entry.get())
      
      def updt():
            if entry.get() != '' and Lstbox1.curselection() != ():
                 selected=Lstbox1.curselection()[0]
                 Lstbox1.delete(selected)
                 Lstbox1.insert(selected,entry.get())
      
      def delt():
            if Lstbox1.curselection() != ():
                 Lstbox1.delete(Lstbox1.curselection())
      
      root = Tk()
      root.title('列表框實驗')
      root.geometry('320x240')
      
      frame1 = Frame(root,relief=RAISED)
      frame1.place(relx=0.0)
      
      frame2 = Frame(root,relief=GROOVE)
      frame2.place(relx=0.5)
      
      Lstbox1 = Listbox(frame1)
      Lstbox1.pack()
      
      entry = Entry(frame2)
      entry.pack()
      
      btn1 = Button(frame2,text='初始化',command=ini)
      btn1.pack(fill=X)
      
      btn2 = Button(frame2,text='添加',command=ins)
      btn2.pack(fill=X)
      
      btn3 = Button(frame2,text='插入',command=ins) # 添加和插入功能實質上是一樣的
      btn3.pack(fill=X)
      
      btn4 = Button(frame2,text='修改',command=updt)
      btn4.pack(fill=X)
      
      btn5 = Button(frame2,text='刪除',command=delt)
      btn5.pack(fill=X)
      
      btn6 = Button(frame2,text='清空',command=clear)
      btn6.pack(fill=X)
      
      root.mainloop()
      
      • 3.5.2、組合框:(Combobox) 實質上是帶文本框的上拉列表框,其功能也將是Python 的列表類型數據可視化呈現,并提供用戶單選或多選所列條目以形成人機交互。在圖形化界面設計時,由于其具有靈活的界面,因此往往比列表框更受喜愛。但該控件并不包含在 tkinter 模塊中,而是與 TreeView、Progressbar、Separator等控件一同包含在tkinter 的子模塊ttk中。如果使用該控件,應先與from tkinter import ttk 語句引用ttk子模塊,然后創建組合框實例: 實例名=Combobox(根對象,[屬性列表])
        指定變量var=StringVar(),并設置實例屬性 textvariable = var,values=[列表...]。組合框控件常用方法有:獲得所選中的選項值get()和獲得所選中的選項索引current()。
        看下面的一個例子:實現四則運算計算器,將兩個操作數分別填入兩個文本框后,通過選擇組合框中的算法觸發運算,如下:

        組合框的應用

        from tkinter.ttk import *
        
        def calc(event):
               a = float(t1.get())
               b = float(t2.get())
               dic = {0:a+b,1:a-b,2:a*b,3:a/b}
               c = dic[comb.current()]
               lbl.config(text=str(c))
        
        root = Tk()
        root.title('四則運算')
        root.geometry('320x240')
        
        t1 = Entry(root)
        t1.place(relx=0.1,rely=0.1,relwidth=0.2,relheight=0.1)
        
        t2 = Entry(root)
        t2.place(relx=0.5,rely=0.1,relwidth=0.2,relheight=0.1)
        
        var = StringVar()
        
        comb = Combobox(root,textvariable=var,values=['加','減','乘','除',])
        comb.place(relx=0.1,rely=0.5,relwidth=0.2)
        comb.bind('<<ComboboxSelected>>',calc)
        
        lbl=Label(root,text='結果')
        lbl.place(relx=0.5,rely=0.7,relwidth=0.2,relheight=0.3)
        
        root.mainloop()
        
    • 3.6、滑塊:(Scale) 是一種 直觀地進行數值輸入的交互控件,其主要屬性見下表:

      屬性 功能描述
      from_ 起始值(最小可取值)
      lable 標簽文字,默認為無
      length 滑塊控件實例寬(水平方向)或 高(垂直方向),默認為100像素
      orient 滑塊控件實例呈現方向,VERTCAL或HORIZONTAL(默認)
      repeatdelay 鼠標響應延時,默認為 300ms
      resolution 分辨精度,即最小值間隔
      sliderlength 滑塊寬度,默認為30 像素
      state 狀態,若設置 state=DISABLED,則滑塊控件實例不可用
      tickinterval 標尺間隔,默認為0,若設置過小,則會重疊
      to 終止值(最大可取值)
      variable 返回數值類型,可為IntVar(整數)、DoubleVar(浮點數)、或 StringVar(字符串)
      width 控件實例本身的寬度,默認為15像素

      滑塊控件實例的主要方法比較簡單,有 get()和set(值),分別為取值和將滑塊設在某特定值上。滑塊實例也可綁定鼠標左鍵釋放事件<ButtoonRelease-1>,并在執行函數中添加參數event來實現事件響應。
      例如:在一個窗體上設計一個200像素寬的水平滑塊,取值范圍為1.0~5.0,分辨精度為0.05,刻度間隔為 1,用鼠標拖動滑塊后釋放鼠標可讀取滑塊值并顯示在標簽上。效果如下:


      滑塊控件的應用
      from tkinter  import  *
      
      def show(event):
            s = '滑塊的取值為' + str(var.get())
            lb.config(text=s)
      
      root = Tk()
      root.title('滑塊實驗')
      root.geometry('320x180')
      var=DoubleVar()
      scl = Scale(root,orient=HORIZONTAL,length=200,from_=1.0,to=5.0,label='請拖動滑塊',tickinterval=1,resolution=0.05,variable=var)
      scl.bind('<ButtonRelease-1>',show)
      scl.pack()
      
      lb = Label(root,text='')
      lb.pack()
      
      root.mainloop()
      
    • 3.7、菜單:(Menu)用于可視化地為一系列的命令分組,從而方便用戶找到和觸發執行這些命令。這里Menu所實例化別的主要是菜單,其通式為:

      菜單實例名=Menu(根窗體)
      菜單分組1=Menu(菜單實例名)
      菜單實例名.add_cascade(<label=菜單分組1 顯示文本>,<menu=菜單分組1>)
      菜單分組1.add_command(<label=命令1文本>,<command=命令1函數名>)
      

      其中較為常見的方法有:add_cascade()、add_command()和add_separator(),分別用于添加一個菜單分組、添加一條菜單命令和添加一條分割線
      利用Menu控件也可以創建快捷菜單(又稱為上下文菜單)。通常需要右擊彈出的控件實例綁定鼠標右擊響應事件<Button-3>,并指向一個捕獲event參數的自定義函數,在該自定義函數中,將鼠標的觸發位置event.x_root 和 event.y_root以post()方法傳給菜單。
      例子:仿照window自帶的“記事本”中的文件和編輯 菜單,實現在主菜單個快捷菜單上觸發菜單命令,并相應改變窗體上的標簽的文本內容。效果如下:

      菜單和快捷菜單

      from tkinter import *
      
      def new():
           s = '新建'
           lb1.config(text=s)
      
      def ope():
           s = '打開'
           lb1.config(text=s)
      
      def sav():
           s = '保存'
           lb1.config(text=s)
      
      def cut():
           s = '剪切'
           lb1.config(text=s)
      
      def cop():
           s = '復制'
           lb1.config(text=s)
      
      def pas():
           s = '粘貼'
           lb1.config(text=s)
      
      def popupmenu(event):
           mainmenu.post(event.x_root,event.y_root)
      
      root = Tk()
      root.title('菜單實驗')
      root.geometry('320x240')
      
      lb1 = Label(root,text='顯示信息',font=('黑體',32,'bold'))
      lb1.place(relx=0.2,rely=0.2)
      
      mainmenu = Menu(root)
      menuFile = Menu(mainmenu)  # 菜單分組 menuFile
      mainmenu.add_cascade(label="文件",menu=menuFile)
      menuFile.add_command(label="新建",command=new)
      menuFile.add_command(label="打開",command=ope)
      menuFile.add_command(label="保存",command=sav)
      menuFile.add_separator()  # 分割線
      menuFile.add_command(label="退出",command=root.destroy)
      
      menuEdit = Menu(mainmenu)  # 菜單分組 menuEdit
      mainmenu.add_cascade(label="編輯",menu=menuEdit)
      menuEdit.add_command(label="剪切",command=cut)
      menuEdit.add_command(label="復制",command=cop())
      menuEdit.add_command(label="粘貼",command=pas())
      
      root.config(menu=mainmenu)
      root.bind('Button-3',popupmenu) # 根窗體綁定鼠標右擊響應事件
      root.mainloop()
      
    • 3.8、子窗體:用Toplevel可新建一個顯示在最前面的子窗體,其通式為: 字體實例名=Toplevel(根窗體),子窗體與根窗體類似,也可設置title、geomerty等屬性,并在畫布上布局其他控件。如下的例子:在根窗體上創建菜單,觸發創建一個新的窗體

      根窗體與子窗體

      from tkinter import *
      
      def newwind():
            winNew = Toplevel(root)
            winNew.geometry('320x240')
            winNew.title('新窗體')
            lb2 = Label(winNew,text='我在新窗體上')
            lb2.place(relx=0.2,rely=0.2)
            btClose=Button(winNew,text='關閉',command=winNew.destroy)
            btClose.place(relx=0.7,rely=0.5)
      
      root = Tk()
      root.title('新建窗體實驗')
      root.geometry('320x240')
      
      lb1 = Label(root,text='主窗體',font=('黑體',32,'bold'))
      lb1.place(relx=0.2,rely=0.2)
      
      mainmenu = Menu(root)
      menuFile = Menu(mainmenu)
      mainmenu.add_cascade(label='菜單',menu=menuFile)
      menuFile.add_command(label='新窗體',command=newwind)
      menuFile.add_separator()
      menuFile.add_command(label='退出',command=root.destroy)
      
      root.config(menu=mainmenu)
      root.mainloop()
      

      關閉窗體程序運行的方法通常用 destory(),而不建議用 quit()。用Toplevel 所創建的子窗體是非模式(Modeless)的窗體,雖然初建時子窗體在最前面,但根窗體上的控件實例也是可以被操作的。

    • 3.9、模式對話框(Modal):是相對于前面介紹的非模式窗體而言的,所彈出的對話框必須應答,在關閉之前無法操作其后面的其他窗體。常見的模式對話框有消息對話框、輸入對話框、文件選擇對話框、顏色選擇對話框等。

      • 3.9.1、交互對話框

        (一)、消息對話框: 引用 tkinter.messagebox 包,可使用消息對話框函數。執行這些函數,可彈出模式消息對話框,并根據用戶的響應但會一個布爾值。其通式為:

         消息對話框函數(<title=標題文本>,<message=消息文本>,[其他參數])
        

        看下面的例子:單擊按鈕,彈出確認取消對話框,并將用戶回答顯示在標簽中。效果如下:


        確定取消對話框
        from tkinter import *
        import tkinter.messagebox
        
        def xz():
            answer=tkinter.messagebox.askokcancel('請選擇','請選擇確定或取消')
            if answer:
                lb.config(text='已確認')
            else:
                lb.config(text='已取消')
        
        root = Tk()
        
        lb = Label(root,text='')
        lb.pack()
        btn=Button(root,text='彈出對話框',command=xz)
        btn.pack()
        root.mainloop()
        

        (二)、輸入對話框: 引用tkinter.simpledialog包,可彈出輸入對話框,用以接收用戶的簡單輸入。輸入對話框常用 askstring()、askfloat()和askfloat() 三種函數,分別用于接收字符串、整數和浮點數類型的輸入。
        如下面的例子:單擊按鈕,彈出輸入對話框,接收文本輸入顯示在窗體的標簽上。如下:

        輸入對話框

        from tkinter.simpledialog import *
        
        def xz():
            s=askstring('請輸入','請輸入一串文字')
            lb.config(text=s)
        
        root = Tk()
        
        lb = Label(root,text='')
        lb.pack()
        btn=Button(root,text='彈出輸入對話框',command=xz)
        btn.pack()
        root.mainloop()
        
      • 3.9.2、文件選擇對話框:引用tkinter.filedialog包,可彈出文件選擇對話框,讓用戶直觀地選擇一個或一組文件,以供進一步的文件操作。常用的文件選擇對話框函數有 askopenfilename()、askopenfilenames()和asksaveasfilename(),分別用于進一步打開一個文件、一組文件和保存文件。其中,askopenfilename()和asksaveasfilenamme()函數的返回值類型為包含文件路徑的文件名字符串,而askopenfilenames()函數的返回值類型為元組。
        例如:單擊按鈕,彈出文件選擇對話框(“打開”對話框),并將用戶所選擇的文件路徑和文件名顯示在窗體的標簽上。如下

        文件選擇對話框

        from tkinter import *
        import tkinter.filedialog
        
        def xz():
            filename=tkinter.filedialog.askopenfilename()
            if filename != '':
                 lb.config(text='您選擇的文件是'+filename)
            else:
                 lb.config(text='您沒有選擇任何文件')
        
        root = Tk()
        
        lb = Label(root,text='')
        lb.pack()
        btn=Button(root,text='彈出文件選擇對話框',command=xz)
        btn.pack()
        root.mainloop()
        
      • 3.9.3、顏色選擇對話框:引用tkinter.colorchooser包,可使用 askcolor()函數彈出模式顏色選擇對話框,讓用戶可以個性化地設置顏色屬性。該函數的返回形式為包含RGB十進制浮點元組和RGB十六進制字符串的元組類型,例如:“((135.527343.52734375,167.65234375,186.7265625)),'#87a7ba'”。通常,可將其轉換為字符串類型后,再截取以十六進制數表示的RGB顏色字符串用于為屬性賦值。
        舉例:單擊按鈕,彈出顏色選擇對話框,并將用戶所選擇的顏色設置為窗體上標簽的背景顏色,如下:

        顏色選擇對話框

        from tkinter import *
        import tkinter.colorchooser
        
        def xz():
            color=tkinter.colorchooser.askcolor()
            colorstr=str(color)
            print('打印字符串%s 切掉后=%s' % (colorstr,colorstr[-9:-2]))
            lb.config(text=colorstr[-9:-2],background=colorstr[-9:-2])
        
        root = Tk()
        
        lb = Label(root,text='請關注顏色的變化')
        lb.pack()
        btn=Button(root,text='彈出顏色選擇對話框',command=xz)
        btn.pack()
        root.mainloop()
        
  • 4、事件響應
    用tkinter 可將用戶事件與自定義函數綁定,用鍵盤或鼠標的動作事件來響應觸發自定義函數的執行。其通式為:

    控件實例.bind(<事件代碼>,<函數名>)
    

    其中,事件代碼通常以半角小于號“<”和大于號“>” 界定,包括事件和按鍵等 2~3個部分,它們之間用減號分隔,常見事件代碼見下表:

    事件 事件代碼 備注
    單擊鼠標左鍵 <ButtonPress-1> 可簡寫為<Button-1> 或 <1>
    單擊鼠標中鍵 <ButtonPress-2> 可簡寫為<Button-2> 或 <2>
    單擊鼠標右鍵 <ButtonPress-3> 可簡寫為<Button-3> 或 <3>
    釋放鼠標左鍵 <ButtonRelease-1> ---
    釋放鼠標中鍵 <ButtonRelease-2> ---
    釋放鼠標右鍵 <ButtonRelease-3> ---
    按住鼠標左鍵移動 <B1-Motion> ---
    按住鼠標中鍵移動 <B2-Motion> ---
    按住鼠標右鍵移動 <B3-Motion> ---
    轉動鼠標滾輪 <MouseWheel> ---
    雙擊鼠標左鍵 <Double-Button-1> ---
    鼠標進入控件實例 <Enter> 注意與回車事件的區別
    鼠標離開控件實例 <Leave> ---
    鍵盤任意鍵 <Key> ---
    字母和數字 < Key-字母>,例如<key-a>、<Key-A> 簡寫不帶小于和大于號,例如:a,A和1等
    回車 <Return> <Tab>,<Shift>,<Control>(注意不能用<Ctrl>),<Alt>等類同
    空格 <Space> ---
    方向鍵 <Up> ,<Down>,<Left>,<Right> ---
    功能鍵 <Fn>例如:<F1>等 ---
    組合鍵 鍵名之間以減號鏈接,例如<Control-k>,<Shift-6>,<Alt-Up>等 注意大小寫

    例如,將框架控件實例frame 綁定鼠標右鍵單擊事件,調用自定義函數 myfunc()可表示為"frame.bind('<Button-3>',myfunc)",注意: myfunc后面沒有括號。將控件實例綁定到鍵盤事件和部分光標不落在具體控件實例上的鼠標事件時,還需要設置該實例執行focus_set() 方法獲得焦點,才能對事件持續響應。例如: frame.focus_set()。所調用的自定義函數若需要利用鼠標或鍵盤的響應值,可將event作為參數,通過event的屬性獲取。event的屬性見下表:

    event屬性 意義
    x或y(注意是小寫) 相對于事件綁定控件實例左上角的坐標值(像素)
    root_x或root_y(注意是小寫) 相對于顯示屏幕左上角的坐標值(像素)
    char 可顯示的字符,若按鍵不可顯示,則返回為空字符串
    keysysm 字符或字符型按鍵名,如:“a”或“Escape”
    keysysm_num 按鍵的十進制 ASCII 碼值

    例如:將標簽綁定鍵盤任意鍵觸發事件并獲取焦點,并將按鍵字符顯示在標簽上


    響應鍵盤事件
    from tkinter import *
    
    def show(event):
    s=event.keysym
    lb.config(text=s)
    
    root=Tk()
    root.title('按鍵實驗')
    root.geometry('200x200')
    lb=Label(root,text='請按鍵',font=('黑體',48))
    lb.bind('<Key>',show)
    lb.focus_set()
    lb.pack()
    root.mainloop()
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容