Qt5/PyQt5 如何恢复QTextEdit 的准确可见区域和光标位置?

In Qt5/PyQt5 how do I restore exact visible area and cursor position of QTextEdit?

之前有人问过这个问题,但似乎只是关于 光标位置..

我实现了某种基于 QTextEdit 的自动加载更改文本编辑器。问题是:当我使用

应用新加载的文本时
self.my_editor.setPlainText(new_text)

光标会跳到0位置,很不舒服

当然,我不是唯一有这种感觉的人,所以人们已经问过他们如何在应用新文本后恢复光标,例如这里:https://www.qtcentre.org/threads/13933-Restoring-cursor-position-in-QTextEdit

但我找到的答案只涵盖文本光标本身的位置。

例如,此代码将保存光标、设置新文本并恢复光标:

c = self.my_editor.textCursor()
p = c.position()
self.my_editor.setPlainText(new_text)
c.setPosition(p)
self.my_editor.setTextCursor(c)

但现在编辑器会有效地滚动到位置 0,然后再次向下滚动,以便能够在恢复的位置显示光标。所以在视觉上编辑器跳来跳去(不过这仍然比丢失光标要好)

有没有办法同时存储 QTextEdit 实例的可视区域?当然,如果文本内容真的发生了变化,那么最小化视觉跳跃几乎是微不足道的,但如果文本发生变化 behind ,难道不应该根本看不到跳跃吗?光标?

假设内容总是几乎一样,可以将滚动条的值存起来,更新文本后再设置:

        c = self.my_editor.textCursor()
        p = c.position()
        hPos = self.my_editor.horizontalScrollBar().value()
        vPos = self.my_editor.verticalScrollBar().value()
        self.my_editor.setPlainText(new_text)
        c.setPosition(p)
        self.my_editor.horizontalScrollBar().setValue(hPos)
        self.my_editor.verticalScrollBar().setValue(vPos)
        self.my_editor.setTextCursor(c)

滚动条和光标重置的顺序取决于您的需要:如果光标可以在可见视口之外,您可能更愿意先设置光标然后恢复滚动条。

最后,如果内容可以变化很多,你应该使用基于滚动条最大值的比率:

        try:
            hBar = self.my_editor.horizontalScrollBar()
            hPos = hBar.value() / hBar.maximum()
        except ZeroDivisionError:
            hPos = 0
        try:
            vBar = self.my_editor.verticalScrollBar()
            vPos = vBar.value() / vBar.maximum()
        except ZeroDivisionError:
            vPos = 0
        self.my_editor.setPlainText(new_text)
        c.setPosition(p)
        self.my_editor.setTextCursor(c)
        hBar.setValue(hPos * hBar.maximum())
        vBar.setValue(vPos * vBar.maximum())

注意:最大值必须动态使用,因为文本更改时范围可能会更改。