PyQt5 - QSyntaxHighlighter not working properly
-
I'm using
QSyntaxHighlighter
to highlight aQTextEdit
but it doesn't work if theQTextEdit
has a text at start. It highlights all with a same color. If I instead of adding the whole text at once I add each character by character it works.
So not sure of which is the proper way to use aQSyntaxHighlighter
.Take a look at this minimal example:
Do uncomment81
,93
and84
lines and comment80
line to see how it should look like.import sys import re from PyQt5.QtGui import QBrush, QSyntaxHighlighter, QTextCharFormat, QColor, QPalette, QFont, QTextCursor, QTextLayout from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QTextEdit, QMainWindow, QApplication class MarkdownHighlighter(QSyntaxHighlighter): MARKDOWN_KEYS_REGEX = { 'HeaderAtx': re.compile(u'(?u)^\#{1,6}(.*?)\#*(\n|$)'), # ## Header } def __init__(self, parent): super().__init__(parent) self.parent = parent parent.setTabStopWidth(parent.fontMetrics().width(' ') * 6) self.defaultTheme = { "background-color":"#3e3d32", "color":"#ffffff", "header": { "color":"#fd971f", "font-weight":"bold", "font-style":"normal" } } self.setTheme(self.defaultTheme) def setTheme(self, theme): self.theme = theme self.MARKDOWN_KWS_FORMAT = {} pal = self.parent.palette() pal.setColor(QPalette.Base, QColor(theme['background-color'])) self.parent.setPalette(pal) self.parent.setTextColor(QColor(theme['color'])) text_char_format = QTextCharFormat() text_char_format.setForeground(QBrush(QColor(theme['header']['color']))) text_char_format.setFontWeight(QFont.Bold if theme['header']['font-weight']=='bold' else QFont.Normal) text_char_format.setFontItalic(True if theme['header']['font-style']=='italic' else False) self.MARKDOWN_KWS_FORMAT['HeaderAtx'] = text_char_format self.rehighlight() def highlightBlock(self, text): text = str(text) self.highlightMarkdown(text,0) def highlightMarkdown(self, text, strt): cursor = QTextCursor(self.document()) bf = cursor.blockFormat() self.setFormat(0, len(text), QColor(self.theme['color'])) if self.highlightAtxHeader(text, cursor, bf, strt): return def highlightEmptyLine(self, text, cursor, bf, strt): textAscii = str(text.replace(u'\u2029','\n')) if textAscii.strip(): return False else: return True def highlightAtxHeader(self, text, cursor, bf, strt): found = False for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['HeaderAtx'],text): #bf.setBackground(QBrush(QColor(7,54,65))) #cursor.movePosition(QTextCursor.End) #cursor.mergeBlockFormat(bf) self.setFormat(mo.start()+strt, mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['HeaderAtx']) found = True return found class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) text_edit = QTextEdit("## Some header<br>Some paragraph") # text_edit = QTextEdit("") # for char in "## Some header\nSome paragraph": # add_text_to_text_edit(text_edit, char) syntax_highlighter = MarkdownHighlighter(text_edit) self.setCentralWidget(text_edit) self.show() def add_text_to_text_edit(text_edit: QTextEdit, text: str) -> None: current_text = text_edit.toPlainText() new_text = current_text + text text_edit.setPlainText(new_text) if __name__ == "__main__": app = QApplication(sys.argv) main_window = MainWindow() sys.exit(app.exec_())
-
I'm using
QSyntaxHighlighter
to highlight aQTextEdit
but it doesn't work if theQTextEdit
has a text at start. It highlights all with a same color. If I instead of adding the whole text at once I add each character by character it works.
So not sure of which is the proper way to use aQSyntaxHighlighter
.Take a look at this minimal example:
Do uncomment81
,93
and84
lines and comment80
line to see how it should look like.import sys import re from PyQt5.QtGui import QBrush, QSyntaxHighlighter, QTextCharFormat, QColor, QPalette, QFont, QTextCursor, QTextLayout from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QTextEdit, QMainWindow, QApplication class MarkdownHighlighter(QSyntaxHighlighter): MARKDOWN_KEYS_REGEX = { 'HeaderAtx': re.compile(u'(?u)^\#{1,6}(.*?)\#*(\n|$)'), # ## Header } def __init__(self, parent): super().__init__(parent) self.parent = parent parent.setTabStopWidth(parent.fontMetrics().width(' ') * 6) self.defaultTheme = { "background-color":"#3e3d32", "color":"#ffffff", "header": { "color":"#fd971f", "font-weight":"bold", "font-style":"normal" } } self.setTheme(self.defaultTheme) def setTheme(self, theme): self.theme = theme self.MARKDOWN_KWS_FORMAT = {} pal = self.parent.palette() pal.setColor(QPalette.Base, QColor(theme['background-color'])) self.parent.setPalette(pal) self.parent.setTextColor(QColor(theme['color'])) text_char_format = QTextCharFormat() text_char_format.setForeground(QBrush(QColor(theme['header']['color']))) text_char_format.setFontWeight(QFont.Bold if theme['header']['font-weight']=='bold' else QFont.Normal) text_char_format.setFontItalic(True if theme['header']['font-style']=='italic' else False) self.MARKDOWN_KWS_FORMAT['HeaderAtx'] = text_char_format self.rehighlight() def highlightBlock(self, text): text = str(text) self.highlightMarkdown(text,0) def highlightMarkdown(self, text, strt): cursor = QTextCursor(self.document()) bf = cursor.blockFormat() self.setFormat(0, len(text), QColor(self.theme['color'])) if self.highlightAtxHeader(text, cursor, bf, strt): return def highlightEmptyLine(self, text, cursor, bf, strt): textAscii = str(text.replace(u'\u2029','\n')) if textAscii.strip(): return False else: return True def highlightAtxHeader(self, text, cursor, bf, strt): found = False for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['HeaderAtx'],text): #bf.setBackground(QBrush(QColor(7,54,65))) #cursor.movePosition(QTextCursor.End) #cursor.mergeBlockFormat(bf) self.setFormat(mo.start()+strt, mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['HeaderAtx']) found = True return found class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) text_edit = QTextEdit("## Some header<br>Some paragraph") # text_edit = QTextEdit("") # for char in "## Some header\nSome paragraph": # add_text_to_text_edit(text_edit, char) syntax_highlighter = MarkdownHighlighter(text_edit) self.setCentralWidget(text_edit) self.show() def add_text_to_text_edit(text_edit: QTextEdit, text: str) -> None: current_text = text_edit.toPlainText() new_text = current_text + text text_edit.setPlainText(new_text) if __name__ == "__main__": app = QApplication(sys.argv) main_window = MainWindow() sys.exit(app.exec_())
@Patitotective Don't combine plain text not html. I think that in the first case it is happening that QTextEdit considers it to be plain text as opposed to the second that you explicitly consider to be plain text.
-
Hi,
Did you already check the Syntax Highlighter Example ?
I think it provides a pretty good base that you can base your code on.
-
I'm using
QSyntaxHighlighter
to highlight aQTextEdit
but it doesn't work if theQTextEdit
has a text at start. It highlights all with a same color. If I instead of adding the whole text at once I add each character by character it works.
So not sure of which is the proper way to use aQSyntaxHighlighter
.Take a look at this minimal example:
Do uncomment81
,93
and84
lines and comment80
line to see how it should look like.import sys import re from PyQt5.QtGui import QBrush, QSyntaxHighlighter, QTextCharFormat, QColor, QPalette, QFont, QTextCursor, QTextLayout from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QTextEdit, QMainWindow, QApplication class MarkdownHighlighter(QSyntaxHighlighter): MARKDOWN_KEYS_REGEX = { 'HeaderAtx': re.compile(u'(?u)^\#{1,6}(.*?)\#*(\n|$)'), # ## Header } def __init__(self, parent): super().__init__(parent) self.parent = parent parent.setTabStopWidth(parent.fontMetrics().width(' ') * 6) self.defaultTheme = { "background-color":"#3e3d32", "color":"#ffffff", "header": { "color":"#fd971f", "font-weight":"bold", "font-style":"normal" } } self.setTheme(self.defaultTheme) def setTheme(self, theme): self.theme = theme self.MARKDOWN_KWS_FORMAT = {} pal = self.parent.palette() pal.setColor(QPalette.Base, QColor(theme['background-color'])) self.parent.setPalette(pal) self.parent.setTextColor(QColor(theme['color'])) text_char_format = QTextCharFormat() text_char_format.setForeground(QBrush(QColor(theme['header']['color']))) text_char_format.setFontWeight(QFont.Bold if theme['header']['font-weight']=='bold' else QFont.Normal) text_char_format.setFontItalic(True if theme['header']['font-style']=='italic' else False) self.MARKDOWN_KWS_FORMAT['HeaderAtx'] = text_char_format self.rehighlight() def highlightBlock(self, text): text = str(text) self.highlightMarkdown(text,0) def highlightMarkdown(self, text, strt): cursor = QTextCursor(self.document()) bf = cursor.blockFormat() self.setFormat(0, len(text), QColor(self.theme['color'])) if self.highlightAtxHeader(text, cursor, bf, strt): return def highlightEmptyLine(self, text, cursor, bf, strt): textAscii = str(text.replace(u'\u2029','\n')) if textAscii.strip(): return False else: return True def highlightAtxHeader(self, text, cursor, bf, strt): found = False for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['HeaderAtx'],text): #bf.setBackground(QBrush(QColor(7,54,65))) #cursor.movePosition(QTextCursor.End) #cursor.mergeBlockFormat(bf) self.setFormat(mo.start()+strt, mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['HeaderAtx']) found = True return found class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) text_edit = QTextEdit("## Some header<br>Some paragraph") # text_edit = QTextEdit("") # for char in "## Some header\nSome paragraph": # add_text_to_text_edit(text_edit, char) syntax_highlighter = MarkdownHighlighter(text_edit) self.setCentralWidget(text_edit) self.show() def add_text_to_text_edit(text_edit: QTextEdit, text: str) -> None: current_text = text_edit.toPlainText() new_text = current_text + text text_edit.setPlainText(new_text) if __name__ == "__main__": app = QApplication(sys.argv) main_window = MainWindow() sys.exit(app.exec_())
@Patitotective Don't combine plain text not html. I think that in the first case it is happening that QTextEdit considers it to be plain text as opposed to the second that you explicitly consider to be plain text.
-
Hi,
Did you already check the Syntax Highlighter Example ?
I think it provides a pretty good base that you can base your code on.
@SGaist I'll take a look at it, thanks 🙃
-
@Patitotective Don't combine plain text not html. I think that in the first case it is happening that QTextEdit considers it to be plain text as opposed to the second that you explicitly consider to be plain text.
@eyllanesc Thanks, you were right 🙃
I did:text_edit = QTextEdit() text_edit.setPlainText(text)
Instead of:
text_edit = QTextEdit(text)
And it worked.