在 n 个字符后更改 QTextEdit 中的文本颜色
Change text color in QTextEdit after n characters
我正在寻找一种方法,如果文本的长度超过 n 个字符,则为 QTextEdit 的剩余文本动态着色 - 也就是说,我想要第一个字符以外的所有字符n 每当文本更改时颜色不同。
我尝试使用 textChanged-Signal,但不幸的是每当我这样做时:
cursor = self.textCursor()
format = QTextCharFormat()
format.setForeground(QColor('#303030'))
cursor.setPosition(n)
cursor.movePosition(QTextCursor.End)
cursor.mergeCharFormat(format)
要更改剩余文本的颜色,它会进入无限循环,因为更改格式似乎也会触发 textChanged-Signal。
我尝试的另一件事是使用 QSyntaxHighlighter,但那样我只能访问当前的文本块,而不是整个文本。
我想我必须改为子类化 QTextEdit,但我不知道要更改什么才能让它工作。
您可以通过在插槽的开头和结尾使用 blockSignals()
来临时阻止在重新格式化文本时发出信号。
此外,仅合并字符格式不足以更新文本格式。您还需要将文本编辑的文本光标设置为修改后的文本光标。在插槽的末尾,您还需要将文本光标重置为原始文本光标,以确保保持当前位置和选择,例如
from PyQt5 import QtWidgets, QtGui, QtCore
class TextEdit(QtWidgets.QTextEdit):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setAcceptRichText(True)
self.textChanged.connect(self.text_has_changed)
# maximum number of characters is set to 10
self.max_count = 10
def text_has_changed(self):
# block signals, and save original text cursor
blocked = self.blockSignals(True)
old_cursor = self.textCursor()
# create new cursor for setting char format of part of text before the self.max_count'th character
cursor = QtGui.QTextCursor(self.document())
cursor.setPosition(self.max_count, mode=QtGui.QTextCursor.KeepAnchor)
format = QtGui.QTextCharFormat()
format.setForeground(QtGui.QColor('#000000'))
cursor.mergeCharFormat(format)
# change of text format doesn't take effect until text cursor of self is set to updated text cursor.
self.setTextCursor(cursor)
# if document contains more than self.max_count: reformat everything that comes after the self.max_count'th character.
if self.document().characterCount() > self.max_count:
cursor.setPosition(self.max_count)
cursor.movePosition(QtGui.QTextCursor.End, mode=QtGui.QTextCursor.KeepAnchor)
format.setForeground(QtGui.QColor('#a0a0a0'))
cursor.mergeCharFormat(format)
self.setTextCursor(cursor)
# reset text cursor to original cursor and unblock signals.
self.setTextCursor(old_cursor)
self.blockSignals(blocked)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
w = TextEdit()
w.show()
app.exec()
我正在寻找一种方法,如果文本的长度超过 n 个字符,则为 QTextEdit 的剩余文本动态着色 - 也就是说,我想要第一个字符以外的所有字符n 每当文本更改时颜色不同。
我尝试使用 textChanged-Signal,但不幸的是每当我这样做时:
cursor = self.textCursor()
format = QTextCharFormat()
format.setForeground(QColor('#303030'))
cursor.setPosition(n)
cursor.movePosition(QTextCursor.End)
cursor.mergeCharFormat(format)
要更改剩余文本的颜色,它会进入无限循环,因为更改格式似乎也会触发 textChanged-Signal。
我尝试的另一件事是使用 QSyntaxHighlighter,但那样我只能访问当前的文本块,而不是整个文本。
我想我必须改为子类化 QTextEdit,但我不知道要更改什么才能让它工作。
您可以通过在插槽的开头和结尾使用 blockSignals()
来临时阻止在重新格式化文本时发出信号。
此外,仅合并字符格式不足以更新文本格式。您还需要将文本编辑的文本光标设置为修改后的文本光标。在插槽的末尾,您还需要将文本光标重置为原始文本光标,以确保保持当前位置和选择,例如
from PyQt5 import QtWidgets, QtGui, QtCore
class TextEdit(QtWidgets.QTextEdit):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setAcceptRichText(True)
self.textChanged.connect(self.text_has_changed)
# maximum number of characters is set to 10
self.max_count = 10
def text_has_changed(self):
# block signals, and save original text cursor
blocked = self.blockSignals(True)
old_cursor = self.textCursor()
# create new cursor for setting char format of part of text before the self.max_count'th character
cursor = QtGui.QTextCursor(self.document())
cursor.setPosition(self.max_count, mode=QtGui.QTextCursor.KeepAnchor)
format = QtGui.QTextCharFormat()
format.setForeground(QtGui.QColor('#000000'))
cursor.mergeCharFormat(format)
# change of text format doesn't take effect until text cursor of self is set to updated text cursor.
self.setTextCursor(cursor)
# if document contains more than self.max_count: reformat everything that comes after the self.max_count'th character.
if self.document().characterCount() > self.max_count:
cursor.setPosition(self.max_count)
cursor.movePosition(QtGui.QTextCursor.End, mode=QtGui.QTextCursor.KeepAnchor)
format.setForeground(QtGui.QColor('#a0a0a0'))
cursor.mergeCharFormat(format)
self.setTextCursor(cursor)
# reset text cursor to original cursor and unblock signals.
self.setTextCursor(old_cursor)
self.blockSignals(blocked)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
w = TextEdit()
w.show()
app.exec()