8ecd81ae86
Change-Id: Ia7a38a1035bd34d00f20351a0adc3927e473b2e7 Pick-to: 6.5 6.4 6.2 Reviewed-by: Topi Reiniö <topi.reinio@qt.io>
174 lines
7.1 KiB
Plaintext
174 lines
7.1 KiB
Plaintext
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
|
|
|
/*!
|
|
\example widgets/codeeditor
|
|
\title Code Editor Example
|
|
\ingroup examples-widgets
|
|
\brief The Code Editor example shows how to create a simple editor that
|
|
has line numbers and that highlights the current line.
|
|
|
|
\borderedimage codeeditor-example.png
|
|
|
|
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 \c CodeEditor, which is a widget that
|
|
inherits QPlainTextEdit. We keep a separate widget in \c
|
|
CodeEditor (\c LineNumberArea) onto which we draw the line
|
|
numbers.
|
|
|
|
QPlainTextEdit inherits from QAbstractScrollArea, and editing
|
|
takes place within its \l{QAbstractScrollArea::}{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 \c
|
|
CodeEditor and \c LineNumberArea. Let's start with the \c
|
|
LineNumberArea class.
|
|
|
|
\section1 The LineNumberArea Class
|
|
|
|
We paint the line numbers on this widget, and place it over the \c
|
|
CodeEditor's \l{QAbstractScrollArea::}{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 \c 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 \l{QWidget::}{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.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.h extraarea
|
|
|
|
\section1 CodeEditor Class Definition
|
|
|
|
Here is the code editor's class definition:
|
|
|
|
\snippet widgets/codeeditor/codeeditor.h codeeditordefinition
|
|
|
|
In the editor we resize and draw the line numbers on the \c
|
|
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 \c updateLineNumberWidth() and \c updateLineNumberArea().
|
|
|
|
Whenever, the cursor's position changes, we highlight the current
|
|
line in \c highlightCurrentLine().
|
|
|
|
\section1 CodeEditor Class Implementation
|
|
|
|
We will now go through the code editors implementation, starting
|
|
off with the constructor.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp constructor
|
|
|
|
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.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp extraAreaWidth
|
|
|
|
The \c lineNumberAreaWidth() function calculates the width of the
|
|
\c 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.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp slotUpdateExtraAreaWidth
|
|
|
|
When we update the width of the line number area, we simply call
|
|
QAbstractScrollArea::setViewportMargins().
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp slotUpdateRequest
|
|
|
|
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). \c dy holds the number of pixels the
|
|
view has been scrolled vertically.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp resizeEvent
|
|
|
|
When the size of the editor changes, we also need to resize the
|
|
line number area.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp cursorPositionChanged
|
|
|
|
When the cursor position changes, we highlight the current line,
|
|
i.e., the line containing the cursor.
|
|
|
|
QPlainTextEdit gives the possibility to have more than one
|
|
selection at the same time. we can set the character format
|
|
(QTextCharFormat) of these selections. We clear the cursors
|
|
selection before setting the new
|
|
QPlainTextEdit::ExtraSelection, else several lines would get
|
|
highlighted when the user selects multiple lines with the mouse.
|
|
\omit ask someone how this works \endomit
|
|
|
|
One sets the selection with a text cursor. When using the
|
|
FullWidthSelection property, the current cursor text block (line)
|
|
will be selected. If you want to select just a portion of the text
|
|
block, the cursor should be moved with QTextCursor::movePosition()
|
|
from a position set with \l{QTextCursor::}{setPosition()}.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp extraAreaPaintEvent_0
|
|
|
|
The \c lineNumberAreaPaintEvent() is called from \c LineNumberArea
|
|
whenever it receives a paint event. We start off by painting the
|
|
widget's background.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp extraAreaPaintEvent_1
|
|
|
|
We will now loop through all visible lines and paint the line
|
|
numbers in the extra area for each line. Notice that in a plain
|
|
text edit each line will consist of one QTextBlock; though, if
|
|
line wrapping is enabled, a line may span several rows in the text
|
|
edit's viewport.
|
|
|
|
We get the top and bottom y-coordinate of the first text block,
|
|
and adjust these values by the height of the current text block in
|
|
each iteration in the loop.
|
|
|
|
\snippet widgets/codeeditor/codeeditor.cpp extraAreaPaintEvent_2
|
|
|
|
Notice that we check if the block is visible in addition to check
|
|
if it is in the areas viewport - a block can, for example, be
|
|
hidden by a window placed over the text edit.
|
|
|
|
\section1 Suggestions for Extending the Code Editor
|
|
|
|
No self-respecting code editor is without a syntax
|
|
highligther; the \l{Syntax Highlighter Example} shows how to
|
|
create one.
|
|
|
|
In addition to line numbers, you can add more to the extra area,
|
|
for instance, break points.
|
|
|
|
QSyntaxHighlighter gives the possibility to add user data to each
|
|
text block with
|
|
\l{QSyntaxHighlighter::}{setCurrentBlockUserData()}. This can be
|
|
used to implement parenthesis matching. In the \c
|
|
highlightCurrentLine(), the data of the currentBlock() can be
|
|
fetched with QTextBlock::userData(). Matching parentheses can be
|
|
highlighted with an extra selection. The "Matching Parentheses
|
|
with QSyntaxHighlighter" article in Qt Quarterly 31 implements
|
|
this. You find it here: \l{http://doc.qt.io/archives/qq/}.
|
|
|
|
*/
|