如何一步步更新tkinter GUI?

时间:2018-06-21 16:04:14

标签: python tkinter

问题是我做了一个简短的算法,发现它穿过迷宫,并用蓝色标记了它访问过的所有正方形。核心程序工作正常,但问题是在整个过程完成后,GUI仅显示迷宫及其访问的方块。通常这不是问题,但是我必须能够清楚地看到算法在迷宫中移动。问题在于,当我在搜索算法的每次迭代中调用UpdateMaze函数时,它似乎都不会生效,直到整个遍历完成为止。

  • 墙壁图像只是一个黑色正方形GIF
  • 空间图像只是一个白色正方形GIF
  • 边缘图像只是一个红色正方形GIF
  • 完成是绿色正方形GIF
  • 参观的是一个蓝色方形GIF
import tkinter as tk
from tkinter import *
import time

class MazeGUI():
    def __init__(self):
        self.maze =[
            [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
            [4, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 4],
            [4, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 4],
            [4, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 4],
            [4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 4],
            [4, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 4],
            [4, 0, 1, 2, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 4],
            [4, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 4],
            [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
        ]
        self.wall = tk.PhotoImage(file = "MazePiece_Wall.gif")
        self.space = tk.PhotoImage(file = "MazePiece_Space.gif")
        self.edge = tk.PhotoImage(file = "MazePiece_Outer.gif")
        self.visited = tk.PhotoImage(file = "MazePiece_Visited.gif")
        self.finish = tk.PhotoImage(file = "MazePiece_Finish.gif")

    def UpdateMaze(self):
        for y in range(len(self.maze)):
            for x in range(len(self.maze[y])):
                if self.maze[y][x] == 0:
                    label = Label(root, image=self.space,
                                  width=20, height=20).grid(row=y, column=x)
                elif self.maze[y][x] == 1:
                    label = Label(root, image=self.wall,
                                  width=20, height=20).grid(row=y, column=x)
                elif self.maze[y][x] == 2:
                    label = Label(root, image=self.finish,
                                  width=20, height=20).grid(row=y, column=x)
                elif self.maze[y][x] == 3:
                    label = Label(root, image=self.visited,
                                  width=20, height=20).grid(row=y, column=x)
                elif self.maze[y][x] == 4:
                    label = Label(root, image=self.edge,
                                  width=20, height=20).grid(row=y, column=x)


def Move(Maze,x,y):
    if Maze.maze[y][x] == 2:
        return True
    elif Maze.maze[y][x] == 1:
        return False
    elif Maze.maze[y][x] == 3:
        return False
    elif Maze.maze[y][x] == 4:
        return False
    Maze.maze[y][x] = 3
    if ((x < len(Maze.maze)-1 and Move(Maze,x+1, y))
        or (y > 0 and Move(Maze,x, y-1))
        or (x > 0 and Move(Maze,x-1, y))
        or (y < len(Maze.maze)-1 and Move(Maze,x, y+1))):
        return True
    return False

root = Tk()
Maze = MazeGUI()
root.lift()
StartPosX = 1
StartPosY = 1
Move(Maze,StartPosX,StartPosY)
Maze.UpdateMaze()
root.mainloop()

1 个答案:

答案 0 :(得分:0)

我认为以下内容显示了如何做所需的基础知识。它使用tkinter通用after()方法来周期性地调用make_move()方法,该方法最终会在每次移动后调用update_maze()以重新显示迷宫。

看起来好像没有发生任何事情,但是过一会儿您应该会看到显示的迷宫发生了变化。由于使用了我介绍的random模块来生成下一步操作,因此确切需要花费多长时间,因为我真的不了解在Move()函数中执行此操作的逻辑在您的示例代码中。这正是可能需要“修复”以使其完全符合您要完成的目标的目的。

注意:我还更改了代码,以便在代码格式设置以及类,函数,变量等的命名方面更紧密地遵循PEP 8 - Style Guide for Python Code,以使其更具可读性(IMO)。

from random import randint
import tkinter as tk
from tkinter import *
import time

MOVE_DELAY = 1000  # Time delay between moves in millisec.

class MazeGUI():
    SPACE = 0
    WALL = 1
    FINISH = 2
    VISITED = 3
    EDGE = 4

    def __init__(self):
        self.maze = [
            [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
            [4, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 4],
            [4, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 4],
            [4, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 4],
            [4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 4],
            [4, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 4],
            [4, 0, 1, 2, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 4],
            [4, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 4],
            [4, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 4],
            [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
        ]
        self.wall = tk.PhotoImage(file="MazePiece_Wall.gif")        # black
        self.space = tk.PhotoImage(file="MazePiece_Space.gif")      # white
        self.edge = tk.PhotoImage(file="MazePiece_Outer.gif")       # red
        self.finish = tk.PhotoImage(file="MazePiece_Finish.gif")    # green
        self.visited = tk.PhotoImage(file="MazePiece_Visited.gif")  # blue
        self.create_maze()

    def create_maze(self):
        global root

        self.maze_frame = tk.Frame(root)
        self.create_maze_labels()
        self.maze_frame.pack()

    def update_maze(self):
        global root

        self.maze_frame.grid_forget()  # Remove all the existing Labels.
        self.create_maze_labels()
        self.maze_frame.update_idletasks()  # Update display.

    def create_maze_labels(self):
        for y in range(len(self.maze)):
            for x in range(len(self.maze[y])):
                if self.maze[y][x] == self.SPACE:
                    Label(self.maze_frame, image=self.space,
                          width=20, height=20).grid(row=y, column=x)
                elif self.maze[y][x] == self.WALL:
                    Label(self.maze_frame, image=self.wall,
                          width=20, height=20).grid(row=y, column=x)
                elif self.maze[y][x] == self.FINISH:
                    Label(self.maze_frame, image=self.finish,
                          width=20, height=20).grid(row=y, column=x)
                elif self.maze[y][x] == self.VISITED:
                    Label(self.maze_frame, image=self.visited,
                          width=20, height=20).grid(row=y, column=x)
                elif self.maze[y][x] == self.EDGE:
                    Label(self.maze_frame, image=self.edge,
                          width=20, height=20).grid(row=y, column=x)

    def make_move(self, x, y):
        global root

        status = self.move(x, y)
        # if status:  # Not sure what to do with return value...
        self.update_maze()

        # Select a random adjoining cell (dx & dy both +/-1).
        dx, dy = randint(0, 2) - 1, randint(0, 2) - 1
        x, y = x+dx, y+dy  # Next position.
        root.after(MOVE_DELAY, self.make_move, x, y)  # Repeat...

    def move(self, x, y):
        if self.maze[y][x] == self.FINISH:
            return True
        elif self.maze[y][x] == self.WALL:
            return False
        elif self.maze[y][x] == self.VISITED:
            return False
        elif self.maze[y][x] == self.EDGE:
            return False

        # Spot is empty (self.SPACE).
        self.maze[y][x] = self.VISITED

        if ((x < len(self.maze)-1 and self.move(x+1, y))
             or (y > 0 and self.move(x, y-1))
             or (x > 0 and self.move(x-1, y))
             or (y < len(self.maze)-1 and self.move(x, y+1))):
            return True
        return False

root = Tk()
maze = MazeGUI()

start_posx, start_posy = 1, 1
maze.make_move(start_posx, start_posy)
maze.update_maze()
root.mainloop()

P.S。对于感兴趣的人,以下是我制作并用于测试的.gif图像(因此您可以下载它们以运行代码):

  • MazePiece_Finish.gif MazePiece_Finish.gif
  • MazePiece_Outer.gifMazePiece_Outer.gif
  • MazePiece_Space.gif MazePiece_Space.gif
  • MazePiece_Visited.gif MazePiece_Visited.gif
  • MazePiece_Wall.gif MazePiece_Wall.gif