Обновление холста Tkinter в mainloop () - PullRequest
0 голосов
/ 06 декабря 2018

Я пытаюсь создать простую визуализацию Bubble Sort в Tkinter, но я не знаю, как обновить canvas / refresh.

from tkinter import *
import random
height, width = 350,600
randomLines = []
master = Tk()
w = Canvas(master,width=width,height=height)
w.pack()

def drawRandomLines():
    w.delete("all")
    for i in range(width):
        w.create_line(i,0,i,randomLines[i])

def bubbleSort():
    for passnum in range(len(randomLines)-1,0,-1):
        for i in range(passnum):
            if randomLines[i]>randomLines[i+1]:
                temp = randomLines[i]
                randomLines[i] = randomLines[i+1]
                randomLines[i+1] = temp

for i in range(width):
    rnd = random.randint(0,width)
    randomLines.append(rnd)
drawRandomLines()
bubbleSort()
mainloop()

Если я использую drawRandomLines () внутри цикла bubbleSort (), он будет удерживатьсяокно и не покажет холст, пока он не отсортирован

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Tkinter не будет обновлять окно до тех пор, пока очередь важных вещей не будет сделана.Так что вам придется форсировать его, если вы хотите обновлять каждую итерацию.Попробуйте это:

def drawRandomLines():
    w.delete("all")
    for i in range(width):
        w.create_line(i,0,i,randomLines[i])
    w.update()   # Force canvas update
0 голосов
/ 07 декабря 2018

Вы можете использовать after() для замены внешней петли for в bubbleSort() и вызова drawRandomLines() внутри bubbleSort():

from tkinter import *
import random

height, width = 350, 600
thickness = 5

# create the random lines
randomLines = [random.randint(1, height-1) for i in range(0, width, thickness)]

master = Tk()
w = Canvas(master, width=width, height=height)
w.pack()

def drawRandomLines():
    w.delete("all")
    for i in range(len(randomLines)):
        x = i * thickness
        # use bars for more clearly presentation
        w.create_rectangle(x, height, x+thickness, height-randomLines[i], fill='red')

def bubbleSort(passnum):
    for i in range(passnum):
        if randomLines[i] > randomLines[i+1]:
            randomLines[i], randomLines[i+1] = randomLines[i+1], randomLines[i]
    drawRandomLines()
    if passnum > 0:
        master.after(20, bubbleSort, passnum-1)
    else:
        w.create_text(50, 50, text='Done!', font=('Arial', 24))

drawRandomLines() # show initial order of lines
bubbleSort(len(randomLines)-1)

master.mainloop()
0 голосов
/ 06 декабря 2018

Вы захотите использовать after() для управления циклом обновления, который не повлияет на основной цикл.Используя after(), мы можем создавать визуальное обновление с течением времени.Нам понадобится переменная отслеживания для управления индексом в цикле и глобальный оператор для трекера.

Пример:

from tkinter import *
import random
height, width = 350, 600
randomLines = []
master = Tk()
tracker = 0
w = Canvas(master, width=width, height=height)
w.pack()

def drawRandomLines():
    global tracker
    if tracker <= width:
        w.create_line(tracker, 0, tracker, randomLines[tracker])
        tracker += 1
        master.after(10, drawRandomLines)

def bubbleSort():
    for passnum in range(len(randomLines)-1, 0, -1):
        for i in range(passnum):
            if randomLines[i] > randomLines[i+1]:
                temp = randomLines[i]
                randomLines[i] = randomLines[i+1]
                randomLines[i+1] = temp

for i in range(width):
    rnd = random.randint(0, width)
    randomLines.append(rnd)
drawRandomLines()
bubbleSort()
mainloop()
...