You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt绘制对称分形树遇递归逻辑问题求助

PyQt 对称分形树递归问题解决办法

我看了你尝试用PyQt绘制对称分形树的两段代码,问题核心都出在递归时的画家状态管理上——没有正确恢复平移、旋转的状态,导致分支的位置偏移,破坏了树形的对称性。下面我帮你分析问题并给出修正后的代码:

原代码的问题分析

第一段代码的问题

在右分支的绘制逻辑中,你多添加了一行不必要的p.translate(0, len):

p.setTransform(self.transform)
self.transform = p.transform()
p.rotate(-self.angle)
p.translate(0, len)  # 这里是多余的!
self.branch(p, len)

这个平移操作会让右分支的起点向下偏移,直接打破了左右分支的对称关系。

第二段代码的问题

递归调用后,旋转和平移的顺序混乱,且没有正确恢复画家的初始状态。每次递归修改的画家状态会影响后续分支,导致树形逐渐偏移,无法保持对称。

修正后的代码

解决这个问题的关键是利用QPainter的save()和restore()方法来管理状态——每次递归绘制分支前保存当前画家状态,绘制完成后恢复,这样就不会让平移、旋转操作互相干扰:

from PyQt5 import QtGui, QtWidgets, QtCore
import sys

class Arena(QtWidgets.QWidget):
    def __init__(self):
        super(Arena, self).__init__()
        self.angle = 45
        self.recursions = 10
        self.setGeometry(2500, 400, 500, 500)
        self.origin = (self.width()/2, self.height())
        self.pal = QtGui.QPalette()
        self.pal.setColor(QtGui.QPalette.Background, QtGui.QColor(0, 0, 0))
        self.setPalette(self.pal)
        self.pen_branch = QtGui.QPen()
        self.pen_branch.setColor(QtGui.QColor(255, 255, 255))
        self.init_UI()

    def init_UI(self):
        self.slider_angle = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
        self.slider_angle.setMinimum(-8000)
        self.slider_angle.setMaximum(8000)
        self.slider_angle.setGeometry(0, 50, self.width(), 50)
        self.slider_angle.valueChanged.connect(self.setAngleValue)
        self.setAngleValue(4500)
        self.slider_angle.setValue(4500)

    def setAngleValue(self, value):
        self.angle = value / 100
        self.update()

    def branch(self, p, length):
        # 绘制当前分支
        p.drawLine(0, 0, 0, -length)
        if length > 3:
            # 保存当前画家状态(平移、旋转等)
            p.save()
            # 移动到当前分支的末端
            p.translate(0, -length)
            # 绘制左分支:旋转指定角度后递归
            p.rotate(self.angle)
            self.branch(p, length * 0.66)
            # 恢复到保存的状态,准备绘制右分支
            p.restore()

            # 再次保存状态,绘制右分支
            p.save()
            p.translate(0, -length)
            # 旋转负角度,保证对称
            p.rotate(-self.angle)
            self.branch(p, length * 0.66)
            p.restore()

    def paintEvent(self, e):
        p = QtGui.QPainter(self)
        p.setRenderHint(QtGui.QPainter.Antialiasing)
        p.setPen(self.pen_branch)
        p.drawText(20, 20, f'angle: {self.angle:.2f}')
        
        # 移动到画布底部中心,作为树干的起点
        p.translate(self.width() / 2, self.height())
        # 绘制树干并启动递归
        self.branch(p, 100)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    arena = Arena()
    arena.show()
    app.exec_()

关键改进点

  • 使用p.save()和p.restore()替代手动保存/设置transform,状态管理更可靠
  • 左右分支的绘制逻辑完全对称:都是先平移到分支末端,再旋转对应角度后递归
  • 移除了所有多余的平移、旋转操作,保证每个分支的起点位置正确

运行这段代码后,你拖动滑块调整角度时,就能得到完美对称的分形树了!

内容的提问来源于stack exchange,提问作者Pau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 17:18:10