直到循环结束后才更新Tkinter窗口

2024-09-30 02:34:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直想用python制作一个排序算法可视化工具,并决定使用Tkinter库作为我可视化数据的方式(如果有人有更好的库可以使用,我愿意接受建议,我查看了matplotlib,但不太愿意)。我的问题是,在对数组排序时,我想进行交换,在交换之后显示更新的数组,然后继续排序;但最终的结果是数组排序,然后更新整个排序的数组。你知道吗

import tkinter as tk
from tkinter import ttk
import random
import time

class SortingVisualizer(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.wm_title(self, "Sorting Visualizer")
        tk.Tk.wm_minsize(self, width=600, height=500)
        tk.Tk.wm_resizable(self, width=False, height=False)


        self.topFrame = tk.Frame(self)
        self.topFrame.grid(row=0, sticky='w')

        self.sortOptions = ['Select Algorithm','Bubble sort','Quicksort', 'Merge sort']
        self.optionVar = tk.StringVar()
        self.optionDrop = ttk.OptionMenu(self.topFrame, self.optionVar, *self.sortOptions)
        self.optionDrop.config(width=15)
        self.optionDrop.grid(row=0, column=1, sticky='ew')

        self.sortButton = ttk.Button(self.topFrame, text = "Sort", command = lambda: bubbleSort(self))
        self.sortButton.grid(row=0, column=2, sticky='w')
        self.genButton = ttk.Button(self.topFrame, text = "Generate New Array", command = self.newArray)
        self.genButton.grid(row=0, column=0)

        self.generateArray()

    def newArray(self):
        self.sortCanvas.destroy()
        self.generateArray()

    def generateArray(self):
        self.array = []
        self.numOperations = 0
        i = 0
        while i < 15:
            height = random.randint(15, 200)
            self.array.append(height)
            i = i + 1
        self.drawCanvas()

    def drawCanvas(self):
        self.sortCanvas = tk.Canvas(self, width=600, height=450)
        self.sortCanvas.grid(row=1)
        self.sortCanvas.create_line(15, 15, 585, 15)
        label = "Number of Operations: " + str(self.numOperations)
        self.numLabel = tk.Label(self.topFrame, text = label)
        self.numLabel.grid(row=1)

        bar_width = 20
        bar_gap = bar_width + 10
        start_x = 30
        start_y = 15
        for bar_height in self.array:
            x1 = start_x + bar_width
            y1 = start_y + bar_height
            self.sortCanvas.create_rectangle(start_x, start_y, x1, y1*2, fill='green')
            start_x = start_x + bar_gap

    def redrawCanvas(self):
        self.sortCanvas.destroy()
        self.drawCanvas()

def bubbleSort(self):
    n = len(self.array)
    for i in range(n):
        for j in range(0, n-i-1):
            if self.array[j]>self.array[j+1]:
                temp = self.array[j]
                self.array[j] = self.array[j+1]
                self.array[j+1] = temp
                self.numOperations += 1
                self.after(300, self.redrawCanvas)

app = SortingVisualizer()
app.mainloop()

我也试过了应用程序后(300, 自重绘画布)得到同样的结果


Tags: self排序defbar数组widtharraystart
3条回答

你做了一个非常好的第一次尝试,你几乎到了那里。我在您的代码中做了一些更改,最重要的是引入了一个root对象(tk.Tk()),所以我可以这样做根目录更新()以便在新方法blip_canvas中重新绘制到sort_canvas。为了避免一些“闪烁”而不是每次都破坏画布,最好只删除“bar”元素。 此外,我还随意更改了一些变量名,使其更具python风格(应该使用下划线而不是大写),并添加了if _name__ == '__main__'语句。你知道吗

请看下面的代码。你知道吗

import tkinter as tk
from tkinter import ttk
import random

class SortingVisualizer:

    def __init__(self):
        self.root = tk.Tk()
        self.root.wm_title("Sorting Visualizer")
        self.root.wm_minsize(width=600, height=500)
        self.root.wm_resizable(width=False, height=False)

        self.top_frame = tk.Frame(self.root)
        self.top_frame.grid(row=0, sticky='w')

        self.sort_options = ['Select Algorithm', 'Bubble sort', 'Quicksort', 'Merge sort']
        self.option_var = tk.StringVar()
        self.option_drop = ttk.OptionMenu(
            self.top_frame, self.option_var, *self.sort_options)
        self.option_drop.config(width=15)
        self.option_drop.grid(row=0, column=1, sticky='ew')

        self.sort_button = ttk.Button(
            self.top_frame, text="Sort", command=self.bubble_sort)
        self.sort_button.grid(row=0, column=2, sticky='w')

        self.gen_button = ttk.Button(
            self.top_frame, text="Generate New Array", command=self.new_array)
        self.gen_button.grid(row=0, column=0)

        self.sort_canvas = tk.Canvas(self.root)
        self.bars = []

    def new_array(self):
        self.generate_array()
        self.blip_canvas()

    def generate_array(self):
        self.array = []
        self.num_operations = 0
        i = 0
        while i < 15:
            height = random.randint(15, 200)
            self.array.append(height)
            i = i + 1

    def draw_canvas(self):
        label = "Number of Operations: " + str(self.num_operations)
        self.num_label = tk.Label(self.top_frame, text=label)
        self.num_label.grid(row=1)

        self.sort_canvas = tk.Canvas(self.root, width=600, height=450)
        self.sort_canvas.grid(row=1)
        self.sort_canvas.create_line(15, 15, 585, 15)

        bar_width = 20
        bar_gap = bar_width + 10
        start_x = 30
        start_y = 15
        self.bars = []
        for bar_height in self.array:
            x1 = start_x + bar_width
            y1 = start_y + bar_height
            self.bars.append(self.sort_canvas.create_rectangle(
                start_x, start_y, x1, y1*2, fill='green'))
            start_x = start_x + bar_gap

    def blip_canvas(self):
        self.sort_canvas.delete(self.bars)
        self.draw_canvas()
        self.root.update()
        self.root.after(200)

    def bubble_sort(self):
        n = len(self.array)
        for i in range(n):
            for j in range(n-i-1):
                if self.array[j] > self.array[j+1]:
                    self.array[j], self.array[j+1] = self.array[j+1], self.array[j]
                    self.num_operations += 1
                    self.blip_canvas()

    def start(self):
        tk.mainloop()


if __name__ == '__main__':
    app = SortingVisualizer()
    app.start()

注意在bubble\u排序中,不需要temp变量来交换array[j]和array[j+1]的值

而不是使用time.sleep(0.2)来设置我使用的延迟:

self.root.update()
self.root.after(200)

Update button after delay所示

您也可以坚持原来的代码,只做一些更改。
1) 更改排序按钮

self.sortButton = ttk.Button(self.topFrame, text = "Sort", command=self.bubbleSort)

2)缩进要与SortingVisualizer对齐的bubbleSort方法

3)将方法redrawCanvas更改为:

    def redrawCanvas(self):
        self.sortCanvas.destroy()
        self.drawCanvas()
        self.update()
        self.after(300)

以及

4)在bubbleSort中调用redrawCanvas

        for j in range(0, n-i-1):
            if self.array[j]>self.array[j+1]:
                temp = self.array[j]
                self.array[j] = self.array[j+1]
                self.array[j+1] = temp
                self.numOperations += 1
                self.redrawCanvas()

瞧,会有用的!你知道吗

你可以Thread你的函数bubbleSort。而且bubbleSort作为类的一个方法似乎更有意义:

import threading, time

class SortingVisualizer(tk.Tk):
    def __init__(self, *args, **kwargs):
        ...

        self.sortButton = ttk.Button(self.topFrame, text = "Sort", command = lambda: threading.Thread(target=self.bubbleSort).start())

        ...

    ...


    def bubbleSort(self):
        n = len(self.array)
        for i in range(n):
            for j in range(0, n-i-1):
                if self.array[j]>self.array[j+1]:
                    temp = self.array[j]
                    self.array[j] = self.array[j+1]
                    self.array[j+1] = temp
                    self.numOperations += 1
                    self.redrawCanvas()
                    time.sleep(0.1)

只是线程之外的另一种解决方案。我曾经遇到过这样一个问题:通过线程化函数,它们可能同时访问一些外部设备(我创建了一个GUI来监视一些硬件),并导致冲突。通过使用.after(),tkinter将处理任务的顺序以避免冲突。你知道吗

您可以重新定义您的bubbleSort函数,以便通过再次调用该函数,for循环的每次迭代都将更改为递归。你知道吗

def bubbleSort(self, i = 1, j = 0):
    n = len(self.array)
    if self.array[j]>self.array[j+1]:
        temp = self.array[j]
        self.array[j] = self.array[j+1]
        self.array[j+1] = temp
        self.numOperations += 1
    j += 1
    if j == n-i-1:
        j = 0
        i += 1
    if i < n:
        self.after(1, lambda: self.bubbleSort(i,j))

相关问题 更多 >

    热门问题