我正在尝试使用 PyQt5 编写深度优先递归回溯迷宫生成器。从功能上讲,一切正常,但并非所有内容都已实现,因此结果可能看起来很奇怪:)。我应该说我对Python和PyQt很陌生。我在图形更新时遇到了问题。我希望窗口根据算法的结果更新图形,该算法在 App 类go
函数中的while
循环中运行。我做了一些研究,但没有任何效果。人们告诉我只添加像self.show()
或self.update()
这样的行,但这些都不起作用。
我知道我可能在概念上做错了什么,例如,我应该将代码的某些部分放在其他地方,或者类似的东西。或者也许有一两行可以放在某个地方以使其工作。
无论哪种情况,请帮助我。
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_())
下面是一个脚本版本,展示了如何使用QApplication.processEvents
、计时器和睡眠来制作一些简单的动画。我冒昧地添加了用于开始新运行的 F5 快捷方式,并整理了其他一些内容:
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_())