实现目标
点击按钮,实现属性的变化,根据状态的不同做区分操作
效果图
实现方式-1
import tkinter as tk
def click1():
global flag_pic
flag_pic = not flag_pic
if flag_pic:
btn_1['image']=pic_2
else:
btn_1['image']=pic_1
root.update()
def click2():
global flag_text
flag_text = not flag_text
if flag_text:
btn_2['text'] = 'Hello'
else:
btn_2['text'] = 'Hi'
root.update()
flag_text = True
flag_pic = True
root = tk.Tk()
pic_1 = tk.PhotoImage(file='pic/play.png')
pic_2 = tk.PhotoImage(file='pic/pause.png')
btn_1 = tk.Button(root,image=pic_2,command=click1)
btn_1.pack()
btn_2 = tk.Button(root,text='Hello',command=click2)
btn_2.pack()
root.mainloop()
评注
评注-1
这里使用到了[tk.PhotoImage],需要注意的是:
You must keep a reference to the image object in your Python program, either by storing it in a global variable, or by attaching it to another object.
Note: When a PhotoImage object is garbage-collected by Python (e.g. when you return from a function which stored an image in a local variable), the image is cleared even if it’s being displayed by a Tkinter widget.
To avoid this, the program must keep an extra reference to the image object. A simple way to do this is to assign the image to a widget attribute, like this:
label = Label(image=photo) label.image = photo # keep a reference! label.pack()
声明 pic_1对象时,必须保持对这个Image对象的引用,如通过全局变量的方式或者类对象属性的方式,否则会出现错误,如按钮控件无法点击且为白板等情况
评注-2
按钮对象不支持“.”的方式调用,即使使用却不报错,如下面的代码,不生效也不报错
def click2():
global flag_text
flag_text = not flag_text
if flag_text:
btn_2.text = 'Hello'
else:
btn_2.text = 'Hi'
root.update()
实现方式-2
这种方式是一种投机取巧的方式,但却可以让我们加以发挥到其他情况的使用上。
import tkinter as tk
def click():
global flag
if flag:
btn_2.pack_forget()
btn_1.pack()
else:
btn_1.pack_forget()
btn_2.pack()
flag = not flag
root.update()
flag = True
root = tk.Tk()
pic_1 = tk.PhotoImage(file='pic/play.png')
pic_2 = tk.PhotoImage(file='pic/pause.png')
btn_1 = tk.Button(root,image=pic_2,command=click)
btn_2 = tk.Button(root,image=pic_1,command=click)
btn_2.pack()
root.mainloop()
评注
我们可以看到,上面这个代码虽然实现了“按钮图标切换”,但本质上是实现了两个按钮,两个按钮交互显现。
这里运用到了【pack_forget()函数】,如果说【pack】是古代女子出门抛头露面,那么【pack_forget】则是躲入深闺不见客,女子本身还存在(区别于【destroy】方法),但并没被世人所见。
如果我们使用【destroy】,那么我们每次岂不是都要新建一个一样的对象。
About 【pack_forget 】:Removes the widget from its current manager. The widget is not destroyed, and can be displayed again by pack or any other manager.
实际上,tkinter的pack布局方式有【pack_forget】,grid布局方式也有它的【grid_forget】,使用pack与pack_forget的方式很容易露马脚,比如下面的情况:
import tkinter as tk
def click():
...
#与上例相同
flag = True
root = tk.Tk()
pic_1 = tk.PhotoImage(file='pic/play.png')
pic_2 = tk.PhotoImage(file='pic/pause.png')
btn_1 = tk.Button(root,image=pic_2,command=click)
btn_2 = tk.Button(root,image=pic_1,command=click)
tk.Button(root,text='Hello').pack()
btn_2.pack()
tk.Button(root,text='World').pack()
tk.Button(root,text='Find').pack()
root.mainloop()
效果图
位置变化,原因大致与pack布局是一种顺序堆叠的方式,后面才pack的控件自然就放在后面的位置了。解决这个问题的办法,是采用grid布局方式,如果每个控件要出现的位置是可以限定的,那么就不需要遵循顺序了。
import tkinter as tk
def click():
global flag
if flag:
btn_2.grid_forget()
btn_1.grid(row=0,column=1)
else:
btn_1.grid_forget()
btn_2.grid(row=0,column=1)
flag = not flag
root.update()
flag = True
root = tk.Tk()
pic_1 = tk.PhotoImage(file='pic/play.png')
pic_2 = tk.PhotoImage(file='pic/pause.png')
btn_1 = tk.Button(root,image=pic_2,command=click)
btn_2 = tk.Button(root,image=pic_1,command=click)
tk.Button(root,text='Hello').grid(row=0,column=0)
btn_2.grid(row=0,column=1)
tk.Button(root,text='World').grid(row=0,column=2)
tk.Button(root,text='Find').grid(row=0,column=3)
root.mainloop()
效果图
当然了,使用这种方式来实现按钮图标的切换是一种很鸡贼的方法,之所以花篇幅描述,则是觉得【pack_forget】、【grid_forget】的运用,对于用tkinter来做简单GUI程序有所帮助。
比如,通过运用这种方式,我们可以实现下面的效果,而不需要重载这个Frame,或者每次都生成展示歌曲列表的【listbox】对象,进而做大量的【listbox.insert】步骤,只需要将这个女孩子从深闺中请出来,而不是又重新培养一个这样的女孩子: