我一直想用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,self.redrawCanvas)之后,并得到相同的结果
只是线程之外的另一种解决方案。我曾经遇到过这样一个问题:通过线程化函数,它们可能同时访问一些外部设备(我创建了一个GUI来监视一些硬件),并导致冲突。通过使用。在()之后,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))
您可以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)
你做了一次很好的第一次尝试,你几乎成功了。我对您的代码做了一些更改,最重要的是引入了root
对象(tk.tk()
),这样我就可以使用root了。update()以新方法重新绘制到排序画布
。为了避免一些“闪烁”,而不是每次都破坏画布,最好只删除“bar”元素。此外,我还随意更改了一些变量名,使其更具python风格(应该使用下划线而不是大写),并添加了if\u name\uuuuu=='\uuuu main\uuu'
语句。
看看下面的代码。
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_排序中,不需要temp变量来交换数组[j]和数组[j 1]的值
而不是使用时间。sleep(0.2)
设置我使用的延迟:
self.root.update()
self.root.after(200)
如延迟后更新按钮中所示
您也可以坚持原来的代码,只做一些更改
1)更改排序按钮
self.sortButton = ttk.Button(self.topFrame, text = "Sort", command=self.bubbleSort)
2) 缩进要与SortingVisualizer对齐的bubbleSort方法
3)更改方法redraCanvas:
def redrawCanvas(self):
self.sortCanvas.destroy()
self.drawCanvas()
self.update()
self.after(300)
和
4) 在bubbleSort中调用重画画布
:
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()
瞧,它会起作用的!
因此,我不确定如何在.setOnAction事件期间计算节点的高度,我已尝试/不确定还要尝试什么我正在尝试在添加节点后查找vBox的高度,但它只是在添加新节点之前打印节点的高度 运行该示例,然后单击将标签添加到vBox并输出的按钮 实际结果: 预期结果: 但是如果你点击打印VBox高度按钮,它会显示正确的高度:
问题内容: 我编写了一个程序,该程序基本上可以在按不同的按钮时绘制不同的数据。该程序可以在Windows下按预期工作,但是当我尝试将其移植到Linux(Red Hat v6)时,我遇到一个奇怪的问题:要绘制的窗口直到关闭主程序后才出现。无论我尝试绘制到哪个数字(图1,2等),或者尝试键入plt.show()等,都会发生这种情况。 我编写的程序几乎有1000行代码,但是我创建了一个具有相同问题的缩写
问题内容: 我有该代码: 它可以很好地上传图像,但是问题是我找不到一种逐一上传图像的方法,我试图将 async 选项 设置为false, 但是它冻结了网络浏览器,直到所有图像都被上传为止,这不是我所需要的。想要,我想以某种方式模拟此 “ async:false” 选项以执行相同的操作,但不冻结Web浏览器。 这该怎么做 ? 问题答案: 您可以创建一个Promise数组,以便在所有Promise都解
主要内容:创建一个空白窗口,设置窗的位置主窗口控件(window)是一切控件的基础,它好比是一台高速运转的机器,而其他控件则相当于这台机器上的部件,比如齿轮、链条、螺丝等等。由此我们知道,主窗口是一切控件的基础,所有的控件的都需要通过主窗口来显示。 Tkinter 提供了一些关于主窗口对象的常用方法,在本节对这些方法做简单的介绍。 创建一个空白窗口 Tkinter 能够很方便地创建一个空白窗口,示例代码如下: 程序运行结果如下: 图1:
问题内容: 我显示了在Ajax调用之前和Ajax调用之后加载DOM的过程,我将其隐藏。由于某些原因,加载图像仅在ajax调用完成之后出现。结果是,除非我输入以下内容,否则加载图像甚至都不会出现。代码如下: 我已经在我的网站上的其他Ajax调用上进行了测试,并且发生了相同的问题。有人解决过这个吗?我正在使用Chrome 26。 编辑:我忘记指定我正在使用 同步 ajax调用。() 问题答案: 这取决
问题内容: 我一直在尝试用Java制作GUI,而不是一直使用“静态”,并且遇到了“ SwingUtilities.invokeLater()”方法。我设法进行了所有设置,但是在运行应用程序时,JPanel上没有任何显示,直到我调整窗口大小为止。有没有解决的办法,或者我做错了吗? 这是我的代码: } 编辑:我知道密码JTextField是一个JPasswordField ..所以忽略它:P 问题答案