Как обновлять графический интерфейс tkinter при каждом движении?

1

Проблема в том, что я сделал короткий алгоритм, который находит его через лабиринт и отмечает все квадраты, которые он посетил синим цветом. Основная программа работает нормально, но проблема в том, что GUI отображает только лабиринт с посещенными квадратами после завершения всего процесса. Обычно это не проблема, но мне нужно уметь заметно видеть, как алгоритм проходит лабиринт по мере его появления. Проблема в том, что когда я UpdateMaze функцию 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()
Теги:
tkinter

1 ответ

0
Лучший ответ

Я думаю, что следующее - это то, что показывает основы того, как делать то, что вы хотите. Он использует tkinter универсальный after() метода периодически вызывать make_move() метод, который в конечном итоге вызывает update_maze() для повторных лабиринтов следующих каждого хода.

Возможно, это не похоже на то, что происходит, но через некоторое время вы увидите, что отображаемый лабиринт изменился. Это непредсказуемо точно, как долго это происходит из-за использования random модуля, который я представил для генерации того, каким должен быть следующий шаг, поскольку я действительно не понимаю логики для этого в функции Move() в вашем примере кода. Это то, что, вероятно, понадобится "фиксировать" для taylor, чтобы оно точно для всего, что вы пытаетесь выполнить.

Примечание. Я также изменил свой код, чтобы он больше соответствовал руководству PEP 8 - Style для кода Python в отношении форматирования кода и наименования классов, функций, переменных и т.д., Чтобы сделать его более читаемым (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()

PS Для всех, кого это интересует, вот изображения .gif которые я сделал и использовал для тестирования (чтобы вы могли загрузить их для запуска кода):

  • MazePiece_Finish.gif Изображение 174551
  • MazePiece_Outer.gif ! Изображение 174551
  • MazePiece_Space.gif Изображение 174551
  • MazePiece_Visited.gif Изображение 174551
  • MazePiece_Wall.gif Изображение 174551
  • 0
    Большое спасибо. Возврат функции 'move' в основном возвращает false, если 'ветвь' тестируемого лабиринта является тупиком. Это делается путем тестирования соседних ячеек целевой ячейки, а затем повторного запуска себя в одной из соседних ячеек. Он делает это рекурсивно, пока у целевой ячейки нет других опций (тупик). В этот момент он возвращает False, что, в свою очередь, заставляет все остальные итерации функции также возвращать False. По сути, если он возвращает false, это тупик. Если он возвращает истину, то его нет. (Я не лучший в объяснении)
  • 0
    Оскар: Ваше объяснение вашей функции Move() приветствуется - теперь оно имеет для меня гораздо больше смысла. Однако код в моем опубликованном ответе на самом деле не делает то, что, как я теперь думаю, вы хотите (то есть для анимации обработки функции). Проблема в том, что функция изменяет содержимое лабиринта только в одном месте, когда выполняет Maze.maze[y][x] = 3 , и делает это только изредка. Я думаю, что вам нужно разработать какой-то анимированный способ показать, что делает его внутренняя логика. Если вы можете сделать это, я смогу обновить мой ответ, если вы не можете понять, как это сделать из существующего кода.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню