QSyntaxHighlighter
-
Hi everyone,
I have a problem with the syntax Highlighter. I saved the colours for highlighting and the user can change them in the settings while he is editing code. So I wrote a signal colorChanged() and a slot to change the colour for highlighting. The next time you change something in a certain line, the new colors will be applied. This works very well.
Additionally I also want the complete file to be rehighlighted directly when the user changes the color. I found the "rehighlight()" slot in the QSyntaxHighlighter class. So I connected my colorChanged() signal to the rehighlight slot, but nothing happend (also no error warning). Same behaviour as before.
I thought the rehighlight slot may got called before the applyColors slot. So I wrote a slot, which first applies the new colors and then rehighlights the whole document. This also didn't work.
QObject::connect(settings, SIGNAL(colorChanged()), this, SLOT(changeColors())); void CppHighlighter::changeColors() { applyColors(); rehighlight(); }
Did I missunderstood the rehighlight slot? Is this a bug? I'm using Qt 5.11
-
Hi,
Where do you emit the signal from ?
How did you change the parameter that defines that ?
Can you show the code related to handling the highlighting ? -
Hi,
I've used QSettings and one saved setting is for example the colour of macros (like #define).
Here is the setter to set the color of the macrovoid ApplicationSettings::setMacros(const QColor& macros) { setValue("macros", macros); emit macrosChanged(); emit colorChanged(); }
as you can see when one sets the colour for macros the colorChanged signal is emitted.
You can access the settings in qml and also in every cpp file (as it is global and a context property).
For example in qml I have designed a ColorPicker, which changes the color of the macros:Custom.FoldedColorPicker { color: settings.macros onClicked: settings.macros = color }
Of course I have done the same for serveral other things, which should be highlighted.
The Syntax Highlighter is implemented similar to the example from qt.
In the constructor I define some Regular Expressions how the SyntaxHighlighter can find macros and I apply a color to them.QStringList macroPatterns; macroPatterns << "\\B#include\\b" << "\\B#define\\b" << "\\B#ifndef\\b" << "\\B#endif\\b" << "\\B#if\\b"; foreach (const QString& pattern, macroPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = ¯oFormat; highlightingRules.append(rule); }
For the colors I have made a function applyColors()
void CppHighlighter::applyColors() { macroFormat.setForeground(settings->property("macros").value<QColor>()); ... }
As rule.format is a reference to macroFormat, rule.format should be changed too.
And I have as I said a slot called changeColors (in my Syntax Highlighter), which calls this function "applyColors()" and "rehighlight"
void CppHighlighter::changeColors() { applyColors(); qDebug() << "Test1" << '\n'; rehighlight(); qDebug() << "Test2" << '\n'; }
This slot is connected to the signal of settings in the constructor of the SyntaxHighlighter
QObject::connect(settings, SIGNAL(colorChanged()), this, SLOT(changeColors()));
For clarity: Except from the rehighlight() method/slot everything worked fine. So if you change a macro manually, the colour will be updated (because the highlight method is called as usually). I also used qDebug and my console showed Test1 and Test2, so rehighlight() is called.
I also tried something like this:
QObject::connect(settings, SIGNAL(colorChanged()), this, SLOT(changeColors())); QObject::connect(settings, SIGNAL(colorChanged()), this, SLOT(rehighlight()));
It didn't worked.
-
I forgot to post the code for the highlight method.
void CppHighlighter::highlightBlock(const QString &text) { foreach (const HighlightingRule &rule, highlightingRules) { QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); while (matchIterator.hasNext()) { QRegularExpressionMatch match = matchIterator.next(); setFormat(match.capturedStart(), match.capturedLength(), *rule.format); } } }
But as it worked perfectly, I don't expeect this method to be wrong.
-
I did some try and error and found out that my Syntax Highlighter works as exspected, but not the textArea.
Here are some outputs"#define" QBrush(QColor(ARGB 1, 0.564706, 0.792157, 0.976471),SolidPattern) 0 7
highlightBlock() is called with the text "#define". It detected the macro from position 0 to 7 and passed this together with the brush to setFormat()
Rehighlight New Color: QBrush(QColor(ARGB 1, 0.937255, 0.603922, 0.603922),SolidPattern) "#define" QBrush(QColor(ARGB 1, 0.937255, 0.603922, 0.603922),SolidPattern) 0 7 Rehighlighted
I changed the color. The syntax Highlighter calls the changeColor slot. The new color ist set and the highlightBlock method is called (through rehighlight()). Again the macro "#define is detected" and should be formatted with the new color from position 0 to 7.
But when I look at my TextArea there has nothing changed. So I add one space.
"#define " QBrush(QColor(ARGB 1, 0.937255, 0.603922, 0.603922),SolidPattern) 0 7
And the color changes.
So it seems to me like the text is formatted correctly, but TextArea does not update itself. I should mention that I have a swipeView and the settings are not on the same page as the textArea. So the textArea is not visible anymore while I change the color.
By the way, I am using a TextArea from Qt Quick Controls 2. And I have done a custom DocumentHandler, which gets the text from the TextArea and creates the SyntaxHighlighter.
Backend.DocumentHandler { id: documentHandler document: editor.textDocument onLoaded: { editor.text = text } }
-
I think my problem is a bug of qt. For some reason the TextArea does not get notified if the textDocument changes. Therefore it does not display the new color.
Someone reported already the same issue:
https://bugreports.qt.io/browse/QTBUG-65248
Almost one year ago and still not solves?I found a patch for it, we need to emit the signal:
void QAbstractTextDocumentLayout::updateBlock(const QTextBlock &block)
This seems to notify the TextArea that something has changed. As we want to rehighlight the complete document, we need to emit the signal for every block. I wrote a simple for loop for it. Didn't find any nicer solution with iterators or a list of blocks and a for each loop. Simply put if after the call of rehighlight().
void CppHighlighter::changeColors() { applyColors(); rehighlight(); for(int i = 0; i < document()->blockCount(); ++i) { emit document()->documentLayout()->updateBlock(document()->findBlockByNumber(i)); } }
Should I open a new bug report for it? The old one seems to be forgotten and the patch might be helpful for the developers.
-
I think my problem is a bug of qt. For some reason the TextArea does not get notified if the textDocument changes. Therefore it does not display the new color.
Someone reported already the same issue:
https://bugreports.qt.io/browse/QTBUG-65248
Almost one year ago and still not solves?I found a patch for it, we need to emit the signal:
void QAbstractTextDocumentLayout::updateBlock(const QTextBlock &block)
This seems to notify the TextArea that something has changed. As we want to rehighlight the complete document, we need to emit the signal for every block. I wrote a simple for loop for it. Didn't find any nicer solution with iterators or a list of blocks and a for each loop. Simply put if after the call of rehighlight().
void CppHighlighter::changeColors() { applyColors(); rehighlight(); for(int i = 0; i < document()->blockCount(); ++i) { emit document()->documentLayout()->updateBlock(document()->findBlockByNumber(i)); } }
Should I open a new bug report for it? The old one seems to be forgotten and the patch might be helpful for the developers.
@Leon_2001 please comment on the original report. that way you get more attention. duplicate reports do not help. most developers already have 100 open reports and its easy to lose track.
Note that the best way to get this fixed is sending the patch to Gerrit
[edit: Fixed link SGaist]
-
I will give it a try tomorrow ;)
I want to use my chance to ask one further (general) questions to QSyntaxHighlighter.
Can I use this class also to do things like auto-intendt or to close open (,{ automatically or for code completion? The highlight method seems pretty handy to me and it's probably possible to achieve this with QSyntaxHighligter.
But as it is called SyntaxHighlighter and as names mostly have a meaning, I wonder if I should do this or use some other approach? -
I wouldn't mix that in. Single Responsibility is a key when developing classes.
You might be interested in KDE's KTextEditor. They provide a complete pretty complete code editor that is used in e.g. Kate and KDevelop.