In slot connected to QPlainTextEdit::textChanged() signal I do syntax highlighting with:
struct Format {
QTextBlock block;
QList< QTextLayout::FormatRange > format;
};
//! Formats.
QMap< int, Format > formats;
void clearFormats()
{
for( const auto & f : std::as_const( formats ) )
f.block.layout()->clearFormats();
formats.clear();
}
void applyFormats()
{
for( const auto & f : std::as_const( formats ) )
f.block.layout()->setFormats( f.format );
}
void setFormat( const QTextCharFormat & format,
long long int startLine, long long int startColumn,
long long int endLine, long long int endColumn )
{
for( auto i = startLine; i <= endLine; ++i )
{
formats[ i ].block = editor->document()->findBlockByNumber( i );
QTextLayout::FormatRange r;
r.format = format;
r.start = ( i == startLine ? startColumn : 0 );
r.length = ( i == startLine ?
( i == endLine ? endColumn - startColumn + 1 :
formats[ i ].block.length() - startColumn ) :
( i == endLine ? endColumn + 1 : formats[ i ].block.length() ) );
formats[ i ].format.push_back( r );
}
}
On each text change I do the following:
clearFormats();
setFormat( ... ); // When needed in text
applyFormats()
All works as expected when I'm typing a text in editor, syntax highlights.
In my application I have a dialog to set colors for syntax highlighting. On colors change I do above procedure with clearing formats, settings the new with new colors, and applying new formats.
And at this point of time colors remains the same, till I type something in editor.
So my question is: what should I do to force a QPlainTextEdit to apply new formats without typing anything?
Minimal reproducible example:
#include <QPlainTextEdit>
#include <QApplication>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTextCharFormat>
#include <QTextDocument>
#include <QTextBlock>
class Edit
: public QPlainTextEdit
{
Q_OBJECT
public:
Edit()
{
connect( this, &QPlainTextEdit::textChanged,
this, &Edit::onTextChanged );
}
~Edit() override = default;
public slots:
void changeColor()
{
if( color == Qt::red )
color = Qt::green;
else
color = Qt::red;
emit textChanged();
}
private slots:
void onTextChanged()
{
clearFormats();
setFormat();
}
private:
void clearFormats()
{
auto b = document()->firstBlock();
while( b.isValid() )
{
b.layout()->clearFormats();
b = b.next();
}
}
void setFormat()
{
auto b = document()->firstBlock();
QTextCharFormat f;
f.setForeground( color );
while( b.isValid() )
{
QTextLayout::FormatRange r;
r.format = f;
r.start = 0;
r.length = b.length();
b.layout()->setFormats( { r } );
b = b.next();
}
}
private:
QColor color = Qt::red;
};
int main( int argc, char ** argv )
{
QApplication app( argc, argv );
QWidget w;
QVBoxLayout l( &w );
Edit e;
l.addWidget( &e );
QPushButton b;
b.setText( "Change color" );
l.addWidget( &b );
b.connect( &b, &QPushButton::clicked, &e, &Edit::changeColor );
w.resize( 800, 600 );
w.show();
return QApplication::exec();
}
#include "main.moc"
I solved it. What was needed it's only update a view-port like: