QT5.14.2 官方例子 - Qt Widgets 5: Code Editor(代码编辑器)

系列总链接:

QT5.14.2 官方例子 - 学习系列

https://blog.csdn.net/qq_22122811/article/details/108007519

 

代码编辑器示例展示了如何创建一个简单的编辑器,该编辑器具有行号并突出显示当前行

从图中可以看到,编辑器在要编辑的区域的左侧显示行号。编辑器将突出显示包含游标的行。

我们在CodeEditor中实现编辑器,它是一个继承QPlainTextEdit的小部件。我们在CodeEditor (LineNumberArea)中保留了一个单独的小部件,在其上绘制行号。

QPlainTextEdit从QAbstractScrollArea继承,编辑发生在它的viewport()的页边距内。我们通过将视窗的左边缘设置为绘制行号所需的大小来为行号区域腾出空间。

在编辑代码时,我们更喜欢QPlainTextEdit而不是QTextEdit,因为它为处理纯文本进行了优化。有关详细信息,请参阅QPlainTextEdit类描述。

QPlainTextEdit允许我们在用户可以用鼠标或键盘进行选择之外添加选择。我们使用此功能突出显示当前行。稍后将对此进行更多介绍。

现在,我们将继续讨论CodeEditor和LineNumberArea的定义和实现。让我们从LineNumberArea类开始。

 

详细讲解:

Code Editor Example | Qt Widgets 5.15.0

https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html

 

目录

主要的类:

思路:

1.空白区域和行号都是由什么组件组成的?

2.行号组件具体怎么工作:

2.1 行号组件定义

2.2 行号组件随着用户操作而改变


 

主要的类:

QPlainTextEdit:

 

思路:

1.空白区域和行号都是由什么组件组成的?

空白编辑区和行号总体由:codeEditor类完成,继承于QPlainTextEdit;

行号组件:由LineNumberArea类完成,继承于QWidget;

我们在这个小部件上绘制行号,并将其放置在CodeEditor的viewport()的左边框区域上。

我们在CodeEditor中实现编辑器,它是一个继承QPlainTextEdit的小部件。我们在CodeEditor (LineNumberArea)中保留了一个单独的小部件,在其上绘制行号。

QPlainTextEdit从QAbstractScrollArea继承,编辑发生在它的viewport()的页边距内。我们通过将视窗的左边缘设置为绘制行号所需的大小来为行号区域腾出空间。

 

2.行号组件具体怎么工作:

2.1 行号组件定义

 定义组件:

  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();
  }

定义了行号区域组件:

lineNumberArea = new LineNumberArea(this);

接着更新行号区域组件的宽度:

updateLineNumberAreaWidth(0);

void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
{
    setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}

[protected] void QAbstractScrollArea::setViewportMargins(int left, int top, int right, int bottom)
设置QScrollArea的上,下,左,右的页面距;

这里设置的左边距,即是行号组件的宽度;

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;
}
blockCount():
此属性保存文档中文本块的数量。
默认情况下,在空文档中,此属性的值为1。

digits:表示行号组件的最大数字个数;

函数的作用是:计算lineNumberAreaWidth()小部件的宽度。我们取编辑器的最后一行中的数字数 (blockCount即最后一行数字数),并将其与数字的最大宽度(fontMetrics().horizontalAdvance(QLatin1Char('9')))相乘。

 

2.2 行号组件随着用户操作而改变

当QScrollerArea的范围更改后,会触发updateRequest信号,执行更新行号区域的槽函数:

connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea);

[signal] void QPlainTextEdit::updateRequest(const QRect &rect, int dy)

This signal is emitted when the text document needs an update of the specified rect. If the text is scrolled, rect will cover the entire viewport area. (不包括页边距)If the text is scrolled vertically, dy carries the amount of pixels the viewport was scrolled.

The purpose of the signal is to support extra widgets in plain text edit subclasses that e.g. show line numbers, breakpoints, or other extra information.

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);
}

如果是垂直上下拉,就执行scroll(dx, dy),或者是水平和竖直方向同时变化,执行update(x,y,w,h),

两者都会使lineNumberArea调用paintEvent(QPaintEvent* event)事件:

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;
};
void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
    QPainter painter(lineNumberArea);
    // 1.填充背景
    painter.fillRect(event->rect(), Qt::lightGray);

    // 2.计算行号区域的头和底的坐标(头设置为原点)
    QTextBlock block = firstVisibleBlock();  // 当前页面, 第一块可见的文本区域
    int blockNumber = block.blockNumber();   // 第一块可见的文本区域的块编号,(编号从0开始,所以最开始是0)

    // 3.保证绘画的起始行号的头和文本块的头平齐
    // qRound: 四舍五入
    // blockBoundingGeometry(block):  返回块的矩形,这里的块的顶部坐标为0;
    // QRectF QRectF::translated(const QPointF &offset) const:
    //                  返回对进行偏移offset的矩形,这里的块的顶部坐标为内容偏移的坐标;
    int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());
    //int top = qRound(blockBoundingGeometry(block).top());
    qDebug() << "top: " << top;
    int bottom = top + qRound(blockBoundingRect(block).height());

    // 如果块有效,(用回车键分配了)
    while (block.isValid() && top <= event->rect().bottom())
    {
        // 块可见,底部坐标大于当前事件的顶部坐标
        if (block.isVisible() && bottom >= event->rect().top())
        {
            // 因为块呈序列的,从0开始,所以可以将块号+1,作为行号
            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;
    }
}

 

当新增加一行,高亮,默认刚开始的block的数量为1,行号随机变化:

    connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine);

当光标位置改变时,我们突出显示当前行,即包含光标的行。

QPlainTextEdit提供了在同一时间有多个选择的可能性。我们可以设置这些选择的字符格式(QTextCharFormat)。在设置新的QPlainTextEdit::ExtraSelection之前,我们清除游标选择,否则当用户用鼠标选择多行时,几行将被突出显示。

一个用文本光标设置选择。当使用FullWidthSelection属性时,当前光标文本块(行)将被选中。如果您只想选择文本块的一部分,则应该使用QTextCursor::movePosition()将光标从使用setPosition()设置的位置中移动。

 

当可编辑文本框block的数量发生变化,将行号组件的宽度做一次更新:

connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth);

槽函数实现分析:参考2.1

 

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Command line: -prefix /home/liuyh/workspace/qt5.14.2-arm -opensource -confirm-license -release -strip -shared -xplatform linux-arm-gnueabi-g++ -optimized-qmake -c++std c++11 --rpath=no -pch -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcanvas3d -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtspeech -skip qtsvg -skip qttools -skip qttranslations -skip qtwayland -skip qtwebengine -skip qtwebview -skip qtwinextras -skip qtx11extras -skip qtxmlpatterns -make libs -make examples -nomake tools -nomake tests -gui -widgets -dbus-runtime --glib=no --iconv=no --pcre=qt --zlib=qt -no-openssl --freetype=qt --harfbuzz=qt -no-opengl -linuxfb --xcb=no -tslib --libpng=qt --libjpeg=qt --sqlite=qt -plugin-sql-sqlite -I/opt/tslib/include -L/opt/tslib/lib -recheck-all executing config test machineTuple + arm-linux-gnueabi-g++ -dumpmachine > sh: 1: arm-linux-gnueabi-g++: not found test config.qtbase.tests.machineTuple FAILED executing config test verifyspec + cd /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/config.tests/verifyspec && /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/bin/qmake "CONFIG -= qt debug_and_release app_bundle lib_bundle" "CONFIG += shared warn_off console single_arch" 'QMAKE_LIBDIR += /opt/tslib/lib' 'INCLUDEPATH += /opt/tslib/include' -early "CONFIG += cross_compile" /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec + cd /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/config.tests/verifyspec && MAKEFLAGS= /usr/bin/make clean && MAKEFLAGS= /usr/bin/make > rm -f verifyspec.o > rm -f *~ core *.core > arm-linux-gnueabi-g++ -c -O2 -march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard -O2 -march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard -pipe -O2 -w -fPIC -I/home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec -I. -I/opt/tslib/include -I/home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/mkspecs/linux-arm-gnueabi-g++ -o verifyspec.o /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec/verifyspec.cpp > make:arm-linux-gnueabi-g++:命令未找到 > make: *** [Makefile:172:verifyspec.o] 错误 127
06-09

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值