是否可以对使用 tkinter 中的网格管理器布局的帧进行动画处理?

Is it possible to animate frames that are layed out with the grid manager in tkinter?

我用tkinter做了这个桌面应用,完成了主要功能。 但现在我想让它看起来更好,甚至可以为菜单设置动画。 问题是我使用的按钮和小部件包含在框架中,并且所有这些都是使用网格布局管理器放置的。 所以我想知道我是否可以为元素(主要是按钮和框架)制作动画 w

举个例子,如果我将鼠标悬停在一个按钮上,它会稍微增大它的尺寸,但我当然希望及时看到该尺寸的增大。欧 r 也许当我点击一个按钮时,我需要换一个新的框架,然后旧的会向右滑动例如

以下代码结合了网格单元内交互式按钮的一些想法:

  • 鼠标悬停回调 <Enter><Leave>
  • 按照 Bryan Oakley 的建议以像素为单位指定的按钮大小(此处:
  • 使用padx/pady和width/height控制space为按钮保留
  • root.after(milliseconds, function) 如 furas 评论中所建议
import tkinter as tk

buttonsize = [120, 50]
extrasize = [10, 10]
framepad = [6, 6]
anim_time = 40
anim_steps = 10

root = tk.Tk()
pixel = tk.PhotoImage(width=1, height=1)

def SizeChange(event, fraction):
    event.widget.grid_configure(padx=(1.0-fraction)*extrasize[0], pady=(1.0-fraction)*extrasize[1])
    event.widget.configure(width=buttonsize[0]+2*fraction*extrasize[0],
        height=buttonsize[1]+2*fraction*extrasize[1])
    root.update_idletasks()


def Highlight(event):
    for idx in range(anim_steps):
        fraction = float(idx+1)/anim_steps
        root.after(int(fraction*anim_time), SizeChange(event, fraction))


def Unhighlight(event):
    for idx in range(anim_steps):
        fraction = 1.0 - float(idx+1)/anim_steps
        root.after(int(fraction*anim_time), SizeChange(event, fraction))


def AddButton(row, col, name):
    tkframe = tk.Frame(root, width=buttonsize[0]+extrasize[0],
        height=buttonsize[1]+extrasize[1])
    tkframe.grid(row=row, column=col, padx=framepad[0], pady=framepad[1], sticky='nsew')
    tkbutton = tk.Button(tkframe, text=name, compound='c', image=pixel,
        width=buttonsize[0], height=buttonsize[1])
    tkbutton.grid(row=0, column=0, padx=extrasize[0], pady=extrasize[1])
    tkbutton.bind('<Enter>', Highlight)
    tkbutton.bind('<Leave>', Unhighlight)


for idx in range(4):
    AddButton(row=idx//2, col=idx%2, name='Button ' + str(idx))


root.mainloop()

虽然看起来动画的流畅度在很大程度上取决于添加到按钮大小和时间步长的额外大小。

这是使用 after 移动 FrameLabelButton 的示例。我使用 place() 来使用相对位置,所以 Frame 离开 window 即使你改变 window 大小。

import tkinter as tk

# --- functions ---

def move(steps=10, distance=0.1):
    if steps > 0:
        # get current position
        relx = float(frame.place_info()['relx'])

        # set new position
        frame.place_configure(relx=relx+distance)

        # repeate it after 10ms
        root.after(10, move, steps-1, distance)

def on_click():
    print('on_click')
    # start move
    move(50, 0.02) # 50*0.02 = 1

# --- main --

root = tk.Tk()

frame = tk.Frame(root, background='red')
frame.place(relx=0, rely=0, relwidth=1, relheight=1)

# to center label and button
#frame.grid_columnconfigure(0, weight=1)
#frame.grid_rowconfigure(0, weight=1)
#frame.grid_rowconfigure(3, weight=1)

label = tk.Label(frame, text='Frame with Label and Button')
label.grid(row=1, column=0)

button = tk.Button(frame, text='MOVE', command=on_click)
button.grid(row=2, column=0)

root.mainloop()