【问题标题】:How can I use tkinter to make an animation?如何使用 tkinter 制作动画?
【发布时间】:2021-12-09 23:54:55
【问题描述】:

作为作业的一部分,我必须实施强化学习算法。我首先为自己设计了一些可视化,这样一旦我真正开始实施算法,我就可以知道发生了什么。我想使用 Tkinter,因为它似乎很容易根据代理(红色圆圈,见附图)采取的行动来进行图像迭代。本质上,我只想要代理移动到另一个方块的图像。它不能通过用户输入发生,一旦我按下运行,它应该自己执行整个算法。问题是由于root.mainloop(),似乎无法更新视图。我应该怎么做,是否应该使用不同的可视化工具,或者有什么方法可以在每次迭代时简单地显示一个新屏幕(无需用户输入)?最后,我尝试使用.update(),但显然不鼓励使用该功能。

class GraphicalInterface:
##Initialisation of the GUI class.
    def __init__(self, height, width):
        self.blockColor = 'DarkSeaGreen3'
        self.block_size=75
        self.padding=1
        self.frame_height = height*self.block_size
        self.frame_width = width*self.block_size
        self.root = Tk()
        self.root.resizable(width=0, height=0)

        self.frm = Frame(self.root, height=self.frame_height+8+self.padding*(height*2),
                         width=self.frame_width+8+self.padding*(width*2), background='lightgray',
                         cursor='circle', relief='sunken', borderwidth=4)
        self.frm.grid_propagate(0)
        self.frm.grid(column=0, row=0, padx=20, pady=20)
        for i in range(0,width):
            for j in range(0,height):
                cur_frame = Frame(self.frm, background=self.blockColor, height=self.block_size, width=self.block_size)
                cur_frame.grid(column=i,row=j, padx=self.padding, pady=self.padding)

    def create_circle(self, x, y, r, canvasName, color):  # center coordinates, radius       https://stackoverflow.com/questions/17985216/simpler-way-to-draw-a-circle-with-tkinter
        x0 = x - r
        y0 = y - r
        x1 = x + r
        y1 = y + r
        return canvasName.create_oval(x0, y0, x1, y1, fill=color)

    def setObstacle(self, x, y):
        cv = Canvas(self.frm, height=self.block_size-15, width=self.block_size-15, background= self.blockColor, highlightthickness=0)
        self.create_circle(x = cv.winfo_reqheight()/2, y=cv.winfo_reqwidth()/2, r=30, canvasName=cv, color='black')
        cv.grid(column=x, row=y, padx=0, pady=0)

    def setAgent(self, x, y):
        cv = Canvas(self.frm, height=self.block_size-15, width=self.block_size-15, background=self.blockColor, highlightthickness=0)
        self.create_circle(x=cv.winfo_reqheight()/2, y=cv.winfo_reqwidth()/2, r=25, canvasName=cv, color='firebrick4')
        cv.grid(column=x, row=y)

    def run(self):
        self.root.mainloop()

【问题讨论】:

  • 最直接的方法是在画布上移动项目,或者在每次算法更改时更新显示的计算。另一种方法是将要显示的算法的每个步骤存储到生成器(或顺序集合)中,然后迭代存储的步骤,并更新算法的进度。最后一种方法允许您将算法与 GUI 机制的实现分开,并更好地控制动画的执行速度。
  • 你试过用update_idletasks刷新屏幕吗?
  • 如果您在一个函数中运行所有内容,那么您必须不时使用update() 来强制mainloop 在窗口中重绘所有内容。如果您在单独的文件中有步骤,那么您可以使用root.after(milliseconds, functions_name) 延迟运行下一个功能 - 这样您就可以在更改之前查看当前状态 - 它会自动重绘窗口。
  • @bryanOakley Yepp 这有帮助。我需要设置自己的循环而不是 mainloop()。在 run() 中,我启动了一个调用 root.after(millis, fname) 和 root.update 的循环。它现在似乎有点慢,但也许这只是图书馆固有的,这很好。非常感谢:)

标签: python tkinter algorithm-animation


【解决方案1】:

本例使用root.after(milliseconds, function_name) 启动windows 后启动函数。此函数运行添加圆圈的循环 - 它需要 root.update() 强制 mainloop() 用新元素重绘窗口。它还使用root.after(milliseconds) 而不是time.sleep()。这一切看起来都像动画。

但它可以使用 root.after(milliseconds, another_function_name) 延迟运行其他函数 - 所以它会运行 action 使用 after() 运行另一个从游戏/环境中获取结果的函数(rewardstate),这个函数将使用after() 再次运行action 等 - 这可能看起来像reinforcement learning 循环。

from tkinter import *

class GraphicalInterface:
##Initialisation of the GUI class.
    def __init__(self, height, width):
        self.blockColor = 'DarkSeaGreen3'
        self.block_size=75
        self.padding=1
        self.frame_height = height*self.block_size
        self.frame_width = width*self.block_size
        self.root = Tk()
        self.root.resizable(width=0, height=0)
        self.height = height
        self.width = width
        
        self.frm = Frame(self.root, height=self.frame_height+8+self.padding*(height*2),
                         width=self.frame_width+8+self.padding*(width*2), background='lightgray',
                         cursor='circle', relief='sunken', borderwidth=4)
        self.frm.grid_propagate(0)
        self.frm.grid(column=0, row=0, padx=20, pady=20)
        for i in range(0,width):
            for j in range(0,height):
                cur_frame = Frame(self.frm, background=self.blockColor, height=self.block_size, width=self.block_size)
                cur_frame.grid(column=i,row=j, padx=self.padding, pady=self.padding)

    def create_circle(self, x, y, r, canvasName, color):  # center coordinates, radius       https://stackoverflow.com/questions/17985216/simpler-way-to-draw-a-circle-with-tkinter
        x0 = x - r
        y0 = y - r
        x1 = x + r
        y1 = y + r
        return canvasName.create_oval(x0, y0, x1, y1, fill=color)

    def setObstacle(self, x, y):
        cv = Canvas(self.frm, height=self.block_size-15, width=self.block_size-15, background= self.blockColor, highlightthickness=0)
        self.create_circle(x = cv.winfo_reqheight()/2, y=cv.winfo_reqwidth()/2, r=30, canvasName=cv, color='black')
        cv.grid(column=x, row=y, padx=0, pady=0)

    def setAgent(self, x, y):
        cv = Canvas(self.frm, height=self.block_size-15, width=self.block_size-15, background=self.blockColor, highlightthickness=0)
        self.create_circle(x=cv.winfo_reqheight()/2, y=cv.winfo_reqwidth()/2, r=25, canvasName=cv, color='firebrick4')
        cv.grid(column=x, row=y)

    def set_all(self):
        for i in range(self.width):
            for j in range(self.height):
                self.setObstacle(i, j)
                self.root.update()
                self.root.after(250)  # like time.sleep()
                
    def run(self):
        #self.root.after(100, self.setObstacle, 0, 0)
        self.root.after(100, self.set_all)
        self.root.mainloop()
        
GraphicalInterface(5, 5).run()        

【讨论】:

    猜你喜欢
    • 2021-07-26
    • 2018-12-16
    • 2020-09-02
    • 1970-01-01
    • 1970-01-01
    • 2018-05-06
    • 2014-05-29
    • 2015-10-18
    • 2018-04-19
    相关资源
    最近更新 更多