Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Toutes les fonctions  ·  Vues d'ensemble  · 

Code Editor Example

Files:

The Code Editor example shows how to create a simple editor that has line numbers and that highlights the current line.

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 {
         return QSize(codeEditor->lineNumberAreaWidth(), 0);
     }

 protected:
     void paintEvent(QPaintEvent *event) {
         codeEditor->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);

 private slots:
     void updateLineNumberAreaWidth(int newBlockCount);
     void highlightCurrentLine();
     void updateLineNumberArea(const QRect &, 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 >= 10) {
         max /= 10;
         ++digits;
     }

     int space = 3 + fontMetrics().width(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 &rect, int dy)
 {
     if (dy)
         lineNumberArea->scroll(0, dy);
     else
         lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());

     if (rect.contains(viewport()->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->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<QTextEdit::ExtraSelection> 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(extraSelections);
 }

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 new QPlainTextEdit::ExtraSelection, else several lines would get highlighted when the user selects multiple lines with the mouse.

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 setPosition().

 void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
 {
     QPainter painter(lineNumberArea);
     painter.fillRect(event->rect(), Qt::lightGray);

The lineNumberAreaPaintEvent() is called from LineNumberArea whenever it receives a paint event. We start off by painting the widget's background.

     QTextBlock block = firstVisibleBlock();
     int blockNumber = block.blockNumber();
     int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
     int bottom = top + (int) blockBoundingRect(block).height();

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.

     while (block.isValid() && top <= event->rect().bottom()) {
         if (block.isVisible() && bottom >= event->rect().top()) {
             QString number = QString::number(blockNumber + 1);
             painter.setPen(Qt::black);
             painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(),
                              Qt::AlignRight, number);
         }

         block = block.next();
         top = bottom;
         bottom = top + (int) blockBoundingRect(block).height();
         ++blockNumber;
     }
 }

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.

Suggestions for Extending the Code Editor

No self-respecting code editor is without a syntax highligther; the 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 setCurrentBlockUserData(). This can be used to implement parenthesis matching. In the highlightCurrentLine(), the data of the currentBlock() can be fetched with QTextBlock::userData(). Matching parentheses can be highlighted with an extra selection.

Publicité

Best Of

Actualités les plus lues

Semaine
Mois
Année
  1. Microsoft ouvre aux autres compilateurs C++ AMP, la spécification pour la conception d'applications parallèles C++ utilisant le GPU 22
  2. Les développeurs ignorent-ils trop les failles découvertes dans leur code ? Prenez-vous en compte les remarques des autres ? 17
  3. « Quelque chose ne va vraiment pas avec les développeurs "modernes" », un développeur à "l'ancienne" critique la multiplication des bibliothèques 17
  4. RIM : « 13 % des développeurs ont gagné plus de 100 000 $ sur l'AppWord », Qt et open-source au menu du BlackBerry DevCon Europe 0
  5. BlackBerry 10 : premières images du prochain OS de RIM qui devrait intégrer des widgets et des tuiles inspirées de Windows Phone 0
  6. Adieu qmake, bienvenue qbs : Qt Building Suite, un outil déclaratif et extensible pour la compilation de projets Qt 17
  7. Quelles nouveautés de C++11 Visual C++ doit-il rapidement intégrer ? Donnez-nous votre avis 10
Page suivante

Le blog Digia au hasard

Logo

Déploiement d'applications Qt Commercial sur les tablettes Windows 8

Le blog Digia est l'endroit privilégié pour la communication sur l'édition commerciale de Qt, où des réponses publiques sont apportées aux questions les plus posées au support. Lire l'article.

Communauté

Ressources

Liens utiles

Contact

  • Vous souhaitez rejoindre la rédaction ou proposer un tutoriel, une traduction, une question... ? Postez dans le forum Contribuez ou contactez-nous par MP ou par email (voir en bas de page).

Qt dans le magazine

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.6
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
 
 
 
 
Partenaires

Hébergement Web