目錄
1.概述tkinter是python的標(biāo)準(zhǔn)GUI庫(kù),用于創(chuàng)建可視界面。
一個(gè)人最簡(jiǎn)單的例子:
也可以設(shè)置窗口的標(biāo)題和屬性
optionDB文件位于當(dāng)前目錄下,內(nèi)容是
*font: SIMHEI 10 bold
表示 黑體,10號(hào)字,加粗顯示;注意末尾應(yīng)該使用換行符
2.Tkinter控件2.1頂層(Toplevel)頂層為其他控件提供容器
from tkinter import * root = Tk() root.title('Toplevel') # 讀取配置文件 root.option_readfile('optionDB') # 主頂層,作為根被引用 Label(root, text="This is the main(default) toplevel").pack(pady=10) # 子頂層,依賴于根,當(dāng)跟被破壞,子頂層也被破壞 t1 = Toplevel(root) Label(t1, text="This is a child of root").pack(padx=10, pady=10) # 臨時(shí)頂層 總是畫(huà)于父頂層頂部,當(dāng)父頂層被圖標(biāo)化或最小化之后,其被隱藏 t2 = Toplevel(root) Label(t2, text="This is a transient window of root").pack(padx=10, pady=10) t2.transient(root) # 設(shè)置窗口邊框?yàn)?0,背景為藍(lán)色 t3 = Toplevel(root, borderwidth=10, bg="blue") # 設(shè)置標(biāo)簽背景藍(lán)色,前景色為白色 Label(t3, text="No wm decorations", bg="blue", fg="white").pack(padx=10, pady=10) # 設(shè)置overrideredirect為非零值,窗口不能被縮放或拖動(dòng) t3.overrideredirect(1) # 窗口大小是300x100,位置為(200,200) t3.geometry("300x100+200+200") root.mainloop() 2.2框架(Frame)框架也是其他控件的容器
例1:顯示不同樣式的框架
from tkinter import * root = Tk() root.title('Frame') # for relief in [RAISED, SUNKEN, FLAT, RIDGE, GROOVE, SOLID]: for relief in ["raised", "sunken", "flat", "ridge", "groove", "solid"]: f = Frame(root, borderwidth=2, relief=relief) Label(f, text=relief, width=10).pack(side=LEFT) f.pack(side=LEFT, padx=5, pady=5) root.mainloop() 例2:顯示不同邊框的不同樣式的框架
from tkinter import * class GUI: def __init__(self): self.root = Tk() self.root.title("Frame Style") # 5種不同的邊框 for bdw in range(5): # of0,of1...of4,表示五個(gè)框架,每個(gè)框架表示一行 setattr(self, "of%d" % bdw, Frame(self.root, borderwidth=0)) # of0,of1...of4每行加入標(biāo)簽控件,文字分別是borderwidth0...borderwidth4,并于顯示在左邊 Label(getattr(self, "of%d" % bdw), text="borderwidth=%d" % bdw).pack(side=LEFT) ifx = 0 for relief in [RAISED, SUNKEN, FLAT, RIDGE, GROOVE, SOLID]: # f0,f1...f4表示每行地方五列 setattr(self, "f%d" % ifx, Frame(getattr(self, "of%d" % bdw), borderwidth=bdw, relief=relief)) # 畫(huà)一行 Label(getattr(self, "f%d" % ifx), text=relief, width=10).pack(side=LEFT) getattr(self, "f%d" % ifx).pack(side=LEFT, padx=7-bdw, pady=5+bdw) ifx = ifx+1 getattr(self, "of%d" % bdw).pack() self.root.mainloop() myGUI = GUI() 例3:框架與按鈕組合使用 from tkinter import * root = Tk() f = Frame(root, width=250, height=110) xf = Frame(f, relief=GROOVE, borderwidth=2) Label(xf, text="You shot him!").pack(pady=10) Button(xf, text="He's dead!", state=DISABLED).pack(side=LEFT, padx=5, pady=8) Button(xf, text="He's completely dead!", command=root.quit).pack(side=RIGHT, padx=5, pady=8) xf.place(relx=0.01, rely=0.125, anchor=NW) Label(f, text="Self-defence against fruit").place(relx=0.06, rely=0.125, anchor=W) f.pack() root.mainloop() 2.3標(biāo)簽(Label)標(biāo)簽可以顯示文字也可以顯示圖形,同時(shí)支持換行
from tkinter import * root = Tk() Label(root, text="stray birds of summer come to my window to sing and fly away." + "And yellow leaves of autumn,which have no songs,flutter and fall there with a sigh.", wraplength=200, justify=LEFT, relief=GROOVE).pack() f = Frame(root) for bitmap, rlf in [("woman", RAISED), ("mensetmanus", SOLID)]: Label(f, bitmap="@pic/%s" % bitmap, relief=rlf).pack(side=LEFT, padx=5) f.pack() root.mainloop() 通過(guò)這種方式讀取圖片,貌似只能讀標(biāo)準(zhǔn)的rc文件
2.4按鈕(Button)嚴(yán)格來(lái)說(shuō),按鈕是對(duì)鼠標(biāo)和鍵盤事件起反應(yīng)的標(biāo)簽。當(dāng)按鈕被點(diǎn)擊的時(shí)候,可以為其綁定一個(gè)回調(diào)函數(shù)
from tkinter import * class GUI: def __init__(self): self.root = Tk() self.root.title("Button Style") for bdw in range(5): setattr(self, "of%d" % bdw, Frame(self.root, borderwidth=0)) Label(getattr(self, "of%d" % bdw), text="borderwidth=%d" % bdw).pack(side=LEFT) fx = 0 for relief in [RAISED, GROOVE, SOLID, FLAT, RIDGE, SUNKEN]: setattr(self, "f%d" % fx, Frame(getattr(self, "of%d" % bdw), borderwidth=bdw, relief=relief)) # Label(getattr(self, "f%d" % fx), text=relief).pack(side=LEFT) Button(getattr(self, "f%d" % fx), text=relief, command=lambda s=self, r=relief, b=bdw: s.prt(r, b)).pack(side=LEFT) getattr(self, "f%d" % fx).pack(side=LEFT, padx=7-bdw, pady=5+bdw) fx = fx + 1 getattr(self, "of%d" % bdw).pack() self.root.mainloop() def prt(self, relief, border): print("%s:%d" % (relief, border)) myGUI = GUI() 這個(gè)程序與框架的第二個(gè)實(shí)例相似。但是按鈕在實(shí)例化的時(shí)候,可以傳入command參數(shù),用于接收一個(gè)回調(diào)函數(shù)。 2.5輸入(Entry)用于收集用戶的輸入
2.6單選按鈕(Radiobutton)實(shí)例1:
實(shí)例2:
from tkinter import * root = Tk() var = IntVar() for value, text in [(0, "apple"), (1, "orange"), (2, "mango"), (3, "banana")]: # 設(shè)置indicatoron=0時(shí),單選按鈕顯示為按鈕框,并且選中的按鈕表示為凹的浮雕 Radiobutton(root, text=text, value=value, variable=var, indicatoron=0).pack(anchor=W, fill=X, ipadx=15) var.set(2) root.mainloop() 2.7復(fù)選按鈕(Checkbutton)例1:
這里要注意的是Checkbutton構(gòu)造函數(shù)沒(méi)有value參數(shù),與單選按鈕的不一樣;不同的復(fù)選按鈕的variable是不同的IntVar類型值
例2:
from tkinter import * class Dummy: pass var = Dummy() root = Tk() root.option_readfile('optionDB') root.title('Checkbutton') for castmember, row, col, status in [ ('John', 0, 0, NORMAL), ('Eric Idle', 0, 1, NORMAL), ('Graham Chapman', 1, 0, DISABLED), ('Terry Jones', 1, 1, NORMAL), ('Michael Palin', 2, 0, NORMAL), ('Terry Gilliam', 2, 1, NORMAL)]: setattr(var, castmember, IntVar()) Checkbutton(root, text=castmember, state=status, anchor=W, variable=getattr(var, castmember)).grid(row=row, column=col, sticky=W) var.John.set(1) getattr(var, "Eric Idle").set(1) root.mainloop() 2.8主菜單(Menubutton)按鈕較為復(fù)雜。所以這里從簡(jiǎn)單到復(fù)雜多寫(xiě)幾個(gè)實(shí)例
2.8.1命令菜單(Command Menu)創(chuàng)建命令菜單的步驟為:
①使用Menubutton創(chuàng)建一個(gè)菜單按鈕
②使用Menu創(chuàng)建一菜單
③使用add_command添加命令菜單項(xiàng)
④將創(chuàng)建的菜單與菜單按鈕關(guān)聯(lián)
例1:
from tkinter import * root = Tk() def new_project(): print("new project") mBar = Frame(root, relief=RAISED, borderwidth=0) mBar.pack(fill=X) fileBtn = Menubutton(mBar, text="button", underline=0) fileBtn.pack(side=LEFT, padx="2m") # 建立菜單項(xiàng) fileBtn.menu = Menu(fileBtn, tearoff=0) # 添加命令菜單 fileBtn.menu.add_command(label="New Project...", command=new_project) fileBtn.menu.add_command(label="New...", underline=0) # 圖片菜單 fileBtn.menu.add_command(bitmap="@pic/RotateLeft") # 添加分割線 fileBtn.menu.add("separator") # 退出command=fileBtn.quit fileBtn.menu.add_command(label="quit", command=root.quit) # 將菜單賦給menubutton fileBtn['menu'] = fileBtn.menu root.mainloop() 2.8.2級(jí)聯(lián)菜單(Cascade Menu)例2: from tkinter import * root = Tk() cascadeBtn = Menubutton(root, text="cascade menubutton") cascadeBtn.pack() # 一級(jí)菜單,以menubutton為根。變量名幾乎是隨便命名的。python類,為一個(gè)不存在的變量賦值,自動(dòng)添加變量 cascadeBtn.menu = Menu(cascadeBtn) # 二級(jí)菜單,以一級(jí)菜單為根 cascadeBtn.menu.choices = Menu(cascadeBtn.menu) # 三級(jí)菜單,以二級(jí)菜單為根 cascadeBtn.menu.choices.vierdones=Menu(cascadeBtn.menu.choices) # 為三級(jí)菜單添加命令 cascadeBtn.menu.choices.vierdones.add_command(label="CRLF-Windows") cascadeBtn.menu.choices.vierdones.add_command(label="LF-Unix and macOS") cascadeBtn.menu.choices.vierdones.add_command(label="CR-Classic macOS") # 為二級(jí)菜單添加命令 cascadeBtn.menu.choices.add_command(label="File Encoding") cascadeBtn.menu.choices.add_command(label="Remove BOM") cascadeBtn.menu.choices.add_command(label="Associate with File Type...") cascadeBtn.menu.choices.add_command(label="Make File Read-Only") # 為二級(jí)菜單的一項(xiàng)命令關(guān)聯(lián)三級(jí)菜單 cascadeBtn.menu.choices.add_cascade(label="Line Separators", menu=cascadeBtn.menu.choices.vierdones) # 一級(jí)菜單設(shè)置 cascadeBtn.menu.add_cascade(label="File Properties", menu=cascadeBtn.menu.choices) # 將一級(jí)菜單關(guān)聯(lián)到menubutton上 cascadeBtn["menu"] = cascadeBtn.menu root.mainloop() 2.8.3其他菜單復(fù)選菜單(Checkbutton Menu),單選菜單(Radiobutton Menu)和禁用菜單(Disable Menu)
from tkinter import * root = Tk() menuBtn = Menubutton(root, text="menubutton") menuBtn.pack() m1 = Menu(menuBtn) m1.add_command(label="apple") # 多選菜單,可以同時(shí)選中多個(gè) m1.add_checkbutton(label="pear") m1.add_checkbutton(label="watermelon") # 將pear設(shè)置為選中 m1.invoke(m1.index("pear")) # 單選菜單,只能同時(shí)選中一個(gè) m1.add_radiobutton(label="lemon") m1.add_radiobutton(label="orange") m1.invoke(m1.index("orange")) # 禁用菜單 m1.add_command(label="durian", state=DISABLED) # 關(guān)聯(lián)進(jìn)menubutton menuBtn["menu"] = m1 root.mainloop() 2.9消息(Message)用于顯示多行文本
from tkinter import * root = Tk() Message(root, text="He wishes for the cloths of heaven" "Had I the heaven's embroidered cloths," "Enwrought with golden and silver light," "The blue and the dim and the dark cloths," "I would spread the cloths under your feat:" "But I,being poor,have only my dreams;" "I have spread my dreams under your feet;" "Tread softly because you tread on my dreams.", bg="royalblue", fg="ivory", relief=GROOVE).pack(padx=10, pady=10) root.mainloop() 可以加\n換行符給文本換行
2.10文本(Text)文本控件提供格式化的文本顯示。 例1: from tkinter import * root = Tk() # 這里的寬和高并不是像素,而是用當(dāng)前字體的字符個(gè)數(shù)來(lái)測(cè)量 text = Text(root, height=20, width=70) # 插入文字 # 在文尾插入文字 text.insert(END, "Something up with my banter,chaps?\n") # 在第一行,第一列插入文字 text.insert(1.0, "Four hours to bury a cat?\n") # text.insert(2.1, "Can i call you 'Frank'?\n") # 當(dāng)前位置插入 text.insert(CURRENT, "Can i call you 'Frank'?\n") # 設(shè)置標(biāo)簽 text.tag_config("bold_italics", font=("verdana", 12, "bold", "italic")) text.insert("3.0", "What's happening Thursday then?\n", "bold_italics") # 插入按鈕 # 定義一個(gè)按鈕 button = Button(text, text="I do live at 46 Horton terrace") # 創(chuàng)建窗口放置按鈕 text.window_create(END, window=button) # 插入圖片 # 創(chuàng)建圖片對(duì)象。這個(gè)完全不行,一般的圖片都加載不了。所以用到第三方庫(kù)PIL # photo = PhotoImage(file="pic/lumber.gif") # text.image_create(END, image=photo) # 使用PIL庫(kù)加載圖片 from PIL import Image, ImageTk img = Image.open("pic/tree.gif") # 縮放一下 img = img.resize((100, 100)) photo = ImageTk.PhotoImage(img) text.image_create(CURRENT, image=photo) # 綁定事件 # 創(chuàng)建事件標(biāo)簽 text.tag_bind("bite", "<1>", lambda e, t=text: t.insert(END, "I'll bite your legs off!")) text.insert(END, "I dare you to click on this\n", "bite") text.pack() root.mainloop() 例2: import tkinter.filedialog import tkinter.messagebox from tkinter import * root = Tk() # 打開(kāi)文件 def open_file(): filename = tkinter.filedialog.askopenfilename(defaultextension=".txt", initialdir="f:") print(filename) root.title(filename) with open(filename, "r") as f: try: # 先清空,再寫(xiě)入 text.delete(1.0, END) text.insert(1.0, f.read()) set_style(text) except: tkinter.messagebox.showwarning("warning", "fail to open a file") def set_style(t): # 返回指定位置字符的左上角坐標(biāo)和寬高,單位為像素 x, y, w, h = t.bbox(3.2) print(x, y, w, h) # 菜單設(shè)置 frame = Frame(root, relief="solid") frame.pack(fill=X) fileBtn = Menubutton(frame, text="File") fileBtn.pack(side=LEFT) fileBtn.menu = Menu(fileBtn, tearoff=0) fileBtn.menu.add_command(label="open...", command=open_file) fileBtn.menu.add("separator") fileBtn.menu.add_command(label="quit", command=root.quit) fileBtn["menu"] = fileBtn.menu # 文本處理 text = Text(root, height=20, width=70) text.pack() root.mainloop() 2.11畫(huà)布(Canvas)http://www.cnblogs.com/vocus/p/11470707.html 2.12列表框(ListBox)
補(bǔ)充: # 選中第二個(gè)值,可以多選一個(gè)區(qū)間 ls.selection_set(1,) # 點(diǎn)擊事件 def print_c(event): print(ls.curselection()) print(ls.get(ls.curselection())) ls.bind("<1>", print_c) 2.13滾動(dòng)條(Scrollbar)滾動(dòng)條能被加到任何支持滾動(dòng),如文本、畫(huà)布和列表框控件上
from tkinter import * root = Tk() ls = Listbox(root, height=6, width=15) # 創(chuàng)建滾動(dòng)條對(duì)象,并且設(shè)置滾動(dòng)與列表框y軸關(guān)聯(lián) scroll = Scrollbar(root, command=ls.yview) # 配置列表框y軸滾動(dòng)屬性,指定其回調(diào)函數(shù)為scroll.set ls.configure(yscrollcommand=scroll.set) ls.pack(side=LEFT) scroll.pack(side=RIGHT, fill=Y) for item in range(30): ls.insert(END, item) root.mainloop() 2.14標(biāo)尺(Scale)from tkinter import * # 通過(guò)修改矩形和三角形(合成一個(gè)向下的箭頭)來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果 def set_height(c, hstr): h = int(hstr) print(h) if h > 210: h = 210 # 修改三角形的坐標(biāo) c.coords("poly", 0, 30+h, 40, 30+h, 20, 40+h) # 修改矩形的坐標(biāo) c.coords("rectangle", 10, 30+h, 10, 0, 30, 0, 30, 30+h, 10, 30+h) root = Tk() canvas = Canvas(root, height=250, width=40, highlightthickness=0) canvas.grid(row=0, column=1, sticky="WN") # 不分成兩部分更好 # poly_point = [(10, 0), (30, 0), (30, 30), (40, 30), (20, 40), (0, 30), (10, 30)] # canvas.create_polygon(poly_point, fill="cadetblue") # 動(dòng)態(tài)效果,通過(guò)canvas.coords修改坐標(biāo)項(xiàng)實(shí)現(xiàn)動(dòng)態(tài)效果,初始化是一個(gè)三角形和一個(gè)矩形。 canvas.create_polygon(0, 30, 40, 30, 20, 40, fill="cadetblue", tags="poly") canvas.create_polygon(10, 30, 10, 0, 30, 0, 30, 30, 10, 30, fill="cadetblue", tags="rectangle") scale = Scale(root, orient=VERTICAL, length=284, from_=0, to=250, tickinterval=50, # scale內(nèi)部似乎維護(hù)了一個(gè)變量h,即為標(biāo)尺滑動(dòng)的高度 command=lambda h, c=canvas: set_height(c, h)) scale.grid(row=0, column=0, sticky="NE") root.mainloop() 3.Pmw大控件Pmw大控件是以Tkinter為基類合成的控件
3.1關(guān)于對(duì)話框(Pmw.AboutDialog)# 導(dǎo)入大控件庫(kù) import Pmw from tkinter import * root = Tk() # 關(guān)于版本 Pmw.aboutversion("1.5") # 關(guān)于版權(quán) Pmw.aboutcopyright("Copyright Company Name 1999\nAll rights reserved") # 關(guān)于聯(lián)系方式 Pmw.aboutcontact( "For information about this application contact:\n" + "Sales at Company Name\n" + "Phone...\n" + "email..." ) # 創(chuàng)建關(guān)于對(duì)話框 about = Pmw.AboutDialog(root, applicationname="this application") root.mainloop() 可以看出創(chuàng)建一個(gè)關(guān)于對(duì)話框很簡(jiǎn)單,但是顯示效果見(jiàn)仁見(jiàn)智。
3.2輸入域(Pmw.EntryField)輸入域包含一個(gè)label和一個(gè)輸入框控件。同時(shí)可以檢查輸入框控件里的內(nèi)容格式
例1:
import Pmw from tkinter import * root = Tk() # labelpos指label的現(xiàn)實(shí)位置北,南,東,西分別為N,S,E,W,label_text標(biāo)簽文字 Pmw.EntryField(root, labelpos=W, label_text="username").pack(padx=10, pady=5) Pmw.EntryField(root, labelpos=W, label_text="password").pack(padx=10, pady=5) Button(root, text="Login").pack() root.mainloop() 做一個(gè)登錄框界面很方便
例2:
import Pmw from tkinter import * root = Tk() # 建議初始化一下,也可以不用 Pmw.initialise() # 只能輸入a~z和A~Z,使用標(biāo)識(shí)alphabetic,min表示最小長(zhǎng)度,max表示最大長(zhǎng)度;minstrict設(shè)置為false,表示不檢查最小輸入,maxstrict表示不檢查最大輸入 user = Pmw.EntryField(root, labelpos=W, label_text="username", value="user", validate={"validator": "alphabetic", "min": 5, "max": 10, "minstrict": 0}) # 只能輸入數(shù)字+字母組合,使用alphanumeric標(biāo)識(shí) pwd = Pmw.EntryField(root, labelpos=W, label_text="password", value="pwd", validate={"validator": "alphanumeric", "min": 5, "max": 10, "minstrict": 0}) # 只能輸入數(shù)字,可以使用numeric標(biāo)識(shí) lucky = Pmw.EntryField(root, labelpos=W, label_text="lucky", value="21", validate={"validator": "numeric", "min": 0, "max": 100}) # 只能輸入指定格式日期,時(shí)間格式貌似只能是2010/1/1 birthday = Pmw.EntryField(root, labelpos=W, label_text="birthday", value="1900/1/1", validate={"validator": "date", "min": "1900/1/1", "max": "2020/1/1"}) # 不檢查格式 sign = Pmw.EntryField(root, labelpos=W, label_text="signature", value="no limitation", validate=None) widgets = (user, pwd, lucky, birthday, sign) for widget in widgets: widget.pack(fill=X, expand=1, padx=10, pady=5) # 使控件對(duì)齊 Pmw.alignlabels(widgets) # 使密碼輸入框獲得輸入焦點(diǎn) # sign.component("entry").focus_set() Button(root, text="Login").pack() root.mainloop() 備注,使用validate設(shè)置輸入內(nèi)容格式,接收的參數(shù)為一個(gè)字典,固定格式如下:
{“validator": "real", "max":0, "min":0, "minstrict": "0"}
其中,validator鍵的值可設(shè)置為:
'numeric'
An integer greater than or equal to 0. Digits only. No sign. 'integer' Any integer (negative, 0 or positive) as accepted by string.atol(). 'hexadecimal' Hex number (with optional leading '0x'), as accepted by string.atol(text, 16). 'real' A number, with or without a decimal point and optional exponent (e or E), as accepted by string.atof(). This validator accepts a 'separator' argument, which specifies the character used to represent the decimal point. The default 'separator' is '.'. 'alphabetic' Consisting of the letters 'a-z' and 'A-Z'. In this case, 'min' and 'max' specify limits on the length of the text. 'alphanumeric' Consisting of the letters 'a-z', 'A-Z' and '0-9'. In this case, 'min' and 'max' specify limits on the length of the text. 'time' Hours, minutes and seconds, in the format 'HH:MM:SS', as accepted by Pmw.timestringtoseconds(). This validator accepts a 'separator' argument, which specifies the character used to separate the three fields. The default separator is ':'. The time may be negative. 'date' Day, month and year, as accepted by Pmw.datestringtojdn(). This validator accepts a 'separator' argument, which specifies the character used to separate the three fields. The default is ':'. This validator also accepts a 'format' argument, which is passed to Pmw.datestringtojdn() to specify the desired ordering of the fields. The default is 'ymd'. 例3:
也可以自定義輸入條件
import Pmw from tkinter import * root = Tk() class Demo: def __init__(self, parent): self._real = Pmw.EntryField(parent, labelpos=W, label_text="score", value=10, validate={"validator": "real", "min": 0, "max": 99, "minstrict": 0}) self._color = Pmw.EntryField(parent, labelpos=W, label_text="color", value="#bbbbbb", validate=self.custom_validate) def show(self): self._real.pack() self._color.pack() # 檢查輸入是#六位顏色值,算法應(yīng)該可以優(yōu)化 def custom_validate(self, text): print(text) if len(text) is not 7 or text[0] != "#": return -1 temp = text[1:7] for i in temp: if (i < '0' or i > '9') and (i < 'a' or i > 'f') and (i < 'A' or i > 'F'): return -1 return 1 myDemo = Demo(root) myDemo.show() root.mainloop() 在這里自定義了一個(gè)函數(shù),用于檢查輸入的文本是#加上六位顏色值
3.2浮動(dòng)圖(Pmw.Balloon)import Pmw from tkinter import * root = Tk() balloon = Pmw.Balloon(root) field = Pmw.EntryField(root, labelpos="w", label_text="Input") field.setentry("your name") field.pack() balloon.bind(field, "please input your name", "msg") root.mainloop() 3.3按鈕框(Pmw.ButtonBox)import Pmw from tkinter import * root = Tk() def button_press(text): print(text) def default_key(event): buttonBox.invoke() buttonBox = Pmw.ButtonBox(root, labelpos=NW, label_text="button box") buttonBox.pack() buttonBox.add("Ok", command=lambda text="ok": button_press(text)) buttonBox.add("Cancel", command=lambda text="cancel": button_press(text)) # 設(shè)置獲得焦點(diǎn)按鈕 buttonBox.setdefault("Cancel") # 事件綁定,回車鍵 root.bind("<Return>", default_key) # root.focus_set() # 到目前為止,我理解它是用于排版 buttonBox.alignbuttons() root.mainloop() 3.4組合框(Pmw.ComboBox)import Pmw from tkinter import * root = Tk() toplevel = Toplevel(root) toplevel.title("play") toplevel.geometry("200x50+200+200") label = Label(toplevel, bg="#fff", fg="blue") label.pack(fill=X, pady=15) # 隱藏頂層窗口 toplevel.withdraw() toplevel.update() def chose_entry(entry): print("you chose %s" % entry) # 更新顯示頂層窗口 toplevel.deiconify() toplevel.update() label.configure(text=entry) music_list = ["sound of silence", "hero", "break free", "halo"] # label_text去掉就是簡(jiǎn)單的列表框,selectioncommand,listbox_width列表框?qū)挾?,selectioncommand列表點(diǎn)擊事件,scrolllist_items列表數(shù)據(jù),dropdown=0列表不隱藏 comboBox = Pmw.ComboBox(root, labelpos=NW, label_text="Music List", listbox_width=24, selectioncommand=chose_entry, scrolledlist_items=music_list, dropdown=0) comboBox.pack() root.mainloop() 這個(gè)關(guān)閉topleve窗口之后,就無(wú)法調(diào)用topleve.deiconify來(lái)顯示了,程序會(huì)報(bào)錯(cuò)。
3.5組合對(duì)話框(Pmw.ComboBoxDialog)import Pmw from tkinter import * root = Tk() musicList = ["just one last dance", "from sarah with love", "stronger"] # selectioncommand屬性被去掉了貌似,可以通過(guò)comboBoxDialog.get()獲得列表選擇 comboBoxDialog = Pmw.ComboBoxDialog(root, combobox_labelpos=W, label_text="play", scrolledlist_items=musicList, listbox_width=25, buttons=("OK", "Cancel"), defaultbutton="Ok") # 可有可無(wú) # comboBoxDialog.pack() # 獲得按鈕點(diǎn)擊選擇 result = comboBoxDialog.activate() choice = comboBoxDialog.get() print("%s,%s" % (result, choice)) root.mainloop() 3.6對(duì)話框(Pmw.Dialog)import Pmw from tkinter import * root = Tk() def default_key(result): print(result) # 對(duì)話框退不出也是一個(gè)問(wèn)題了,只能關(guān)閉主窗口? if result == "Cancel": # root.quit() root.destroy() # 點(diǎn)擊關(guān)閉按鈕的時(shí)候result是None if result is None: root.destroy() dialog = Pmw.Dialog(root, title="dialog", buttons=("Ok", "Cancel"), defaultbutton="Cancel", command=lambda result: default_key(result)) # interior()方法返回對(duì)話框子域 label = Label(dialog.interior(), text="Pmw Dialog\n Bring out your dead!", bg="black", foreground="white", pady=20) label.pack() root.bind("<Return>", default_key) dialog.activate() root.mainloop() 關(guān)不掉對(duì)話框可以試著加上deactivate() 3.7計(jì)數(shù)器(Pmw.Counter)https://www.cnblogs.com/vocus/p/11563263.html import Pmw from tkinter import * root = Tk() counter = Pmw.Counter(root) counter.grid(row=0, column=1) # 設(shè)置初始值 counter.setentry(2) # +1 counter.increment() # +1 counter.increment() # -1 counter.decrement() # datatype數(shù)據(jù)類型,time表示設(shè)置成時(shí)間格式00:00:00,buttonaspect用于設(shè)置箭頭大小,缺省是1.0,orient表示箭頭所在位置 counter1 = Pmw.Counter(datatype="time", increment=60, buttonaspect=2.0, orient=VERTICAL) counter1.grid(row=1, column=1) counter1.setentry("01:00:00") # 獲得值 print("entry:%s" % counter1.get()) print("increment:%s" % counter1.cget("increment")) print("increment:%s" % counter1.cget("buttonaspect")) print(counter1.configure("increment")) counter3 = Pmw.Counter(root, pady=20, padx=20) counter3.grid(row=2, column=1) # 配置部件屬性,使用configure # 改變箭頭北京顏色,以及箭頭顏色。entry_foreground非官方文檔的作法,這樣改變之后,輸入框文本也變色了 counter3.configure(downarrow_background="#3c3f41", uparrow_background="#3c3f41", entry_foreground="#c75450") # 改變輸入域背景色,前景色改變之后,箭頭的顏色也改變了 counter3.configure(entryfield_entry_background="#3c3f41", entryfield_entry_foreground="#a73e28") counter3.setentry(99) root.mainloop() 3.8計(jì)數(shù)對(duì)話框(Pmw.CounterDialog)這個(gè)是繼承自Pmw.dialog,所以具有一些dialog和counter的屬性,可以試試 import Pmw from tkinter import * root = Tk() # CounterDialog cd = Pmw.CounterDialog(root, buttons=("Ok", "Cancel"), defaultbutton="Cancel") cd.setentry("3") num = cd.get() result = cd.activate() print(num, result) root.mainloop() 3.9組(Pmw.Group)import Pmw from tkinter import * root = Tk() group = Pmw.Group(root, tag_text="group", tag_foreground="blue", tag_pyclass=Checkbutton) group.pack(fill=X) label = Label(group.interior(), text="apple") label.pack() root.mainloop() 3.10標(biāo)簽控件(Pwm.Labeledwidget)import Pmw from tkinter import * root = Tk() labelWidget = Pmw.LabeledWidget(root, labelpos=N, label_text="Image Show") # hull指整個(gè)大控件本體 labelWidget.component("hull").configure(borderwidth=3, relief=SUNKEN) labelWidget.pack(padx=10, pady=10) # 加載圖片 from PIL import Image, ImageTk img = Image.open("pic/rose.jpg") photo = ImageTk.PhotoImage(img) btn = Button(labelWidget.interior(), bg="yellow", image=photo) btn.pack(padx=10, ipady=10, fill="both", expand=1) root.mainloop() 3.11消息對(duì)話(Pmw.MessageDialog)import Pmw from tkinter import * root = Tk() md = Pmw.MessageDialog(root, title="Message Dialog", buttons=("apple", "banana", "pear", "lemon"), message_text="choose your favourite fruit") # md.iconname("Simple message dialog") result = md.activate() print(result) root.mainloop() 這個(gè)跟ButtonBox很像,不過(guò)區(qū)別也許是Button和Dialog的區(qū)別吧
3.12消息欄(Pmw.MessageBar)???????????ScrolledListBox
3.13菜單條(Pmw.MenuBar)比tkinter的原生Menu組件更容易創(chuàng)建菜單,同時(shí)還可以直接添加浮動(dòng)幫助功能
import Pmw from tkinter import * root = Tk() balloon = Pmw.Balloon(root) # hull_relief,hull_borderwidth menuBar = Pmw.MenuBar(root, hull_relief=RAISED, hull_borderwidth=1, balloon=balloon) menuBar.pack() # 添加菜單,第一個(gè)參數(shù)菜單名,第二個(gè)參數(shù)是浮動(dòng)內(nèi)容 menuBar.addmenu("Buttons", "Simple Commands") # 第一個(gè)參數(shù)菜單名,第二個(gè)參數(shù)文檔寫(xiě)的是浮動(dòng)幫助信息,但是這里看來(lái)是item類型,第三個(gè)參數(shù)狀態(tài)欄幫助信息,font用于設(shè)置字體,label設(shè)置文本 menuBar.addmenuitem("Buttons", "command", "Close this window", font=("StringerLight", 14), label="Close") from PIL import Image, ImageTk img = Image.open("pic/apple.jpg") img = img.resize((30, 30)) photo = ImageTk.PhotoImage(img) # 古老的程序喜歡用bitmap menuBar.addmenuitem("Buttons", "command", "Close this window", image=photo) # 添加分割線 menuBar.addmenuitem('Buttons', 'separator') # 普通的命令菜單項(xiàng) menuBar.addmenuitem('Buttons', 'command', 'Exit the application', label='Exit') # 添加一個(gè)菜單 menuBar.addmenu("Cascade", "Cascading Menus") # 添加一項(xiàng)級(jí)聯(lián)菜單,注意第二個(gè)參數(shù)為自定義的該級(jí)聯(lián)菜單的名稱標(biāo)識(shí) menuBar.addcascademenu("Cascade", "Submenu", "unknown", label="cascade") # 在級(jí)聯(lián)菜單下加入一個(gè)菜單項(xiàng)項(xiàng) menuBar.addmenuitem("Submenu", "command", "unknown", label="normal") # 添加一個(gè)radiobutton風(fēng)格菜單項(xiàng) menuBar.addmenuitem("Cascade", "radiobutton", "unknown", label="simple") root.mainloop() 3.14選項(xiàng)菜單(Pmw.OptionMenu)簡(jiǎn)單實(shí)現(xiàn)彈出式菜單
這個(gè)效果可以說(shuō)是很奇葩了
3.15記事本(Pmw.NoteBook)老的版本可以使用NoteBookR和NoteBookS創(chuàng)建記事本,但是在教新(?)版本里,已經(jīng)被廢棄了。取而代之的是NoteBook
另外,這里還有點(diǎn)問(wèn)題,可能是Pmw版本的問(wèn)題,運(yùn)行《Python與Tkinter編程》隨書(shū)源碼的時(shí)候會(huì)出錯(cuò),源碼如下(我加了一些注釋):
from tkinter import * import Pmw root = Tk() # root.option_readfile('optionDB') root.title('Notebook') # Pmw.initialise() # 創(chuàng)建三個(gè)頁(yè)面,并設(shè)置標(biāo)題 nb = Pmw.NoteBook(root) p1 = nb.add('Page 1') p2 = nb.add('Page 2') p3 = nb.add('Page 3') nb.pack(padx=5, pady=5, fill=BOTH, expand=1) # 第一個(gè)顯示一個(gè)button Button(p1, text='This is text on page 1', fg='blue').pack(pady=40) # 第二頁(yè)畫(huà)個(gè)圖 c = Canvas(p2, bg='gray30') # 窗口寬高 w = c.winfo_reqwidth() h = c.winfo_reqheight() # 畫(huà)一個(gè)橢圓 c.create_oval(10, 10, w-10, h-10, fill='DeepSkyBlue1') # 文字 c.create_text(w/2, h/2, text='This is text on a canvas', fill='white', font=('Verdana', 14, 'bold')) c.pack(fill=BOTH, expand=1) # setnaturalpagesize 變?yōu)閟etnaturalsize # nb.setnaturalpagesize() nb.setnaturalsize() root.mainloop() 第一個(gè)報(bào)錯(cuò):
在實(shí)例化的時(shí)候,就報(bào)錯(cuò)了,提示
...'#%04x%04x%04x' % (lightRGB[0], lightRGB[1], lightRGB[2]),
TypeError: %x format: an integer is required, not float 找到報(bào)錯(cuò)的代碼行,是在PmwColor.py文件的這段代碼:
def bordercolors(root, colorName):
.... return (
'#%04x%04x%04x' % (lightRGB[0], lightRGB[1], lightRGB[2]), '#%04x%04x%04x' % (darkRGB[0], darkRGB[1], darkRGB[2]) ) 解決辦法很簡(jiǎn)單,只要把float轉(zhuǎn)換成int輸出就好了:
return (
'#%04x%04x%04x' % (int(lightRGB[0]), int(lightRGB[1]), int(lightRGB[2])), '#%04x%04x%04x' % (int(darkRGB[0]), int(darkRGB[1]), int(darkRGB[2])) ) 第二個(gè)報(bào)錯(cuò)是
AttributeError: 'NoteBook' object has no attribute 'setnaturalpagesize'
把setnaturalpagesize 修改為setnaturalsize
這個(gè)函數(shù)可以自動(dòng)調(diào)節(jié)Notebook的大小,而且應(yīng)該放在代碼的末尾處
3.16窗格控件(Pmw.PanedWidget)這個(gè)效果也是有點(diǎn)奇葩
中間有一條可調(diào)整上下兩部分pane的分割線
from tkinter import * import Pmw root = Tk() # 創(chuàng)建一個(gè)pane pane = Pmw.PanedWidget(root, hull_width=300, hull_height=200) pane.pack() # 添加top和bottom兩個(gè)部分,最下值為100 pane.add("top", min=100) pane.add("bottom", min=100) # pane.pane("top")取的上半部分pane的索引,HORIZONTAL,在橫向上劃分 topPane = Pmw.PanedWidget(pane.pane("top"), orient=HORIZONTAL) topPane.pack() # 0~1之間的浮點(diǎn)數(shù)表示的應(yīng)該是占半分比 topPane.add("apple", min=.2) topPane.add("pear", min=.2) btn1 = Button(topPane.pane("apple"), text="apple") btn2 = Button(topPane.pane("pear"), text="pear") btn1.pack() btn2.pack() root.mainloop() 3.17提示對(duì)話框(Pmw.PromptDialog)一個(gè)對(duì)話框加一個(gè)EntryField
from tkinter import * import Pmw root = Tk() def print_c(choice): print(choice) promptDlg = Pmw.PromptDialog(root, title="PASSWORD", entryfield_labelpos=N, label_text="password", # command=print_c entry_show="*", buttons=("Ok", "Cancel")) promptDlg.pack() result = promptDlg.activate() print(result) root.mainloop() 3.18單選選項(xiàng)(Pmw.RadioSelect) from tkinter import * import Pmw root = Tk() def print_c(*args): print(args) # selectmode=MULTIPLE表示可以多選 rs = Pmw.RadioSelect(root, labelpos=W, label_text="fruit", frame_borderwidth=3, frame_relief=RIDGE, command=print_c, selectmode=MULTIPLE) rs.pack() for text in ("apple", "pear", "banana", "lemon", "melon", "peach"): rs.add(text) # 默認(rèn)選擇 rs.invoke("apple") root.mainloop() 3.18單選選項(xiàng)(Pmw.RadioSelect)def print_c(*args): print(args) # selectmode=MULTIPLE表示可以多選 rs = Pmw.RadioSelect(root, labelpos=W, label_text="fruit", frame_borderwidth=3, frame_relief=RIDGE, command=print_c, selectmode=MULTIPLE) rs.pack() for text in ("apple", "pear", "banana", "lemon", "melon", "peach"): rs.add(text) # 默認(rèn)選擇 rs.invoke("apple") 3.19文本對(duì)話框(Pmw.TextDialog)
from tkinter import * import Pmw root = Tk() discuss = """Jack:Nice to meet you! Bruce:Nice to meet you,too! """ textDialog = Pmw.TextDialog(root, scrolledtext_labelpos=N, label_text="discuss", title="TextDialog", defaultbutton=0) textDialog.pack() textDialog.insert(END, discuss) textDialog.configure(text_state=DISABLED) # textDialog.activate() textDialog.tkraise() root.mainloop()
3.20時(shí)間計(jì)數(shù)(Pmw.TimeCounter)from tkinter import * import Pmw root = Tk() tc = Pmw.TimeCounter(root, labelpos=W, label_text="Time Counter", min="00:00:00", max="23:59:59") tc.pack() root.mainloop() 運(yùn)行一下,它直接獲得系統(tǒng)的時(shí)間填入
3.21滾動(dòng)畫(huà)布(Pmw.ScrolledCanvas)這里先弄清一個(gè)東西,用canvas畫(huà)圖的時(shí)候,默認(rèn)是以像素作為單位的,除此之外,還可以使用c作為單位。因?yàn)檎也坏絽⒖嘉臋n,所以我猜測(cè)c是厘米吧,因?yàn)槔迕资莄m;例外我試了一下也可以使用m做單位,1m剛好是1c的十分之一,所以我猜測(cè)是毫米?比如:
from tkinter import * import Pmw root = Tk() # borderframe框架是否有邊界,設(shè)置為True或False;usehullsize,如果設(shè)為True則大控件的大小只由主體組件覺(jué)得,否則由其他組件一起決定; sc = Pmw.ScrolledCanvas(root, borderframe=1, labelpos=N, label_text="ScrolledCanvas", usehullsize=1, hull_width="400", hull_height="300") sc.pack() # 畫(huà)30x10個(gè),矩形寬高為2c*2c,矩形之間間隔為1c for i in range(30): x = -10 + 3*i y = -10 for j in range(10): # 畫(huà)矩形 sc.create_rectangle("%dc" % x, "%dc" % y, "%dc" % (x+2), "%dc" % (y+2), fill="gold1") # 畫(huà)文字 sc.create_text("%dc" % (x+1), "%dc" % (y+1), text="(%d, %d)" % (i, j), fill="indianred1") y = y+3 # 加了這句才會(huì)添加滾動(dòng) sc.resizescrollregion() root.mainloop() 3.22滾動(dòng)區(qū)域(Pmw.ScrolledField)from tkinter import * import Pmw root = Tk() sf = Pmw.ScrolledField(root, label_text="Scrolled Field", labelpos=N, entry_width=20) # 設(shè)置輸入域文本 sf.configure(text="Tom eats an apple") sf.pack() text = ["Jerry broke a glass", "Hannah is swimming", "Pony is a pony"] index = 0 def scroll(): global index # sf.configure(text=text[index]) # 取余 sf.configure(text=text[index % len(text)]) index = index+1 ''' if index == len(text): index = 0 ''' btn = Button(root, text="scroll it", command=scroll) btn.pack() root.mainloop() 這也不是自動(dòng)滾動(dòng)什么的?還是因?yàn)槲沂鞘髽?biāo)壞掉了?
3.23滾動(dòng)框架(Pmw.ScrolledFrame)寫(xiě)個(gè)九九乘法表
from tkinter import * import Pmw root = Tk() from tkinter.dialog import * import tkinter.messagebox as msg def calc(a, b): # dlg = Pmw.Dialog(root, buttons=("Ok",), defaultbutton="Ok") # Label(dlg.interior(), text="%d" % (a*b)).pack() Dialog(None, title="answer", text="%d" % (a*b), strings=("Ok",), default=0, bitmap=DIALOG_ICON) # msg.showinfo("answer", "%d" % (a*b)) sf = Pmw.ScrolledFrame(root, labelpos=N, label_text="Scrolled Frame", hull_width=300, hull_height=200, usehullsize=1, borderframe=1) f = sf.interior() sf.pack() for i in range(9): fm = Frame(f) fm.pack(anchor=NW) y = i+1 for j in range(y): btn = Button(fm, text="%d x %d" % (i+1, j+1), bg="moccasin", borderwidth=1, command=lambda a=i+1, b=j+1: calc(a, b)) btn.pack(side=LEFT) sf.component("frame").configure(bg="linen") root.mainloop() 3.24滾動(dòng)列表框(Pmw.ScrolledListBox)from tkinter import * import Pmw root = Tk() def double_click(): items = slb.getcurselection() if len(items) == 0: print("have no select item") else: print(items[0]) print() # selectioncommand點(diǎn)擊事件,dblclickcommand雙擊事件,usehullsize=True大小由主體組件決定, # vscrollmode="static"顯示垂直滾動(dòng)條,并且總是顯示,listbox_selectmode設(shè)置單選或多選 slb = Pmw.ScrolledListBox(root, labelpos=N, label_text="Scrolled Listbox", items=("rose", "jasmine", "lily", "chrysanthemums", "sakura", "orchid"), dblclickcommand=double_click, hull_width=200, hull_height=150, usehullsize=1, vscrollmode="static", listbox_selectmode=MULTIPLE) slb.pack() root.mainloop() 3.25滾動(dòng)文本(Pmw.ScrolledText)from tkinter import * import Pmw root = Tk() # text_wrap="none"不自動(dòng)換行 st = Pmw.ScrolledText(root, borderframe=1, hull_width=400, hull_height=300, usehullsize=1, labelpos=N, label_text="Scroll text", text_pady=5, text_padx=10, text_wrap="none", vscrollmode="static") st.pack() st.importfile("he Falling Of the Leaves.txt") root.mainloop() 3.26選項(xiàng)對(duì)話(Pwm.SelectionDialog)from tkinter import * import Pmw root = Tk() def get_item(result): c = sdlg.getcurselection() # c是個(gè)元組,判斷一下它的長(zhǎng)度,這里略了 print(c[0]) print(result) # 注意deactivate和activate sdlg.deactivate(result) sdlg = Pmw.SelectionDialog(root, title="SelectionDialog", scrolledlist_items=("tree", "grass", "flower", "bird", "cloud", "wind"), scrolledlist_labelpos=N, label_text="nature", buttons=("ok", "cancel"), defaultbutton="ok", command=get_item) sdlg.activate() root.mainloop()
John E Grayson Python與Tkinter編程 |
|
來(lái)自: Bookroom for ... > 《編程》