I am trying to write a depth first recursive backtracking maze generator with PyQt5. Functionally everything works fine, but not everything is implemented yet, so result may look strange :). I should say that I am quite new to Python and PyQt. I ran into a problem with graphics update. I would like the window to update the graphics based on the outcome of the algorithm which runs in a while
loop in go
function in App class. I did some research but nothing works. People tell me to just add line like self.show()
or self.update()
but none of this works.
I understand that I may have done something wrong conceptually, eg I should place some part of code somewhere else, or something like that. Or maybe there is some line or two to place somewhere to make it work.
In either case, please help me.
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow
from PyQt5.QtGui import QPainter, QPen, QColor
from PyQt5.QtCore import *
import math
import random
import pygame
w = 40
grid = []
qp = QPainter()
clock = pygame.time.Clock()
class Cell(QMainWindow):
def __init__(self, i, j):
# super().__init__()
self.i = i
self.j = j
self.walls = [1, 1, 1, 1] # top, right, bottom, left
self.visited = 0
self.currentCell = 0
def index(self, i, j, cols, rows):
if (i < 0) or (j < 0) or (i > (cols - 1)) or (j > (rows - 1)):
return None
else:
return i + j * cols
def checkNeighbors(self, cols, rows):
neighbors = []
if not (self.index(self.i, self.j - 1, cols, rows) is None):
top = grid[self.index(self.i, self.j - 1, cols, rows)]
if not (self.index(self.i + 1, self.j, cols, rows) is None):
right = grid[self.index(self.i + 1, self.j, cols, rows)]
if not (self.index(self.i, self.j + 1, cols, rows) is None):
bottom = grid[self.index(self.i, self.j + 1, cols, rows)]
if not (self.index(self.i - 1, self.j, cols, rows) is None):
left = grid[self.index(self.i - 1, self.j, cols, rows)]
if 'top' in locals() and not top.visited:
neighbors.append(top)
if 'right' in locals() and not right.visited:
neighbors.append(right)
if 'bottom' in locals() and not bottom.visited:
neighbors.append(bottom)
if 'left' in locals() and not left.visited:
neighbors.append(left)
if neighbors.__len__() > 0:
r = math.floor(random.uniform(0, neighbors.__len__()))
return neighbors[r]
else:
return None
class App(QWidget):
def __init__(self):
super().__init__()
self.left = 100
self.top = 100
self.width = 400
self.height = 400
self.cols = math.floor(self.width/w)
self.rows = math.floor(self.height/w)
self.init_cells()
self.initui()
self.go()
def init_cells(self):
for j in range(self.rows):
for i in range(self.cols):
cell = Cell(i, j)
grid.append(cell)
def go(self):
current = grid[0]
current.visited = 1
current.currentCell = 1
next = current.checkNeighbors(self.cols, self.rows)
while not (next is None):
next = current.checkNeighbors(self.cols, self.rows)
if not (next is None):
next.visited = 1
next.currentCell = 1
current.currentCell = 0
current = next
# I WANT TO UPDATE WINDOW HERE!
def initui(self):
self.setGeometry(self.left, self.top, self.width, self.height)
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.lightGray)
self.setPalette(p)
self.show()
def paintEvent(self, e):
for i in grid:
self.draw_cell(i)
self.show()
def draw_cell(self, cell):
x = cell.i*w
y = cell.j*w
# LINES
qp.begin(self)
qp.setPen(QPen(Qt.black, 1, Qt.SolidLine))
if cell.walls[0]: # top
qp.drawLine(x , y , x + w, y)
if cell.walls[1]: # right
qp.drawLine(x + w, y , x + w, y + w)
if cell.walls[2]: # bottom
qp.drawLine(x + w, y + w, x , y + w)
if cell.walls[3]: # left
qp.drawLine(x , y + w, x , y)
if cell.visited:
qp.setBrush(QColor(255, 0, 255, 100))
qp.drawRect(x, y, w, w)
if cell.currentCell:
qp.setBrush(QColor(0, 255, 0, 255))
qp.drawRect(x, y, w, w)
qp.end()
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Below is a version of your script that shows how to do some simple animation using QApplication.processEvents
, a timer, and sleep. I took the liberty of adding an F5 shortcut for starting a new run, and have tidied up a few other things:
import sys, math, random
from PyQt5.QtWidgets import QApplication, QWidget, QShortcut
from PyQt5.QtGui import QPainter, QPen, QColor, QKeySequence
from PyQt5.QtCore import Qt, QTimer, QThread
WIDTH = 40
grid = []
class Cell():
def __init__(self, i, j):
self.i = i
self.j = j
self.walls = [1, 1, 1, 1] # top, right, bottom, left
self.visited = 0
self.currentCell = 0
def index(self, i, j, cols, rows):
if (i < 0) or (j < 0) or (i > (cols - 1)) or (j > (rows - 1)):
return None
else:
return i + j * cols
def checkNeighbors(self, cols, rows):
neighbors = []
if not (self.index(self.i, self.j - 1, cols, rows) is None):
top = grid[self.index(self.i, self.j - 1, cols, rows)]
if not (self.index(self.i + 1, self.j, cols, rows) is None):
right = grid[self.index(self.i + 1, self.j, cols, rows)]
if not (self.index(self.i, self.j + 1, cols, rows) is None):
bottom = grid[self.index(self.i, self.j + 1, cols, rows)]
if not (self.index(self.i - 1, self.j, cols, rows) is None):
left = grid[self.index(self.i - 1, self.j, cols, rows)]
if 'top' in locals() and not top.visited:
neighbors.append(top)
if 'right' in locals() and not right.visited:
neighbors.append(right)
if 'bottom' in locals() and not bottom.visited:
neighbors.append(bottom)
if 'left' in locals() and not left.visited:
neighbors.append(left)
if len(neighbors) > 0:
r = math.floor(random.uniform(0, len(neighbors)))
return neighbors[r]
else:
return None
class App(QWidget):
def __init__(self):
super().__init__()
self.left = 100
self.top = 100
self.width = 400
self.height = 400
self.cols = math.floor(self.width / WIDTH)
self.rows = math.floor(self.height / WIDTH)
self.active = False
self.initui()
self.init_cells()
def init_cells(self):
if not self.active:
del grid[:]
for j in range(self.rows):
for i in range(self.cols):
cell = Cell(i, j)
grid.append(cell)
QTimer.singleShot(1, self.go)
def go(self):
self.active = True
current = grid[0]
current.visited = 1
current.currentCell = 1
while True:
self.update()
QApplication.processEvents()
QThread.msleep(150)
next = current.checkNeighbors(self.cols, self.rows)
if next is not None:
next.visited = 1
next.currentCell = 1
current.currentCell = 0
current = next
else:
break
self.active = False
def initui(self):
QShortcut(QKeySequence('F5'), self, self.init_cells)
self.setGeometry(self.left, self.top, self.width, self.height)
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.lightGray)
self.setPalette(p)
self.show()
def paintEvent(self, e):
for i in grid:
self.draw_cell(i)
def draw_cell(self, cell):
x = cell.i * WIDTH
y = cell.j * WIDTH
# LINES
qp = QPainter(self)
qp.setPen(QPen(Qt.black, 1, Qt.SolidLine))
if cell.walls[0]: # top
qp.drawLine(x , y , x + WIDTH, y)
if cell.walls[1]: # right
qp.drawLine(x + WIDTH, y , x + WIDTH, y + WIDTH)
if cell.walls[2]: # bottom
qp.drawLine(x + WIDTH, y + WIDTH, x , y + WIDTH)
if cell.walls[3]: # left
qp.drawLine(x , y + WIDTH, x , y)
if cell.visited:
if cell.currentCell:
qp.setBrush(QColor(0, 255, 0, 255))
else:
qp.setBrush(QColor(255, 0, 255, 100))
qp.drawRect(x, y, WIDTH, WIDTH)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.