mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-08 02:17:43 +08:00
qt 6.5.1 original
This commit is contained in:
37
tests/manual/textrendering/codeeditor/CMakeLists.txt
Normal file
37
tests/manual/textrendering/codeeditor/CMakeLists.txt
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(codeeditor LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/widgets/codeeditor")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(codeeditor
|
||||
codeeditor.cpp codeeditor.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(codeeditor PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(codeeditor PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS codeeditor
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
134
tests/manual/textrendering/codeeditor/codeeditor.cpp
Normal file
134
tests/manual/textrendering/codeeditor/codeeditor.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "codeeditor.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QTextBlock>
|
||||
|
||||
//![constructor]
|
||||
|
||||
CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
|
||||
{
|
||||
lineNumberArea = new LineNumberArea(this);
|
||||
|
||||
connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth);
|
||||
connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea);
|
||||
connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine);
|
||||
|
||||
updateLineNumberAreaWidth(0);
|
||||
highlightCurrentLine();
|
||||
}
|
||||
|
||||
//![constructor]
|
||||
|
||||
//![extraAreaWidth]
|
||||
|
||||
int CodeEditor::lineNumberAreaWidth()
|
||||
{
|
||||
int digits = 1;
|
||||
int max = qMax(1, blockCount());
|
||||
while (max >= 10) {
|
||||
max /= 10;
|
||||
++digits;
|
||||
}
|
||||
|
||||
int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
//![extraAreaWidth]
|
||||
|
||||
//![slotUpdateExtraAreaWidth]
|
||||
|
||||
void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
|
||||
{
|
||||
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
|
||||
}
|
||||
|
||||
//![slotUpdateExtraAreaWidth]
|
||||
|
||||
//![slotUpdateRequest]
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//![slotUpdateRequest]
|
||||
|
||||
//![resizeEvent]
|
||||
|
||||
void CodeEditor::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QPlainTextEdit::resizeEvent(e);
|
||||
|
||||
QRect cr = contentsRect();
|
||||
lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
|
||||
}
|
||||
|
||||
//![resizeEvent]
|
||||
|
||||
//![cursorPositionChanged]
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//![cursorPositionChanged]
|
||||
|
||||
//![extraAreaPaintEvent_0]
|
||||
|
||||
void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPainter painter(lineNumberArea);
|
||||
painter.fillRect(event->rect(), Qt::lightGray);
|
||||
|
||||
//![extraAreaPaintEvent_0]
|
||||
|
||||
//![extraAreaPaintEvent_1]
|
||||
QTextBlock block = firstVisibleBlock();
|
||||
int blockNumber = block.blockNumber();
|
||||
int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());
|
||||
int bottom = top + qRound(blockBoundingRect(block).height());
|
||||
//![extraAreaPaintEvent_1]
|
||||
|
||||
//![extraAreaPaintEvent_2]
|
||||
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 + qRound(blockBoundingRect(block).height());
|
||||
++blockNumber;
|
||||
}
|
||||
}
|
||||
//![extraAreaPaintEvent_2]
|
||||
|
68
tests/manual/textrendering/codeeditor/codeeditor.h
Normal file
68
tests/manual/textrendering/codeeditor/codeeditor.h
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CODEEDITOR_H
|
||||
#define CODEEDITOR_H
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPaintEvent;
|
||||
class QResizeEvent;
|
||||
class QSize;
|
||||
class QWidget;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class LineNumberArea;
|
||||
|
||||
//![codeeditordefinition]
|
||||
|
||||
class CodeEditor : public QPlainTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CodeEditor(QWidget *parent = nullptr);
|
||||
|
||||
void lineNumberAreaPaintEvent(QPaintEvent *event);
|
||||
int lineNumberAreaWidth();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void updateLineNumberAreaWidth(int newBlockCount);
|
||||
void highlightCurrentLine();
|
||||
void updateLineNumberArea(const QRect &rect, int dy);
|
||||
|
||||
private:
|
||||
QWidget *lineNumberArea;
|
||||
};
|
||||
|
||||
//![codeeditordefinition]
|
||||
//![extraarea]
|
||||
|
||||
class LineNumberArea : public QWidget
|
||||
{
|
||||
public:
|
||||
LineNumberArea(CodeEditor *editor) : QWidget(editor), codeEditor(editor)
|
||||
{}
|
||||
|
||||
QSize sizeHint() const override
|
||||
{
|
||||
return QSize(codeEditor->lineNumberAreaWidth(), 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override
|
||||
{
|
||||
codeEditor->lineNumberAreaPaintEvent(event);
|
||||
}
|
||||
|
||||
private:
|
||||
CodeEditor *codeEditor;
|
||||
};
|
||||
|
||||
//![extraarea]
|
||||
|
||||
#endif
|
8
tests/manual/textrendering/codeeditor/codeeditor.pro
Normal file
8
tests/manual/textrendering/codeeditor/codeeditor.pro
Normal file
@ -0,0 +1,8 @@
|
||||
QT += widgets
|
||||
|
||||
HEADERS = codeeditor.h
|
||||
SOURCES = main.cpp \
|
||||
codeeditor.cpp
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/widgets/codeeditor
|
||||
INSTALLS += target
|
173
tests/manual/textrendering/codeeditor/codeeditor.qdoc
Normal file
173
tests/manual/textrendering/codeeditor/codeeditor.qdoc
Normal file
@ -0,0 +1,173 @@
|
||||
// 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 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/}.
|
||||
|
||||
*/
|
18
tests/manual/textrendering/codeeditor/main.cpp
Normal file
18
tests/manual/textrendering/codeeditor/main.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "codeeditor.h"
|
||||
|
||||
int main(int argv, char **args)
|
||||
{
|
||||
QApplication app(argv, args);
|
||||
|
||||
CodeEditor editor;
|
||||
editor.setWindowTitle(QObject::tr("Code Editor Example"));
|
||||
editor.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
Reference in New Issue
Block a user