Python-tkinter
按钮等其他内容见微信收藏笔记部分。
http://effbot.org/tkinterbook/button.htm
其他常用组件:ScrolledText、Labelframe
固定窗口大小:root.resizable(0,0),第一个0表示固定宽,第二个0表示固定高,非0表示不固定。布尔值就好。
Label
1 from tkinter import * 2 3 4 class Application(Frame): 5 def __init__(self, master): 6 super().__init__(master) 7 self.label2 = None 8 self.create_widget() 9 self.pack() 10 11 def create_widget(self): 12 label = Label(self, text='标签一\n还能换行', width=9, height=2, 13 bg='red', fg='blue', font=('黑体', 30)) # 还有‘宋体’等。如果是字符width、height单位是字符(字母数字1个字符,汉字算2个字符) 14 label.pack() 15 16 # global img # 也可以在此处创建图片对象,只是不符合PEP8 17 # img = PhotoImage(file='label.gif') # 若不设为global会导致局部变量调完后销毁,看不到效果 18 self.label2 = Label(self, image=img, width=50, height=30) # 如果是图像width、height单位是像素 19 self.label2.pack() 20 21 label3 = Label(self, text='随便写点', borderwidth=1, relief='solid', justify='right') 22 label3.pack() 23 24 25 root = Tk() 26 root.title('窗口标题') 27 root.geometry('300x200-500-400') 28 img = PhotoImage(file='label.gif') 29 app = Application(root) 30 root.mainloop()
Option的3种设置方式:
1 from tkinter import * 2 3 4 class App(Frame): 5 def __init__(self, master): 6 super().__init__(master) 7 self.create_widgets() 8 self.pack() 9 10 def create_widgets(self): 11 label = Label(self, dict(text='标签文本', border=1), justify='right', width=20, 12 font=('黑体', 20, 'bold')) # option设置方式一:命名参数 也可写成justify=RIGHT 13 label['bg'] = 'red' # option设置方式二:字典索引 14 label.config(fg='blue', height=3) # option设置方式三:config方法 15 label.pack() 16 17 18 root = Tk() 19 root.title('窗口标题') 20 root.geometry('300x200+500+400') 21 app = App(root) 22 root.mainloop()
Entry和密码显示样式设置:
1 from tkinter import * 2 3 4 class App(Frame): 5 def __init__(self, master): 6 super().__init__(master) 7 self.pack() 8 self.create_widgets() 9 10 def create_widgets(self): 11 lable_username = Label(self, text='用户名') 12 lable_username.pack() 13 14 username = StringVar() # username变量会改变Entry中的值,Entry中的值变化会改变username值,互相影响。 15 entry_username = Entry(self, textvariable=username) 16 entry_username.pack() 17 username.set('admin') 18 19 lable_pwd = Label(self, text='密码') 20 lable_pwd.pack() 21 22 pwd = StringVar() 23 entry_pwd = Entry(self, textvariable=pwd, show='*') 24 entry_pwd.pack() 25 26 btn = Button(self, text='确定', command=lambda: self.f(username, pwd)) 27 btn.pack() 28 29 def f(self, username, pwd): 30 print('用户名:', username.get()) 31 print('密码:', pwd.get()) 32 33 34 master = Tk() 35 app = App(master) 36 master.mainloop()
Text组件:有好多方法和知识点
1 # Text组件 2 from tkinter import * 3 import webbrowser 4 5 6 class App(Frame): 7 def __init__(self, master): 8 super().__init__(master) 9 self.pack() 10 self.create_widgets() 11 12 def create_widgets(self): 13 self.w = Text(self, width=50, height=15, bg='gray') 14 self.w.pack() 15 16 self.w.insert(1.0, '0123456789\nabcdefghijklmnopqrstuvwxyz') # 1.0表示第1行第0列,行从1开始计,列从0开始计 17 self.w.insert(2.4, '随便写点啥') 18 19 Button(self, text='重复插入文本', command=self.insertText).pack(side=LEFT) 20 Button(self, text='返回文本', command=self.returnText).pack(side=LEFT) 21 Button(self, text='添加图片文本', command=self.addImg).pack(side=LEFT) 22 Button(self, text='添加组件', command=self.addWidget).pack(side=LEFT) 23 Button(self, text='通过tag精确控制文本', command=self.testTag).pack(side=LEFT) 24 25 def insertText(self): 26 self.w.insert(INSERT, '在光标处插入') # INSERT表示在光标处插入 27 self.w.insert(END, '在最后插入') # END表示在末尾插入 28 29 def returnText(self): 30 print(self.w.get(1.3, 2.3)) # 打印从第1行第3列开始到第2行第5列开始的字符,包头不包尾,即不包括第2行第5列那个字符 31 self.w.insert(1.5, '新字') 32 print(self.w.get(1.0, END)) # 打印所有字符 33 34 def addImg(self): 35 # 写法一: 36 # global photo #不能用局部变量,不然图片不显示,因为方法调完后局部变量对象就会销毁 37 # photo=PhotoImage(file='label.gif') 38 # self.w.image_create(END, image=photo) 39 40 # 写法二: 41 self.photo = PhotoImage(file='label.gif') 42 self.w.image_create(END, image=self.photo) 43 44 def addWidget(self): 45 self.w.window_create(INSERT, window=Button(self.w, text='按钮')) 46 47 def testTag(self): 48 self.w.delete(1.0, END) 49 self.w.insert(INSERT, '好好学习,天天向上\n0987654321sdljflds\nslfjlajfksdfowef\nsfslfjdskjlfs') 50 self.w.tag_add('good', 1.0, 1.9) 51 self.w.tag_config('good', background='red', foreground='blue') 52 53 self.w.tag_add('sogo', 4.0, 4.2) 54 self.w.tag_config('sogo', underline=True) 55 self.w.tag_bind('sogo', '<Button-1>', self.webshow) 56 57 def webshow(self, e): 58 webbrowser.open('sogo.com') 59 60 61 root = Tk() 62 app = App(root) 63 root.mainloop()
Radiobutton
1 from tkinter import * 2 from tkinter import messagebox 3 4 class App(Frame): 5 def __init__(self, master): 6 super().__init__(master) 7 self.pack() 8 self.create_widgets() 9 10 def create_widgets(self): 11 self.v_bool = BooleanVar() 12 self.v_bool.set(True) 13 self.r_bool1 = Radiobutton(self, text='真', value=True, variable=self.v_bool) 14 self.r_bool2 = Radiobutton(self, text='假', value=False, variable=self.v_bool) 15 self.r_bool1.pack(side=LEFT);self.r_bool2.pack(side=LEFT) 16 17 self.v_int = IntVar() 18 self.v_int.set(0) 19 self.r_int1 = Radiobutton(self, text='零', value=0, variable=self.v_int) 20 self.r_int2 = Radiobutton(self, text='一', value=1, variable=self.v_int) 21 self.r_int1.pack(side='left');self.r_int2.pack(side=LEFT) 22 23 self.v_double = DoubleVar() 24 self.v_double.set(1.1) 25 self.r_double1 = Radiobutton(self, text='1点1', value=1.1, variable=self.v_double) 26 self.r_double2 = Radiobutton(self, text='2点2', value=2.2, variable=self.v_double) 27 self.r_double1.pack(side=LEFT);self.r_double2.pack(side=LEFT) 28 29 self.v_string = StringVar() 30 self.v_string.set('M') 31 self.r_string1 = Radiobutton(self, text='男', value='M', variable=self.v_string) 32 self.r_stirng2 = Radiobutton(self, text='女', value='F', variable=self.v_string) 33 self.r_string1.pack(side=LEFT);self.r_stirng2.pack(side=LEFT) 34 35 Button(self, text='确定', command=self.confirm).pack() 36 37 def confirm(self): 38 info = ''.join(['v_bool=', str(self.v_bool.get()), '\nv_int=', str(self.v_int.get()), '\nv_double=', 39 str(self.v_double.get()), '\nv_string=', self.v_string.get()]) 40 messagebox.showinfo('信息', info) 41 42 root = Tk() 43 app = App(root) 44 root.mainloop()
Checkbutton
1 from tkinter import * 2 from tkinter import messagebox 3 4 5 class App(Frame): 6 def __init__(self, master): 7 super().__init__(master) 8 self.pack() 9 self.create_widgets() 10 11 def create_widgets(self): 12 self.v_bool = BooleanVar() 13 print('默认值:BooleanVar()=', self.v_bool.get()) 14 self.c_bool = Checkbutton(self, text='布尔值', variable=self.v_bool, onvalue=True, 15 offvalue=False) # 一开始通过默认值判断onvalue是否符合 16 self.c_bool.pack(side='left') 17 18 self.v_int = IntVar() 19 print('默认值:IntVar()=', self.v_int.get()) 20 self.c_int = Checkbutton(self, text='整数', variable=self.v_int, onvalue=1, offvalue=0) # 一开始无论啥值都不勾选 21 self.c_int.pack(side=LEFT) 22 23 self.v_double = DoubleVar() 24 print('默认值:DoubleVar()=', self.v_double.get()) 25 self.c_double = Checkbutton(self, text='浮点数', variable=self.v_double, onvalue=1.1, offvalue=0.0) # 一开始无论啥值都不勾选 26 self.c_double.pack(side=LEFT) 27 28 self.v_string = StringVar() 29 print('默认值:StringVar()=', self.v_string.get()) 30 self.c_string = Checkbutton(self, text='字符串', variable=self.v_string, onvalue='a', 31 offvalue='') # 一开始通过判断offvalue的值确定是否勾选,若一开始offvalue!='',则勾选 32 self.c_string.pack(side=LEFT) 33 34 Button(self, text='确定', command=self.confirm).pack() 35 36 def confirm(self): 37 info = ''.join(['c_bool:', str(self.v_bool.get()), '\nc_int:', str(self.v_int.get()), '\nc_double:', 38 str(self.v_double.get()), '\nc_string:', self.v_string.get()]) 39 messagebox.showinfo('结果', info) 40 41 42 root = Tk() 43 app = App(root) 44 root = mainloop()
Canvas
1 from tkinter import * 2 import random 3 4 5 class App(Frame): 6 def __init__(self, master): 7 super().__init__(master) 8 self.pack() 9 self.create_widgets() 10 11 def create_widgets(self): 12 self.canvas = Canvas(self, width=500, height=300, bg='green') 13 self.canvas.pack() 14 15 line = self.canvas.create_line(15, 15, 35, 28, 45, 66) # 连续3个坐标点,形成折线 16 rect = self.canvas.create_rectangle(60, 60, 150, 150) # 矩形 17 oval = self.canvas.create_oval(60, 60, 150, 150) # 椭圆 18 19 # 方法一:对象属性,即self.photo 20 self.photo = PhotoImage(file='label.gif') 21 self.canvas.create_image(180, 90, image=self.photo) 22 # 方法二:全局变量:global photo ,但不建议用全局变量,原则:少用全局变量,全局变量比局部变量慢,而且风险大 23 # global photo 24 # photo = PhotoImage(file='label.gif') 25 # self.canvas.create_image(180, 90, image=photo) 26 # 用局部变量不行,因为方法调完后局部变量对象会自动销毁,图片无法显示 27 # photo = PhotoImage(file='label.gif') 28 # self.canvas.create_image(180, 90, image=photo) 29 30 Button(self, text='画多个矩形', command=self.drawMultiRect).pack() 31 32 def drawMultiRect(self): 33 for i in range(10): 34 x1 = random.randrange(int(self.canvas['width']) / 2) 35 y1 = random.randrange(int(self.canvas['height']) / 2) 36 x2 = x1 + random.randrange(int(self.canvas['width']) / 2) 37 y2 = y1 + random.randrange(int(self.canvas['height']) / 2) 38 self.canvas.create_rectangle(x1, y1, x2, y2) 39 40 41 root = Tk() 42 root.title('画布') 43 root.geometry('600x400+300-200') 44 app = App(root) 45 root.mainloop()
grid布局
1 from tkinter import * 2 3 4 class App(Frame): 5 def __init__(self, master): 6 super().__init__(master) 7 self.pack() 8 self.create_widgets() 9 10 def create_widgets(self): 11 self.label_username = Label(self, text='用户名') 12 self.label_username.grid(row=0, column=0) 13 self.entry_username = Entry(self).grid(row=0, column=1) 14 self.label_tips = Label(self, text='用户名为手机号').grid(row=0, column=2) 15 16 Label(self, text='密码').grid(row=1, column=0) 17 Entry(self, show='#').grid(row=1, column=1) 18 19 Button(self, text='登录').grid(row=2, column=1, sticky=EW) # EW为左右两端对齐,两端拉长 20 Button(self, text='取消').grid(row=2, column=2, sticky=E) 21 22 23 root = Tk() 24 root.title('grid布局') 25 root.geometry('600x400+300-200') 26 app = App(root) 27 root.mainloop()
计算器界面:知识点:enumerate、rowspan跨行、columnspan跨列,padx横向间距,pady竖向间距
1 from tkinter import * 2 3 class App(Frame): 4 def __init__(self, master): 5 super().__init__(master) 6 self.pack() 7 self.createWidgets() 8 9 def createWidgets(self): 10 btnTexts = (('MC', 'M+', 'M-', 'MR'), ('C', '±', '÷', '×'), (7, 8, 9, '-'), (4, 5, 6, '+'), (1, 2, 3, '='), (0, '.')) 11 Entry(self).grid(row=0, column=0, columnspan=4, padx=3, pady=3) # columnspan跨列,padx横向间距,pady竖向间距 12 for rindex, r in enumerate(btnTexts): 13 for cindex, c in enumerate(r): 14 if c == '=': 15 Button(self, text=c).grid(row=rindex + 1, column=cindex, rowspan=2,sticky=NSEW) # rowspan跨行。sticky=NSEW,其中NSEW顺序不能随便写 16 elif c == 0: 17 Button(self, text=c).grid(row=rindex + 1, column=cindex, columnspan=2, sticky=NSEW) 18 elif c == '.': 19 Button(self, text=c).grid(row=rindex + 1, column=cindex + 1, sticky=NSEW) 20 else: 21 Button(self, text=c).grid(row=rindex + 1, column=cindex, sticky=NSEW) 22 23 root = Tk() 24 app = App(root) 25 root.mainloop()
pack布局
1 from tkinter import * 2 3 root = Tk() 4 root.geometry('700x220') #第3、4个参数,与屏幕左、上的距离可省 5 f1 = Frame(root);f1.pack() # 和f1=Frame(root).pack()写法效果不一样 6 f2 = Frame(root);f2.pack() # 和f2=Frame(root).pack()写法效果不一样 7 8 btnTexts = ('天龙八部', '雪山飞狐', '笑傲江湖', '神雕侠侣', '飞狐外传') 9 for i in btnTexts: 10 Button(f1, text=i).pack(side=LEFT, padx=10,pady=5) 11 12 for i in range(10): 13 Label(f2, width=5, height=10, borderwidth=1, relief='solid', 14 bg='black' if i % 2 == 0 else 'white').pack(side='left', padx=2) 15 root.mainloop()
place()布局
1 from tkinter import * 2 3 root=Tk();root.geometry('500x300') 4 5 f1=Frame(root,width=200,height=200,bg='green') 6 f1.place(x=30,y=30)#绝对定位x,y 7 8 #relx和x同时存在时先通过relx相对定位,再通过x偏移,即x在有relx时的作用不是绝对定位,成了偏移量 9 #relx、rely、relwidth、relheigth取值范围[0,1],相对父组件,relx=0最左,relx=1最右,rely=0最顶,rely=1最底 10 #relwidth=0.5父组件宽度一半,relheight=0.5父组件高度一半 11 Button(root,text='好好学习').place(relx=.2,x=100,y=20,relwidth=.2,relheight=.5) 12 Button(f1,text='天天向上').place(relx=.4,rely=.8) 13 Button(f1,text='勤学精专').place(relx=.3,rely=.2) 14 root.mainloop()
扑克牌出牌效果
1 from tkinter import * 2 3 class App(Frame): 4 def __init__(self,master): 5 super().__init__(master) 6 self.pack() 7 self.createWidgets() 8 9 def createWidgets(self): 10 # self.img=PhotoImage(file='pai/pai7.gif') 11 # self.pai=Label(self.master,image=self.img)#此处self不显示图片,要写成self.master才行 12 # self.pai.place(x=10,y=50) 13 14 self.imgs=[PhotoImage(file='pai/pai'+str(i)+'.gif') for i in range(7,10)] 15 self.pais=[Label(self.master,image=self.imgs[i]) for i in range(3)] 16 for i in range(3):self.pais[i].place(x=10+i*50,y=50) 17 18 self.pais[2].bind_class('Label','<1>',self.play)#pais[0]、pais[1]、pais[2]随便写哪个,都一样,为什么?因为绑定了类事件bind_class('Label')吗? 19 # self.pais[1].bind_class('Label','<Button-1>',self.play)# <1>和<Button-1>效果一样 20 21 def play(self,e): 22 print(e.widget.winfo_geometry())# 获取宽高坐标 23 print(e.widget.winfo_y()) #获取坐标y 24 if e.widget.winfo_y()==50: 25 e.widget.place(y=30) #设置坐标y 26 else: 27 e.widget.place(y=50) 28 29 root=Tk() 30 root.geometry('800x500') 31 app=App(root) 32 root.mainloop()
组件绑定事件,消息处理:widget.bind(event,handler)
1 #coding='utf-8' 2 #coding=utf-8 3 #以上两种写法都行 4 from tkinter import * 5 6 root=Tk();root.geometry('600x400') 7 c=Canvas(root,width=200,height=200,bg='green') 8 c.pack() 9 10 def mouseTest(e): 11 print('鼠标左键单击位置(相对于父容器):{},{}'.format(e.x,e.y)) 12 print('鼠标左键单击位置(相对于屏幕):{},{}'.format(e.x_root,e.y_root)) 13 print('事件绑定的组件:{}'.format(e.widget)) 14 15 def testDrag(e): 16 c.create_oval(e.x,e.y,e.x+1,e.y+1) 17 18 def keyboardTest(e): 19 print('键的keycode:{},键的char:{},键的keysym:{}'.format(e.keycode,e.char,e.keysym)) 20 21 def press_a_test(e): 22 print('press a') 23 24 def release_a_test(e): 25 print('release a') 26 27 c.bind('<1>',mouseTest) #单击:1鼠标左键 2鼠标中键 3鼠标右键 28 29 c.bind('<B1-Motion>',testDrag) #Motion移动:1鼠标左键 2鼠标中键 3鼠标右键 30 31 root.bind('<KeyPress>',keyboardTest) 32 root.bind('<KeyPress-a>',press_a_test) #小写a 。大写A无效 33 root.bind('<KeyRelease-a>',release_a_test) 34 root.mainloop()
使用lambda绑定带参数的函数:
1 from tkinter import * 2 root=Tk(); 3 def f1(): 4 print('不涉及获取事件event对象') 5 6 def f2(a,b): 7 print(a+b) 8 9 Button(root,text='绑定f1',command=f1).pack() 10 Button(root,text='绑定f2',command=lambda :f2(2,3)).pack() 11 12 root.mainloop()
OptionMenu
1 from tkinter import * 2 3 root = Tk(); 4 root.geometry('250x150') 5 6 v = StringVar() #v = StringVar(root) 参数root可有可无 7 v.set('天龙八部') 8 # optionMenu=OptionMenu(root,v,'红楼梦','水浒传','三国演义','西游记',width=10).pack() #这种写法会报错 9 optionMenu=OptionMenu(root,v,'红楼梦','水浒传','三国演义','西游记') 10 optionMenu.pack() 11 optionMenu['width']=10#会报错,为啥?? 12 13 # optionMenu = OptionMenu(root, v, '红楼梦', '水浒传', '三国演义', '西游记').pack() 14 # print(optionMenu) # None 15 # optionMenu['width'] = 10 # TypeError: 'NoneType' object does not support item assignment 16 17 def f(): 18 print('选择了:',v.get()) 19 v.set('四大名著') # 可直接修改optionMenu值 20 21 Button(root,text='确定',command=f).pack() 22 root.mainloop()
Scale
1 from tkinter import * 2 3 root = Tk();root.geometry('500x200') 4 5 def f(v): 6 print('滑块值:', v) 7 newFont = ('宋体', v, 'bold') 8 label.config(font=newFont) 9 10 # 这有个坑:from_有个下划线,容易忽略。 11 # 会自动把scale的值当参数传给函数,orient默认竖直,tickinterval刻度显示间距 12 scale = Scale(root, from_=10, to=50, tickinterval=5, length=200, orient=HORIZONTAL, command=f) 13 scale.pack() 14 15 label = Label(root, text='好好学习', width=9, height=1, bg='red', fg='yellow') 16 label.pack() 17 18 root.mainloop()
选择颜色:colorchooser、askcolor
1 from tkinter import * 2 from tkinter.colorchooser import * 3 4 root = Tk(); 5 root.geometry('500x300') 6 7 def f(): 8 color = askcolor(color='yellow', title='选择颜色') # color='yellow'默认色 9 print(color) 10 root.config(bg=color[1]) 11 12 Button(root, text='选择背景颜色', command=f).pack() 13 root.mainloop()
打开文件,获取文件路径:
1 from tkinter import * 2 from tkinter.filedialog import * 3 4 root=Tk();root.geometry('500x300') 5 6 def f(): 7 file=askopenfilename(title='上传文件',initialdir='c:',filetypes=[('自定义说明','.txt')]) 8 label['text']=file 9 10 Button(root,text='选择文本文件',command=f).pack() 11 label=Label(root,width=50,height=5,bg='pink') 12 label.pack() 13 root.mainloop()
打开文件,获取文件内容:
1 from tkinter.filedialog import * 2 3 root=Tk();root.geometry('500x300') 4 5 def f(): 6 with askopenfile(title='上传文件',initialdir='D:',filetypes=[('自定义说明','.txt')]) as file: 7 label['text']=file.read() 8 9 Button(root,text='选择文本文件内容',command=f).pack() 10 label=Label(root,width=50,height=5,bg='pink') 11 label.pack() 12 root.mainloop()
简单对话框:tkinter.simpledialog、askinteger、askfloat、askstring
1 from tkinter.simpledialog import * 2 3 root=Tk() 4 5 def f(): 6 text=askinteger(title='标题',prompt='提示语',initialvalue=10,minvalue=0,maxvalue=100) 7 # text=askfloat() 8 # text=askstring() 9 label['text']=text 10 11 Button(root,text='输入一个数',command=f).pack() 12 label=Label(root) 13 label.pack() 14 root.mainloop()
通用消息框
1 from tkinter import * 2 from tkinter.messagebox import * 3 4 root=Tk() 5 text=showinfo(title='标题',message='提示信息') 6 print(text) # ok 7 # showwarning() 8 # showerror() 9 root.mainloop()
简易记事本:菜单Menu
增加快捷键事件绑定:root.bind('<Control-n>', lambda event:self.newfile()) # 通过bind绑定的都会传事件对象event,所以要用lambda接收参数,self.newfile()为lambda的表达式,可以不使用传进来的事件对象参数。
root.bind('<Control-o>', lambda event:self.openfile())
新建文件:
def newfile(self):
self.filename=asksavefilename(title='新建文件',initialfile='未命名.txt', filetypes=[('文本文件','*.txt')], defaultextension='.txt')
1 from tkinter.filedialog import * 2 3 root=Tk();root.geometry('450x350+400+280') 4 5 menubar=Menu(root)#创建主菜单 6 7 menuFile=Menu(menubar)#创建子菜单 8 menuEdit=Menu(menubar) 9 menuHelp=Menu(menubar) 10 11 #将子菜单加入到主菜单栏 12 menubar.add_cascade(label='文件(F)',menu=menuFile) 13 menubar.add_cascade(label='编辑(E)',menu=menuEdit) 14 menubar.add_cascade(label='帮助(H)',menu=menuHelp) 15 16 def openfile(): 17 text.delete(1.0,END) #还可写成 '1.0','end' 随意 18 with askopenfile(title='打开文件') as f: 19 content=f.read() 20 text.insert(INSERT,content) 21 print(f.name) 22 23 24 def savefile(): 25 with open('d:/menu.txt','w') as f: 26 content=text.get(1.0,END) 27 f.write(content) 28 29 #给子菜单添加菜单项 30 menuFile.add_command(label='打开',accelerator='ctrl+o',command=openfile) 31 menuFile.add_command(label='保存',accelerator='ctrl+s',command=savefile) 32 menuFile.add_separator()#添加分割线 33 menuFile.add_command(label='退出',command=quit) #退出随便用exit或quit 34 # menuFile.add_command(label='退出',command=exit) 35 36 root['menu']=menubar 37 38 ############################################################## 39 40 #添加右键:上下文件菜单、快捷菜单 41 def createContextMenu(e): 42 contextBar.post(e.x_root,e.y_root) 43 44 contextBar=Menu(root)#创建右键菜单(上下文件菜单、快捷菜单) 45 contextBar.add_command(label='另存为...') 46 contextBar.add_command(label='退出应用',command=exit) 47 48 root.bind('<3>',createContextMenu) 49 50 51 text=Text(root,width=50,height=20) 52 text.pack() 53 54 root.mainloop()
简易画图小工具:
1 from tkinter import * 2 from tkinter.colorchooser import * 3 4 class App(Frame): 5 def __init__(self,master,fgcolor='#000000'): 6 super().__init__(master) 7 self.x=0 8 self.y=0 9 self.fgcolor='#ff0000' 10 self.lastDraw=0 #从1开始的整数,最后绘制的图形的id 11 self.startDrawFlag=False 12 self.pack() 13 self.createWidgets() 14 15 def createWidgets(self): 16 self.drawPad = Canvas(self, width=900, height=450, bg='black') 17 self.drawPad.pack() 18 19 start=Button(self,text='开始',name='start') 20 start.pack(side=LEFT,padx=10) 21 self.pen=Button(self,text='画笔',name='pen') 22 self.pen.pack(side=LEFT,padx=10) 23 rect=Button(self,text='矩形',name='rect') 24 rect.pack(side=LEFT,padx=10) 25 clear=Button(self,text='清屏',name='clear') 26 clear.pack(side=LEFT,padx=10) 27 erasor=Button(self,text='橡皮擦',name='erasor') 28 erasor.pack(side=LEFT,padx=10) 29 self.line=Button(self,text='直线',name='line') 30 self.line.pack(side=LEFT,padx=10) 31 lineArrow=Button(self,text='箭头直线',name='lineArrow') 32 lineArrow.pack(side=LEFT,padx=10) 33 color=Button(self,text='颜色',name='color') 34 color.pack(side=LEFT,padx=10) 35 36 # 给所有Button类对象绑定单击鼠标左键事件。此语句导致了按钮没有点击态,未解之谜? 37 self.pen.bind_class('Button','<1>',self.eventManager) 38 self.drawPad.bind('<ButtonRelease-1>',self.stopDraw) 39 40 #增加颜色切换快捷键 41 # self.drawPad.bind('<KeyPress-r>',self.changeColor) # 无效 42 # self.bind('<KeyPress-r>',self.changeColor) # 无效 43 self.master.bind('<KeyPress-r>',self.changeColor) # 有效,区分大小写 44 self.master.bind('<KeyPress-g>',self.changeColor) # 有效 45 self.master.bind('<KeyPress-b>',self.changeColor) # 有效 46 47 def eventManager(self,e): 48 name=e.widget.winfo_name() 49 if name=='line': 50 self.drawPad.bind('<B1-Motion>',self.myline) 51 elif name=='lineArrow': 52 self.drawPad.bind('<B1-Motion>',self.mylineArrow) 53 elif name=='rect': 54 self.drawPad.bind('<B1-Motion>',self.myrect) 55 elif name=='pen': 56 self.drawPad.bind('<B1-Motion>',self.mypen) 57 elif name=='erasor': 58 self.drawPad.bind('<B1-Motion>',self.myerasor) 59 elif name=='clear': 60 # self.drawPad.delete('all') # 写法一 61 self.drawPad.delete(ALL) # 写法二 62 self.drawPad.delete('ALL') # 这种写法不行 63 elif name=='color': 64 self.fgcolor=askcolor(color='yellow',title='选择颜色')[1] 65 66 def startDraw(self,e): 67 self.drawPad.delete(self.lastDraw) # 删除鼠标抬起前的所有画线,只保留鼠标抬起前的最后一次画线 68 69 if not self.startDrawFlag: 70 self.startDrawFlag = True 71 self.x = e.x 72 self.y = e.y 73 74 def myline(self,e): 75 self.startDraw(e) 76 self.lastDraw=self.drawPad.create_line(self.x,self.y,e.x,e.y,fill=self.fgcolor) 77 # print(self.lastDraw) #从1开始的整数,最后绘制的图形的id 78 79 def mylineArrow(self,e): 80 self.startDraw(e) 81 self.lastDraw=self.drawPad.create_line(self.x,self.y,e.x,e.y,arrow=LAST,fill=self.fgcolor) 82 83 def myrect(self,e): 84 self.startDraw(e) 85 # self.lastDraw=self.drawPad.create_rectangle(self.x,self.y,e.x,e.y,fill=self.bgcolor) # 填充 86 self.lastDraw=self.drawPad.create_rectangle(self.x,self.y,e.x,e.y,outline=self.fgcolor) 87 88 def mypen(self,e): 89 self.startDraw(e) 90 self.drawPad.create_line(self.x,self.y,e.x,e.y,fill=self.fgcolor) 91 self.x=e.x 92 self.y=e.y 93 94 def myerasor(self,e): 95 self.startDraw(e) 96 self.drawPad.create_rectangle(e.x-5,e.y-5,e.x+5,e.y+5,fill='black') 97 self.x=e.x 98 self.y=e.y 99 100 def stopDraw(self,e): 101 self.startDrawFlag=False 102 self.lastDraw=0 # 画下一条线时保留之前画的线不被删除 103 104 def changeColor(self,e): 105 if e.char=='r': # 区别大小写 106 self.fgcolor='#ff0000' 107 elif e.char=='g': 108 self.fgcolor='green' 109 elif e.char=='b': 110 self.fgcolor='blue' 111 112 def main(): 113 root=Tk();root.geometry('900x500+200+140') 114 App(root) 115 root.mainloop() 116 117 if __name__ == '__main__': 118 main()
未完
待续