QT编辑框带行号

很可惜,qt的几个编辑框并没有相关功能。所以我们要自己实现一个。

先讲讲原理:
QPlainTextEdit继承自QAbstractScrollArea,编辑发生在其viewport()的边距内。我们可以通过将视口的左边缘设置一个空白区域,用于绘制行号。

之所以使用QPlainTextEdit而不是QTextEdit,因为它针对处理纯文本进行了优化。更重要的是它允许我们在高亮多行文字。
 

一.LineNumberArea类

我们新建一个类,叫做LineNumberArea,继承QWidget,并在上绘制行号。

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

二.CodeEditor类

CodeEditor继承QPlainTextEdit,LineNumberArea是他的私有成员变量。

此外我们还要增加几个方法,用于计算左侧行号的渲染绘制的空白区域大小。

详见代码

class CodeEditor : public QPlainTextEdit
{Q_OBJECTpublic: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;
};

当编辑器中的行数发生变化或者编辑器的viewport()滚动时或者编辑器的大小发生时,我们需要调整左侧区域大小,并绘制行号。因此我们需要updateLineNumberWidth()和updateLineNumberArea()方法。

三.CodeEditor类实现

在构造函数中,我们将QPlainTextEdit中的信号连接到对应的槽函数。

然后计算行号区域宽度并高亮显示第一行。

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();//高亮显示
}

lineNumberAreaWidth()函数计算LineNumberArea的宽度并返回。

一般取编辑器最后一行的文字,并计算该行文字的宽度。

按字符’9‘的宽度作为单个字符的宽度。

int CodeEditor::lineNumberAreaWidth()
{int digits = 1;int max = qMax(1, blockCount());//计算数位while (max >= 10) {max /= 10;++digits;}//取字符9的宽度int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;return space;
}

当我们更新行号区域的宽度时,需调用QAbstractScrollArea::setViewportMargins(),更新设置左侧行号区的宽度。

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

当编辑器视口滚动时,会调用updateLineNumberArea。QRect是编辑区域中需要更新(重绘)的部分。dy是鼠标滚动时的距离,单位是像素。

void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
{if (dy)lineNumberArea->scroll(0, dy);elselineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());if (rect.contains(viewport()->rect()))updateLineNumberAreaWidth(0);
}

当编辑器的大小发生变化时,我们还需要调整行号区域的大小。

void CodeEditor::resizeEvent(QResizeEvent *e)
{QPlainTextEdit::resizeEvent(e);QRect cr = contentsRect();lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}

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

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

每当LineNumberArea接收到绘制事件(paintEvent)时,就会调用CodeEditor的lineNumberAreaPaintEvent。

lineNumberAreaPaintEvent将遍历所有可见的线条,并在每行的额外区域中绘制行号。在纯文本编辑中,每一行都由一个QTextBlock组成;

void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{QPainter painter(lineNumberArea);painter.fillRect(event->rect(), Qt::lightGray);QTextBlock block = firstVisibleBlock();int blockNumber = block.blockNumber();int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());int bottom = top + qRound(blockBoundingRect(block).height());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;}
}

参考资料:

Code Editor Example | Qt Widgets 5.15.17

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/883422.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QtCreator通过CMake多文件编译.cpp、.qss、.h、.ui文件,达到MVC三层架构的效果

博主在构建C项目的时候&#xff0c;一般都喜欢将头文件和源文件分开为不同的文件夹&#xff0c;比如include目录下只存放.h文件和.ui文件&#xff0c;src目录下只存放.cpp和.qss文件&#xff0c;res目录下只存放图片、音频等文件&#xff0c;这时候使用CMake对项目进行分文件管…

qml圆形图片,qml圆形头像制作

代码比较简单&#xff0c;就不细讲了&#xff0c;大家直接看下面源码吧&#xff01;如果对你有所帮助&#xff0c;可以帮角角点个关注嘛&#xff1f; import QtQuick import QtQuick.Effects import Qt5Compat.GraphicalEffectsWindow {width: 640height: 480visible: truetit…

使用代理服务器后sse数据合并问题

如果是使用本地代理服务器devServer compress:false,如果是发布到生产环境下的代理服务器nginx 增加如下配置&#xff0c;该配置同时支持websocket和sse proxy_http_version 1.1; #设置代理请求使用 HTTP/1.1 版本。WebSocket 需要 HTTP/1.1&#xff0c;因为它支持持久连接和更…

【每日一题】LeetCode - 盛最多水的容器

给定一个长度为 n 的整数数组 height。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i])。要求找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 输入示例&#xff1a; height [1,8,6,2,5,4,8,3,7]输出&#xff1a; 4…

Python快速入门教程

目录 1. Python 简介 2. 环境准备 3. 第一个 Python 程序 4. 变量与数据类型 5. 基本操作与控制结构 6. 函数与模块 7. 实践项目 结语 Python 是一种非常友好的编程语言&#xff0c;特别适合初学者。它的语法简洁&#xff0c;容易上手&#xff0c;并且广泛应用于各种领…

C++结合图形编程与物联网:你更偏向哪种方式来学习信息学奥赛?

随着信息学奥赛在全国范围内的热度逐年攀升&#xff0c;学生和家长们越来越重视如何有效备赛。传统的编程学习方式侧重于算法和数据结构&#xff0c;但随着科技的发展&#xff0c;图形化编程与物联网&#xff08;IoT&#xff09;项目逐渐成为新兴的学习路径。通过C结合图形化编…

Rust 力扣 - 1. 两数相加

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用一个全局的备忘录&#xff0c;然后我们遍历数组&#xff0c;如果当前元素在备忘录里面找到了&#xff0c;就返回备忘录里面记录的下标和当前下标记录&#xff0c;没找到就把当前元素匹配的元素和当前元素…

人工智能_神经网络103_感知机_感知机工作原理_感知机具备学习能力_在学习过程中自我调整权重_优化效果_多元线性回归_逻辑回归---人工智能工作笔记0228

由于之前一直对神经网络不是特别清楚,尤其是对神经网络中的一些具体的概念,包括循环,神经网络卷积神经网络以及他们具体的作用,都是应用于什么方向不是特别清楚,所以现在我们来做教程来具体明确一下。 当然在机器学习之后还有深度学习,然后在深度学习中对各种神经网络的…

Java对称加密:AES 高级加密标准

1、对称加密简述 对称加密&#xff0c;又称对称密钥加密或私钥加密&#xff0c;是一种在加密和解密过程中使用相同一个密钥的加密算法。这种加密方式的核心在于&#xff0c;发送方使用某个密钥对数据进行加密&#xff0c;接收方则使用完全相同的密钥对数据进行解密。由于加密和…

基于物联网的智慧考场系统设计(论文+源码)

1. 功能设计 &#xff08;1&#xff09;温度监测与控制功能&#xff1a; 系统需要能够实时采集考场内的温度信息&#xff0c;通过DS18B20传感器获取准确的数据&#xff0c;并在OLED屏幕和APP上显示。当温度异常过高时&#xff0c;系统应自动启动继电器&#xff0c;模拟空调开启…

数字IC后端实现 | Innovus各个阶段常用命令汇总

应各位读者要求&#xff0c;小编最近按照Innovus流程顺序整理出数字IC后端项目中常用的命令汇总。限于篇幅&#xff0c;这次只更新到powerplan阶段。有了这份Innovus常用命令汇总&#xff0c;学习数字IC后端从此不再迷路&#xff01;如果大家觉得这个专题还不错&#xff0c;想继…

C语言_动态内存管理

本章重点 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 几个经典的笔试题 柔性数组 1. 为什么存在动态内存分配 我们已经掌握的内存开辟方式有&#xff1a; int val 20;//在栈空间上开辟四个字节 char arr[10] {0}…

Maven进阶——坐标、依赖、仓库

目录 1.pomxml文件 2. 坐标 2.1 坐标的概念 2.2 坐标的意义 2.3 坐标的含义 2.4 自己项目的坐标 2.5 第三方项目坐标 3. 依赖 3.1 依赖的意义 3.2 依赖的使用 3.3 第三方依赖的查找方法 3.4 依赖范围 3.5 依赖传递和可选依赖 3.5.1 依赖传递 3.5.2 依赖范围对传…

算法的学习笔记—数组中的逆序对(牛客JZ51)

&#x1f600;前言 在算法和数据结构领域&#xff0c;"逆序对"是一个经典问题。它在数组中两个数字之间定义&#xff0c;若前面的数字大于后面的数字&#xff0c;则这两个数字组成一个逆序对。我们要做的就是&#xff0c;给定一个数组&#xff0c;找出数组中所有的逆…

Docker 镜像下载问题及解决办法

Docker 镜像下载问题及解决办法 我在杂乱的、破旧的村庄寂寞地走过漫长的雨季&#xff0c;将我年少的眼光从晦暗的日子里打捞出来的是一棵棵开花的树&#xff0c;它们以一串串卓然不俗的花擦明了我的眼睛&#xff0c;也洗净了我的灵魂。 引言 在使用 Docker 时&#xff0c;用户…

【AI绘画】Midjourney进阶:对角线构图详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;什么是构图为什么Midjourney要使用构图 &#x1f4af;对角线构图特点应用场景提示词书写技巧测试 &#x1f4af;小结 &#x1f4af;前言 【AI绘画】Midjourney进阶&a…

免费送源码:Java+MVC+HTML+CSS +MySQL 考研资料共享系统的设计与实现 计算机毕业设计原创定制

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设考研资料共享系统。 本…

Win10+MinGW13.1.0编译Qt5.15.15

安装windows SDK、python、ruby、cmake、Perl[可选]安装MySQL解压qt-everywhere-opensource-src-5.15.15.zip&#xff08;注&#xff1a;不要使用qt-everywhere-opensource-src-5.15.15.tar.xz&#xff09;修改源代码 E:\qt-everywhere-src-5.15.15\qtbase\src\3rdparty\angle\…

028_Comma_Separated_List_in_Matlab中的逗号分割列表

什么是逗号分割列表 这玩意一般都不知道是什么&#xff0c;Comma-separated list&#xff0c;CSL&#xff0c; 虽然&#xff0c;用Matlab的时候天天会用到。这到底是个什么玩意&#xff1f;或者&#xff0c;更进一步&#xff0c;这到底是不是个玩意&#xff1f; 每次调用一个…

CSS3 动画相关属性实例大全(三)(columns、filter、flex、flex-basis 、flex-grow、flex-shrink属性)

CSS3 动画相关属性实例大全&#xff08;三) &#xff08;columns、filter、flex、flex-basis 、flex-grow、flex-shrink属性&#xff09; 本文目录&#xff1a; 一、columns属性&#xff08;设置元素的列宽和列数&#xff09; 二、filter属性&#xff08;调整图像、背景和边…