Making changes to a QTextEdit without adding an undo command to the undo stack
Asked Answered
F

3

7

I'm looking for a way to change the QTextCharFormat of a QTextEdit's QTextBlock without triggering the addition of an undo command. Let me explain:

The QTextCharFormat of a QTextBlock can be easily changed by using the QTextCursor::setBlockCharFormat() method. Assuming we have a QTextEdit called myTextEdit whose visible cursor is within the text block we want to change, we can change the textblock's QTextCharFormat like so:

text_cursor = myTextEdit.textCursor()
text_cursor.setBlockCharFormat(someNewCharFormat)

The above code works fine, but it will also add an undo command to the myTextEdit undo stack. For my own purposes, I would like to be able to change the QTextCharFormat of a QTextBlock without adding an undo command to the QTextEdit's undo stack.

I considered temporarily disabling the undo/redo system with the QTextDocument::setUndoRedoEnabled() method, but that method also clears the undo stack, which I don't want to do. I've also looked for other ways to change how the undo/redo system behaves, but I haven't found a way to get it to temporarily ignore changes. I simply want to make a change to a QTextEdit without the undo/redo system registering the change at all.

Any tips or suggestions are appreciated. Thanks!

Fey answered 24/11, 2014 at 20:7 Comment(1)
I think you may be out of luck, see this qt-interest thread (which is a bit old, but it summarizes the issues quite well). – Belindabelisarius
W
8

You have to group this with previous modification. It is simple you have to surround code which does this modification with: beginEditBlock and endEditBlock. See documentation.

text_cursor = myTextEdit.textCursor()
text_cursor.beginEditBlock()
text_cursor.setCharFormat(someOtherCharFormat) # some previous modification
text_cursor.setBlockCharFormat(someNewCharFormat)
text_cursor.endEditBlock()

this way you will make a single commit for undo stack for any complex modification.

Woodworking answered 24/11, 2014 at 20:26 Comment(3)
Hi Marek. Thanks for the suggestion! Unfortunately, this solution doesn't accomplish what I need. I really need there to be no undo command added at all. The reason I need this is that I am trying to expand the undo/redo system to track and change attributes of the overall program that it doesn't track by default. This means that, when an action is undone, I am executing additional code that could be thought of as part of the undo action. In my case, the setBlockCharFormat() method would be run as part of an undo, and therefore, should not add an undo command to the stack. – Fey
so try undo then inside edit block redo and than your change. – Woodworking
beginEditBlock() is exactly what collapses many operations into one undo/redo step. This was hard to find. Thanks! We were about to refactor QTextDocument to use QUndoStack. This saved us 1 week of work. πŸ‘ – Hake
W
3

joinPreviousBlock() should do the trick:

cursor = self.textCursor()
cursor.joinPreviousEditBlock()
cursor.setPosition(start, QTextCursor.MoveAnchor)
cursor.setPosition(end, QTextCursor.KeepAnchor)
cursor.setCharFormat(fmt)
cursor.endEditBlock()
Whitener answered 29/1, 2019 at 14:14 Comment(0)
B
2

You should use QSyntaxHighlighter. Extends it and implement highlightBlock func, and call setFormat in it to change format without making undo/redo stack. See documentation for more detail.

If you feel QSyntaxHighlighter is not what you want, you can use QTextLayout. It is low level api and its setAdditionalFormats func doesn't make any undo stack.

range1 = QTextLayout.FormatRange()
range1.start = 0
range1.length = 10
range1.format = QTextCharFormat()
# additional ranges here...
textBlock.layout().setAdditionalFormats([range1, ...])

This is also used in the inside of QSyntaxHighlighter.

Bunni answered 31/1, 2019 at 10:53 Comment(0)

© 2022 - 2024 β€” McMap. All rights reserved.