Reputation: 175
Hello, Recently I have been working on creating a graphical representation of a sorting algorithm. Currently however I am stuck trying to find a way to update the gui elements overtime compared to all the elements being sorted at once when the for loop is completely finished. To fix this issue I tried using pythons threading library to run the method(loop) in its own thread where it should be able to run over the course of multiple frames instead of just one, however this lead to the same result or sometimes all the gui elements would dissapear (would still exist just not visible on screen)
Have The ability to watch the gui elements update over the course of x amount of time to show the progress of the sorting algorithm
Actual : The for loop waits till completion before updating all gui elements Expected: Update gui elements overtime (x amount of seconds)
Around Line 45 is where I run the algorithm, The Method I tried for threading is shown just above that at line 40
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout
import sys
import random
class MRE(QWidget):
def __init__(self):
super().__init__()
#initialized Values
self.n = 250 # n is the Number Of Values In the array to be sorted
self.values = [] #Holds all the Rectangle Objects that are in the Graphics Scene
# Set Layout
grid = QGridLayout()
self.setLayout(grid)
# Set Size of Window
self.resize(600, 400)
# Set Widgets
self.sortingGraphic = QtWidgets.QGraphicsView(self)
self.sortingGraphic.resize(600,400)
# Setup Scene View
self.scene = QtWidgets.QGraphicsScene()
self.sortingGraphic.setScene(self.scene)
# Open Application
self.show()
def main(self):
self.scene.setSceneRect(0, 0, self.sortingGraphic.width() - 5, self.sortingGraphic.height() - 5)
self.value_gen() #Generates Random Values to Array Change n (in __init__) to change amount
#---- Help! ----
# Also Tried the Following
#import threading
#threading.Thread(self.bubbleSort()).start()
# Runs Bubble Sort Algorithm that will sort the Values in order
self.bubbleSort()
def bubbleSort(self):
n = len(self.values)
for i in range(n - 1):
for j in range(0, n - i - 1):
if self.values[j].scenePos().y() > self.values[j + 1].scenePos().y():
# Update Graphic Positions
self.switch(self.values[j], self.values[j + 1])
# Update Position in List
self.values[j], self.values[j + 1] = self.values[j + 1], self.values[j]
def switch(self, a: QtWidgets.QGraphicsRectItem, b: QtWidgets.QGraphicsRectItem):
#Holds temporary values of each item
temp_a = a.scenePos()
temp_b = b.scenePos()
# Updates Graphics View and swaps positions
a.setPos(temp_b.x(), temp_a.y())
b.setPos(temp_a.x(), temp_b.y())
def value_gen(self):
# Grab the Size of the View and calculate width of each line
width = (self.sortingGraphic.geometry().width() - 5) / self.n
for value in range(self.n):
# Randomizes Height Between 0 and Height of Screen
height = random.randrange(0, self.sortingGraphic.geometry().height() - 5)
# Create Rect Item
rect_item = QtWidgets.QGraphicsRectItem(QtCore.QRectF(0, 0, width, height))
rect_item.setPos(width * value, self.sortingGraphic.height() - height)
# Adds Item to Values List
self.values.append(rect_item)
# Adds Rect item to Screen
self.scene.addItem(rect_item)
if __name__ == '__main__':
app = QApplication(sys.argv)
mre = MRE()
mre.main()
sys.exit(app.exec_())
If anyone has any ideas on what I could try it would be greatly appreciated, thank you!
Upvotes: 0
Views: 214
Reputation: 243897
The objective of visualizing an algorithm is not to visualize its speed but the behavior of the data, so in this case, a timer that executes each pass in t seconds is enough as shown below:
import random
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
def bubbleSort(elements, switch, compare):
n = len(elements)
for i in range(n - 1):
for j in range(0, n - i - 1):
if compare(elements[j], elements[j + 1]):
switch(elements[j], elements[j + 1])
elements[j], elements[j + 1] = (
elements[j + 1],
elements[j],
)
yield
class MRE(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.n = 100
self.items = []
self.resize(600, 400)
self.view = QtWidgets.QGraphicsView()
self.view.setRenderHints(QtGui.QPainter.Antialiasing)
self.view.scale(1, -1)
self.scene = QtWidgets.QGraphicsScene()
self.view.setScene(self.scene)
grid = QtWidgets.QGridLayout(self)
grid.addWidget(self.view)
self.timer = QtCore.QTimer(interval=10, timeout=self.next_step)
def main(self):
self.value_gen()
self.start_algorithm()
self.show()
def value_gen(self):
height = 100
width = 2
for value in range(self.n):
h = random.randrange(0, height)
item = self.scene.addRect(QtCore.QRectF(0, 0, width, h))
item.setPos(2 * value * width, 0)
item.setPen(QtGui.QPen(QtCore.Qt.NoPen))
item.setBrush(QtGui.QColor("black"))
self.items.append(item)
self.fix_size()
def start_algorithm(self):
self.algorithm = bubbleSort(self.items, self.switch, self.compare)
self.timer.start()
def next_step(self):
try:
next(self.algorithm)
except StopIteration:
self.timer.stop()
def switch(self, item_a, item_b):
pos_a = item_a.scenePos()
pos_b = item_b.scenePos()
item_a.setPos(pos_b)
item_b.setPos(pos_a)
self.fix_size()
def compare(self, item_a, item_b):
return item_a.rect().height() < item_b.rect().height()
def fix_size(self):
self.view.fitInView(self.scene.itemsBoundingRect())
def resizeEvent(self, event):
self.fix_size()
super().resizeEvent(event)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mre = MRE()
mre.main()
sys.exit(app.exec_())
Upvotes: 2