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

如何为PySide6的CodeEditor示例添加跨行大括号对代码折叠区域?

实现PySide6 CodeEditor的大括号代码折叠功能

1. 新增折叠状态存储

在原CodeEditor类中添加字典用于记录可折叠块的信息,键为大括号起始行号,值为(结束行号, 是否折叠)的元组:

class CodeEditor(QPlainTextEdit):
    def __init__(self, parent=None):
        super().__init__(parent)
        # 初始化折叠块存储
        self.fold_blocks = {}
        # 其他原有初始化代码...

2. 解析代码中的大括号配对

实现代码解析函数,通过栈结构匹配{和}的对应关系,在文本变化时更新折叠块数据:

def update_fold_blocks(self):
    self.fold_blocks.clear()
    stack = []
    lines = self.toPlainText().split('\n')
    for line_num, line in enumerate(lines):
        stripped_line = line.strip()
        if stripped_line.endswith('{'):
            stack.append(line_num)
        elif stripped_line.startswith('}') and stack:
            start_line = stack.pop()
            self.fold_blocks[start_line] = (line_num, False)

# 在初始化中连接文本变化信号
self.textChanged.connect(self.update_fold_blocks)

3. 扩展行号区域的绘制逻辑

修改LineNumberArea的paintEvent方法,在可折叠块的起始行右侧绘制折叠/展开图标(-表示展开,+表示折叠):

class LineNumberArea(QWidget):
    # 原有初始化代码...

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.fillRect(event.rect(), Qt.lightGray)

        block = self.editor.firstVisibleBlock()
        block_number = block.blockNumber()
        top = self.editor.blockBoundingGeometry(block).translated(self.editor.contentOffset()).top()
        bottom = top + self.editor.blockBoundingRect(block).height()

        while block.isValid() and top <= event.rect().bottom():
            if block.isVisible() and bottom >= event.rect().top():
                # 绘制行号
                number = str(block_number + 1)
                painter.setPen(Qt.black)
                painter.drawText(0, top, self.width() - 15, self.editor.fontMetrics().height(),
                                Qt.AlignRight, number)
                # 绘制折叠图标
                if block_number in self.editor.fold_blocks:
                    is_folded = self.editor.fold_blocks[block_number][1]
                    icon_text = '-' if not is_folded else '+'
                    painter.drawText(self.width() - 12, top, 10, self.editor.fontMetrics().height(),
                                    Qt.AlignCenter, icon_text)
            block = block.next()
            block_number += 1
            top = bottom
            bottom = top + self.editor.blockBoundingRect(block).height()

同时调整行号区域宽度,给图标留出空间,修改CodeEditor的resizeEvent:

def resizeEvent(self, event):
    super().resizeEvent(event)
    cr = self.contentsRect()
    self.line_number_area.setGeometry(QRect(cr.left(), cr.top(), self.fontMetrics().horizontalAdvance('999') + 15, cr.height()))

4. 添加折叠/展开的交互逻辑

在LineNumberArea中重写mousePressEvent,处理图标点击事件,切换折叠状态并控制对应行的显示:

def mousePressEvent(self, event):
    block = self.editor.cursorForPosition(event.pos()).block()
    block_number = block.blockNumber()
    if block_number in self.editor.fold_blocks:
        end_line, is_folded = self.editor.fold_blocks[block_number]
        # 切换折叠状态
        self.editor.fold_blocks[block_number] = (end_line, not is_folded)
        # 控制中间行的显示/隐藏
        for line_num in range(block_number + 1, end_line):
            target_block = self.editor.document().findBlockByNumber(line_num)
            target_block.setVisible(not is_folded)
        # 更新视图
        self.editor.viewport().update()
        self.update()

注意事项

  • 上述解析逻辑仅处理单行末尾的{和单行开头的},若需支持更复杂的语法场景(比如{在行中间),需要优化解析规则。
  • 折叠后滚动视图时,可根据需求添加自动调整可见区域的逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:03:20