使用PyQt5开发国际象棋项目时可移动区域高亮失效的解决方法
问题根源
你的标记完全不生效本质是两个核心问题导致的:
- 绘制流程错位:PyQt 的窗口重绘机制是自动触发的,正常执行
paintEvent时会先跑完drawRectangles逻辑,把整个棋盘的黑白格子全部绘制一遍,直接把你手动在reachable_cells里画的标记完全覆盖。而且你在reachable_cells里手动创建QPainter调用begin(self)的操作,完全绕开了Qt官方的重绘流程,绘制内容会在下一次自动重绘时被冲掉,根本留不住。 - 变量不一致的低级bug:你在
drawRectangles里用的格子尺寸是self.case,但reachable_cells里却用了self.size作为绘制尺寸,就算流程对了,坐标位置也会完全错位,根本对不齐格子。
正确实现思路
不需要单独写一个触发式的绘制函数,把所有绘制逻辑统一收敛到paintEvent流程里,通过状态驱动绘制即可:
- 在类的初始化方法里新增一个状态变量,比如
self.selected_piece_moves = [],用来存储当前选中棋子对应的所有可移动格子坐标,初始为空列表。 - 保留你原本的
drawRectangles绘制逻辑,在画完所有基础黑白棋盘格之后,紧接着遍历状态变量里存的可移动格子坐标,叠加自定义的标记效果(不管是改底色还是画图标都可以)。 - 在鼠标点击的事件处理逻辑里,检测到用户点中己方棋子时,计算出该棋子的所有合法移动坐标,赋值给
self.selected_piece_moves,然后调用self.update()触发窗口自动重绘就行,不要手动创建QPainter执行绘制。
两种标记效果的实现示例
半透明底色标记
如果想给可移动格子叠一层红色标记,不需要完全替换原本的黑白配色,用半透颜色就可以在drawRectangles走完之后追加这段绘制逻辑:
# 已完成基础棋盘绘制后追加 if self.selected_piece_moves: # 第四个参数是透明度,100是半透效果 qp.setBrush(QtGui.QColor(255, 0, 0, 100)) for col, row in self.selected_piece_moves: # 坐标计算完全和drawRectangles对齐,统一用self.case当格子尺寸 qp.drawRect(100 + col * self.case, row * self.case, self.case, self.case)
叠加圆形图标标记
这种方式更直观,完全不会破坏棋盘原本的配色,实现逻辑也更简单:
if self.selected_piece_moves: qp.setBrush(QtGui.QColor(0, 120, 255, 180)) for col, row in self.selected_piece_moves: # 计算每个格子的中心点 cell_center_x = 100 + col * self.case + self.case / 2 cell_center_y = row * self.case + self.case / 2 # 在格子中心画直径为格子一半大小的实心圆 qp.drawEllipse( cell_center_x - self.case / 4, cell_center_y - self.case / 4, self.case / 2, self.case / 2 )
注意事项
- 坐标偏移要和原逻辑完全对齐:你原本的
drawRectangles里行坐标是从1到8遍历的,也就是第一行实际绘制位置是1*self.case,计算可移动格子坐标的时候要匹配这个偏移,别把最顶行的位置漏了。 - 不要在
paintEvent之外手动调用QPainter.begin(self):这种操作很容易引发设备上下文错乱、绘制内容不刷新的问题,所有需要更新界面的场景只要修改对应状态变量,调用self.update()即可,Qt会自动调度重绘流程。 - 当用户取消选中棋子(比如点击空白位置、选中其他棋子)时,把
self.selected_piece_moves清空,再调用一次self.update(),之前的标记就会自动消失。
内容的提问来源于stack exchange,提问作者Arthur Cassou
相关产品推荐
相关产品推荐

