Code Editor Example▲

As can be seen from the image, the editor displays the line numbers in an area to the left of the area for editing. The editor will highlight the line containing the cursor.
We implement the editor in CodeEditor, which is a widget that inherits QPlainTextEdit. We keep a separate widget in CodeEditor (LineNumberArea) onto which we draw the line numbers.
QPlainTextEdit inherits from QAbstractScrollArea, and editing takes place within its viewport()'s margins. We make room for our line number area by setting the left margin of the viewport to the size we need to draw the line numbers.
When it comes to editing code, we prefer QPlainTextEdit over QTextEdit because it is optimized for handling plain text. See the QPlainTextEdit class description for details.
QPlainTextEdit lets us add selections in addition to the selection the user can make with the mouse or keyboard. We use this functionality to highlight the current line. More on this later.
We will now move on to the definitions and implementations of CodeEditor and LineNumberArea. Let's start with the LineNumberArea class.
The LineNumberArea Class▲
We paint the line numbers on this widget, and place it over the CodeEditor's viewport()'s left margin area.
We need to use protected functions in QPlainTextEdit while painting the area. So to keep things simple, we paint the area in the CodeEditor class. The area also asks the editor to calculate its size hint.
Note that we could simply paint the line numbers directly on the code editor, and drop the LineNumberArea class. However, the QWidget class helps us to scroll() its contents. Also, having a separate widget is the right choice if we wish to extend the editor with breakpoints or other code editor features. The widget would then help in the handling of mouse events.
class
LineNumberArea : public
QWidget
{
public
:
LineNumberArea(CodeEditor *
editor) : QWidget(editor) {
codeEditor =
editor;
}
QSize sizeHint() const
override
{
return
QSize(codeEditor-&
gt;lineNumberAreaWidth(), 0
);
}
protected
:
void
paintEvent(QPaintEvent *
event) override
{
codeEditor-&
gt;lineNumberAreaPaintEvent(event);
}
private
:
CodeEditor *
codeEditor;
}
;
CodeEditor Class Definition▲
Here is the code editor's class definition:
class
CodeEditor : public
QPlainTextEdit
{
Q_OBJECT
public
:
CodeEditor(QWidget *
parent =
0
);
void
lineNumberAreaPaintEvent(QPaintEvent *
event);
int
lineNumberAreaWidth();
protected
:
void
resizeEvent(QResizeEvent *
event) override
;
private
slots:
void
updateLineNumberAreaWidth(int
newBlockCount);
void
highlightCurrentLine();
void
updateLineNumberArea(const
QRect &
amp;, int
);
private
:
QWidget *
lineNumberArea;
}
;
In the editor we resize and draw the line numbers on the LineNumberArea. We need to do this when the number of lines in the editor changes, and when the editor's viewport() is scrolled. Of course, it is also done when the editor's size changes. We do this in updateLineNumberWidth() and updateLineNumberArea().
Whenever, the cursor's position changes, we highlight the current line in highlightCurrentLine().
CodeEditor Class Implementation▲
We will now go through the code editors implementation, starting off with the constructor.
CodeEditor::
CodeEditor(QWidget *
parent) : QPlainTextEdit(parent)
{
lineNumberArea =
new
LineNumberArea(this
);
connect(this
, SIGNAL(blockCountChanged(int
)), this
, SLOT(updateLineNumberAreaWidth(int
)));
connect(this
, SIGNAL(updateRequest(QRect,int
)), this
, SLOT(updateLineNumberArea(QRect,int
)));
connect(this
, SIGNAL(cursorPositionChanged()), this
, SLOT(highlightCurrentLine()));
updateLineNumberAreaWidth(0
);
highlightCurrentLine();
}
In the constructor we connect our slots to signals in QPlainTextEdit. It is necessary to calculate the line number area width and highlight the first line when the editor is created.
int
CodeEditor::
lineNumberAreaWidth()
{
int
digits =
1
;
int
max =
qMax(1
, blockCount());
while
(max &
gt;=
10
) {
max /=
10
;
++
digits;
}
int
space =
3
+
fontMetrics().horizontalAdvance(QLatin1Char('9'
)) *
digits;
return
space;
}
The lineNumberAreaWidth() function calculates the width of the LineNumberArea widget. We take the number of digits in the last line of the editor and multiply that with the maximum width of a digit.
void
CodeEditor::
updateLineNumberAreaWidth(int
/* newBlockCount */
)
{
setViewportMargins(lineNumberAreaWidth(), 0
, 0
, 0
);
}
When we update the width of the line number area, we simply call QAbstractScrollArea::setViewportMargins().
void
CodeEditor::
updateLineNumberArea(const
QRect &
amp;rect, int
dy)
{
if
(dy)
lineNumberArea-&
gt;scroll(0
, dy);
else
lineNumberArea-&
gt;update(0
, rect.y(), lineNumberArea-&
gt;width(), rect.height());
if
(rect.contains(viewport()-&
gt;rect()))
updateLineNumberAreaWidth(0
);
}
This slot is invoked when the editors viewport has been scrolled. The QRect given as argument is the part of the editing area that is do be updated (redrawn). dy holds the number of pixels the view has been scrolled vertically.
void
CodeEditor::
resizeEvent(QResizeEvent *
e)
{
QPlainTextEdit::
resizeEvent(e);
QRect cr =
contentsRect();
lineNumberArea-&
gt;setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}
When the size of the editor changes, we also need to resize the line number area.
void
CodeEditor::
highlightCurrentLine()
{
QList&
lt;QTextEdit::
ExtraSelection&
gt; extraSelections;
if
(!
isReadOnly()) {
QTextEdit::
ExtraSelection selection;
QColor lineColor =
QColor(Qt::
yellow).lighter(160
);
selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::
FullWidthSelection, true
);
selection.cursor =
textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
}
setExtraSelections(e