QT QPlainTextEdit 实现代码折叠功能

1、控件

  • QPlainTextEdit :加载代码,以及使用 QTextBlock针对每行进行处理,好比高亮、隐藏setVisible (False)等,而QTextEdit 默认的 DocumentLayout 不支持隐藏 QTextBlock 。
  • QPushButton:添加折叠、展开两个按钮,方便测试。

2、界面

这里写图片描述

  • 只是测试改功能,因此用Qtdesigner写了个简易的界面。
  • QPlainTextEdit 继承自定义的类CMyText。
  • 直接加载代码,而后点击折叠、展开触发操做。

3、代码

import sys
import os
from PyQt5 import QtWidgets, QtCore, QtGui

FILE = r"E:\mygithub\FileCompare\test\py2ui.txt"


class CMyText(QtWidgets.QPlainTextEdit):
    m_Start = 10
    m_End = 50

    def __init__(self, parent=None):
        super(CMyText, self).__init__(parent)
        self.InitUI()

    def InitUI(self):
        self.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap)
        with open(FILE, "r", encoding="utf8") as fp:
            lstLines = fp.readlines()
            lst = []
            for i, line in enumerate(lstLines):
                lst.append("%s-%s" % (i, line)) # 添加行号,方便直观观察
            self.setPlainText("".join(lst))

    def E_Fold(self):
        document = self.document()
        for x in range(self.m_Start + 1, self.m_End + 1):
            oTextBlock = document.findBlockByNumber(x)
            oTextBlock.setVisible(False)    # 隐藏

    def E_Unfold(self):
        document = self.document()
        for x in range(self.m_Start + 1, self.m_End + 1):
            oTextBlock = document.findBlockByNumber(x)
            oTextBlock.setVisible(True)     # 显示
  • 这是按照直观想法写出的代码,天然而然想到,隐藏直接将对应的块设置为不可见。

4、实际效果花屏问题:

这里写图片描述

  • 能够看到点击以后并不会理解隐藏11-50行。python

  • 滑动以后才会隐藏,并且滑下去时其实仍是通过了11-50行,能够看到再滑上来时,花屏了加载了好几回51行。git

  • 缘由:github

    • 点击没反应:点击虽然调用了隐藏,可是界面并无重绘,因此还须要调用self.viewport().update(),展开时也同样。web

    • 滚动花屏:滚动时也应该调用self.viewport().update()app

    def scrollContentsBy(self, dx, dy):
            self.viewport().update()
            super(CMyText, self).scrollContentsBy(dx, dy)

5、滚动的另外一个问题。

这里写图片描述

  • 此时点击马上隐藏了,可是滑动到10行继续玩下滑动时,滚动条正常向下滑动,代码并无向下滑,而是过了一段时间才开始滚动。svg

  • 缘由:猜测代码其实仍是包括隐藏的行,因此滚动时仍是会滚过这些隐藏的行。测试

  • 解决:在折叠、展开时调用document.adjustSize()便可。ui

    def E_Fold(self):
          document = self.document()
          for x in range(self.m_Start + 1, self.m_End + 1):
              oTextBlock = document.findBlockByNumber(x)
              oTextBlock.setVisible(False)
          self.viewport().update()
          document.adjustSize()
  • 此时完美运行代码折叠、展开。能够继续作本身想作的效果了。spa

  • 完整代码见:https://github.com/lamborghini1993/FileCompare/tree/LocalFileCompare/test_fold