这一节记录的是我在使用python tkinter时的一些笔记。
背景:现在需要构建一个简易的聊天工具,说简易是因为确实只需要很简单的几个界面,包括一个登陆界面、一个好友列表和单击好友时弹出好友对话框可以交谈,我们这里只需要创建简单的界面(不包括业务),所以选择用tkinter这个模块来实现。
要点一、神马是tkinter?
Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口.Tk和Tkinter可以在大多数的Unix平台下使用,同样可以应用在Windows和Macintosh系统里.,Tk8.0的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中.(摘自百度百科)想要查看你的Tkinter版本,只需要在python命令行模式下输入print Tkinter.TkVersion即可,笔者的版本是8.5。
要点二、安装
一般情况下,安装python时,自带安装了Tkinter,并且与python的版本相对应,例如python2.7.3对应的应该是8.5版本,其余的我倒不是很熟悉。但有些预安装的python可能没有带上tkinter,例如我在虚拟机Fedora17上的python并没有自带tkinter,这时候解决办法是使用yum install tkinter命令即可。
要点三、登陆框
View Code
1 #-*- coding: utf-8 -*-
2 importTkinter3 from Tkinter import *
4 from multiprocessing importProcess,Pipe5 classLogin:6 def __init__(self,master,con):7 self.con = con#pipe connection
8 self.parent = master#Tk实例,父容器
9 self.username = ""
10 self.password=""
11 master.protocol("WM_DELETE_WINDOW", self.cancel)#绑定关闭按钮到cancel函数
12 self.__layout__(master)13
14 pass
15
16 #布局
17 def __layout__(self,master):18 master.geometry("320x150+400+100")#窗口大小及坐标
19 master.title("腾Q登陆框")20
21 row1 =Frame(master)22 row1.pack(padx=10,pady=15)23 Label(row1,width=8,text="用户名:",anchor=W).pack(side=LEFT)24 self.en_user =Entry(row1)25 self.en_user.pack(side=LEFT)26
27 row2 =Frame(master)28 row2.pack(padx=10,pady=0)29 Label(row2,width=8,text="密码:",anchor=W).pack(side=LEFT)30 self.en_pswd = Entry(row2,show="*")31 self.en_pswd.pack(side=LEFT)32
33 row3 =Frame(master)34 row3.pack(padx=10,pady=15)35 Button(row3,text="确定",width=10,command=self.ok).pack(side=LEFT,padx=5)36 Button(row3,text="取消",width=10,command=self.cancel).pack(side=LEFT,padx=5)37 pass
38
39 defok(self):40 self.username =self.en_user.get()41 self.password =self.en_pswd.get()42 if notself.validate():43 print "usrname or password error"
44 return
45 self.con.send({"res":True,"data":(self.username,self.password)})46 self.parent.quit()47 self.parent.destroy()48 pass
49
50 #验证账号密码
51 defvalidate(self):52 returnTrue53
54 defcancel(self):55 self.con.send({"res":False,"data":(self.username,self.password)})56 self.parent.quit()57 self.parent.destroy()58 pass
效果如图:
要点四、好友列表
View Code
1 #-*- coding: utf-8 -*-
2 importTkinter3 from Tkinter import *
4 from multiprocessing importProcess,Pipe5 from Chat import *
6 importstring7 classMain:8 def __init__(self,master,con=""):9 self.con = con #ends of a pipe
10 self.parent =master11 self.__loadmyself__()12 self.__layout__(master)13
14 #在这里导入个人资料,至少包含name属性
15 def __loadmyself__(self):16 self.me = {"name":u"沉鱼落雁"}17 pass
18
19 def __layout__(self,master):20 master.geometry("320x720+400+0")21 master.title("腾Q")22
23 f_message =Frame(master)24 f_message.pack(fill=X)25
26 Label(f_message,text=self.me['name']+"(online)").grid(row=0,sticky=W,pady=10,padx=5)27 Label(f_message,text="好友列表:").grid(row=1,sticky=W)28
29
30 f_friendlist =Frame(master)31 f_friendlist.pack(fill=BOTH)32 #带滚动条
33 scrollbar = Scrollbar(f_friendlist, orient=VERTICAL)34
35 self.listbox = Listbox(f_friendlist,yscrollcommand=scrollbar.set,height=700)36 scrollbar.config(command=self.listbox.yview)37 scrollbar.pack(side=RIGHT, fill=Y)38 self.listbox.bind("",self.show)39 self.refreshfriends()40 self.listbox.pack(fill=BOTH,expand=1)41 pass
42
43 #在这里导入好友列表
44 defloadfriends(self):45 #reading friends list from server
46 #for example:(needs to be modified)
47 self.friendlist = [{"ID":0,"name":u"xxx","state":"on"},{"ID":1,"name":u"范德萨","state":"off"}]48
49 fl =self.friendlist50 for obj infl:51 self.listbox.insert(END,"%s(%s)"% (obj["name"],obj["state"]))52 for i in range(2,50):53 obj = {"ID":i,"name":u"王老吉%d"%i,"state":"on"}54 self.friendlist.append(obj)55 self.listbox.insert(END,"%s(%s)"% (obj["name"],obj["state"]))56 pass
57
58 #更新好友列表,通常是周期性更新好友状态
59 defrefreshfriends(self):60 self.listbox.delete(0,END)61 self.loadfriends()62 pass
63
64 #开启对话框
65 defshow(self,event):66 lb =self.listbox;67 ss =lb.curselection()68 if len(ss) == 1:69 #print lb.curselection(),lb.get(lb.curselection())
70 index =string.atoi(ss[0])71 if index >=len(self.friendlist) :72 print "error",index,len(self.friendlist)73 else:74 obj =self.friendlist[index]75 if not obj.has_key("open"):76 self.__openchat__(obj)77 else:78 if not obj["open"] == "yes":79 self.__openchat__(obj)80 else:81 print obj['ID'],"alreay open"
82 #print self.friendlist[ss[0]]
83 pass
84
85 def __openchat__(self,obj):86 obj["open"] = "yes"
87 chat = Chat(self.parent,"",obj,self.me)88 pass
89
90 if __name__ == "__main__":91 root =Tk()92 main =Main(root)93 root.mainloop()
效果如图:
要点五、对话框基类
View Code
1 #coding=UTF-8
2 #File: myDialog.py
3
4 from Tkinter import *
5 importos6
7 classDialog(Toplevel):8
9 def __init__(self, parent, title =None):10
11 Toplevel.__init__(self, parent)12 self.transient(parent)13
14 iftitle:15 self.title(title)16
17 self.parent =parent18
19 self.result =None20
21
22 body =Frame(self)23 self.initial_focus =self.body(body)24 body.pack(padx=5, pady=5,fill=X)25
26 self.buttonbox()27
28 #self.grab_set()
29
30 if notself.initial_focus:31 self.initial_focus =self32
33 self.protocol("WM_DELETE_WINDOW", self.cancel)34
35 self.geometry("+%d+%d" % (parent.winfo_rootx()+50,36 parent.winfo_rooty()+50))37
38 self.initial_focus.focus_set()39
40 self.wait_window(self)41
42 #43 #construction hooks
44
45 defbody(self, master):46 #create dialog body. return widget that should have
47 #initial focus. this method should be overridden
48
49 pass
50
51 defbuttonbox(self):52 #add standard button box. override if you don't want the
53 #standard buttons
54
55 box =Frame(self)56
57 self.btn_ok = Button(box, text="确定", width=10, command=self.ok)58 self.btn_ok .pack(side=LEFT, padx=5, pady=5)59 self.btn_cancel = Button(box, text="取消", width=10, command=self.cancel)60 self.btn_cancel .pack(side=LEFT, padx=5, pady=5)61
62 #self.bind("", self.ok)
63 #self.bind("", self.cancel)
64
65 box.pack(anchor=E)66
67 #68 #standard button semantics
69
70 def ok(self, event=None):71
72 if notself.validate():73 self.initial_focus.focus_set() #put focus back
74 return
75
76 self.withdraw()77 self.update_idletasks()78
79 self.apply()80
81 self.cancel()82
83 def cancel(self, event=None):84 #put focus back to the parent window
85 self.parent.focus_set()86 self.destroy()87
88 #89 #command hooks
90
91 defvalidate(self):92
93 return 1 #override
94
95 defapply(self):96
97 pass #override
要点六、对话框
View Code
1 #coding=UTF-8
2 importTkinter3 from Tkinter import *
4 from myDialog import *
5 from datetime import *
6
7 classChat(Dialog):8 def __init__(self,master,title,obj,me):9 self.obj =obj10 self.me =me11 t = u"与"+obj['name']+u"聊天中"
12 Dialog.__init__(self,master,t)13
14 defapply(self):15 dt=datetime.now()16 timestr = u'%s于%s说: \n' % (self.me['name'],dt.strftime('%c'))17 msg = self.input.get(1.0,END)18 if msg.strip() == "":19 returnFalse20 self.insertmessage(timestr+msg)21 self.input.delete(1.0,END)22
23 self.text.yview(MOVETO, 1.0)24 pass
25
26 defbody(self,master):27 self.geometry("680x480")28 self.resizable(False,False)29
30 frame =Frame(master)31 Label(frame,text="聊天记录:").pack(padx=5,pady=5)32 frame.grid(row=0,sticky=W)33
34 frame =Frame(master)35 frame.grid(row=1)36 self.text_scrollbar = Scrollbar(frame, orient=VERTICAL)37 self.text = Text(frame,yscrollcommand= self.text_scrollbar.set,height=14,bg="white")38 self.text_scrollbar.config(command=self.text.yview)39 self.text_scrollbar.pack(side=RIGHT, fill=Y)40 self.text.bind("", lambda e : "break")41 self.text.pack()42
43 frame =Frame(master)44 Label(frame,text="输入聊天信息:").pack(padx=5,pady=5)45 frame.grid(row=2,sticky=W)46
47
48 frame =Frame(master)49 frame.grid(row=3)50 scrollbar = Scrollbar(frame, orient=VERTICAL)51 self.input = Text(frame,yscrollcommand=scrollbar.set,height=8,bg="white")52 scrollbar.config(command=self.input.yview)53 scrollbar.pack(side=RIGHT,fill=Y)54 self.input.pack(fill=Y)55
56
57 #插入聊天信息(显示在聊天框)
58 definsertmessage(self,msg):59 self.text.insert(END,msg+"\n")60 pass
61
62 #设置对话框标题
63 defsetTitle(self,title):64 self.title(title)65 pass
66
67 def ok(self,event=None):68 self.apply()69 pass
70
71 def cancel(self,event=None):72 self.obj["open"] = "no"
73 print "set open %s to no"%self.obj['name']74 Dialog.cancel(self,event)75
76 if __name__ == "__main__":77 print "开放的"
效果如图: