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
相关文章:
QT编辑框带行号
很可惜,qt的几个编辑框并没有相关功能。所以我们要自己实现一个。 先讲讲原理: QPlainTextEdit继承自QAbstractScrollArea,编辑发生在其viewport()的边距内。我们可以通过将视口的左边缘设置一个空白区域,…...
Kafka认证时Successfully logged in真的认证成功了?
背景 某个应用需要配置 Kafka 集群信息,且需要在验证集群是否可达。基本实现思路是创建一个生产者对象,然后发送一条测试数据,调用 Producer 的 send 方法发送消息后,再调用 get() 方法,即同步发送消息,测…...
软考信息系统管理师,系统集成项目管理工程师,考哪一个合适?
根据2024年的考试安排,高级项目管理师和系统集成工程师考试改为每年一次。 2024年上半年考高级项目管理师,下半年考系统集成项目管理工程师。 根据这个调整,建议先报名5月份的高级项目管理师考试。如果通过了,大家都高兴&#x…...
AI学习指南自然语言处理篇-位置编码(Positional Encoding)
AI学习指南自然语言处理篇-位置编码(Positional Encoding) 目录 引言位置编码的作用位置编码的原理绝对位置编码相对位置编码位置编码在Transformer中的应用位置编码的意义总结 引言 在自然语言处理中,文本数据通常以序列的形式存在。然而…...
macOS 15 Sequoia dmg格式转用于虚拟机的iso格式教程
想要把dmg格式转成iso格式,然后能在虚拟机上用,最起码新版的macOS镜像是不能用UltraISO,dmg2iso这种软件了,你直接转放到VMware里绝对读不出来,办法就是,在Mac系统中转换为cdr,然后再转成iso&am…...
【01初识】-初识 RabbitMQ
目录 学习背景1- 初识 MQ1-1 同步调用什么是同步调用?小结:同步调用优缺点 1-2 异步调用什么是异步调用?小结:异步调用的优缺点,什么时候使用异步调用? 1-3 MQ 技术选型 学习背景 异步通讯的特点ÿ…...
CTF-RE 从0到N:汇编层函数调用
windows 在 Windows 平台上的汇编语言中,调用函数的方式通常遵循特定的调用约定(Calling Convention)。最常见的调用约定包括: cdecl: C 默认调用约定,调用者清理堆栈。stdcall: Windows API 默认调用约定࿰…...
雷池社区版compose配置文件解析-mgt
在现代网络安全中,选择合适的 Web 应用防火墙至关重要。雷池(SafeLine)社区版免费切好用。为网站提供全面的保护,帮助网站抵御各种网络攻击。 compose.yml 文件是 Docker Compose 的核心文件,用于定义和管理多个 Dock…...
无人机避障——4D毫米波雷达Octomap从点云建立三维栅格地图
Octomap安装 sudo apt-get install ros-melodic-octomap-ros sudo apt-get install ros-melodic-octomap-msgs sudo apt-get install ros-melodic-octomap-server sudo apt-get install ros-melodic-octomap-rviz-plugins # map_server安装 sudo apt-get install ros-melodic-…...
Python(数据结构2)
常见数据结构 队列 队列(Queue),它是一种运算受限的线性表,先进先出(FIFO First In First Out) Python标准库中的queue模块提供了多种队列实现,包括普通队列、双端队列、优先队列等。 1 普通队列 queue.Queue 是 Python 标准库 queue 模块中的一个类…...
深入解析HTTP与HTTPS的区别及实现原理
文章目录 引言HTTP协议基础HTTP响应 HTTPS协议SSL/TLS协议 总结参考资料 引言 HTTP(HyperText Transfer Protocol)超文本传输协议是用于从Web服务器传输超文本到本地浏览器的主要协议。随着网络安全意识的提高,HTTPS(HTTP Secure…...
Java IO 模型
I/O 何为 I/O? I/O(Input/Output) 即输入/输出 。 我们先从计算机结构的角度来解读一下 I/O。 根据冯.诺依曼结构,计算机结构分为 5 大部分:运算器、控制器、存储器、输入设备、输出设备。 输入设备(比…...
安装双系统后ubuntu无法联网(没有wifi标识)网卡驱动为RTL8852BE
安装双系统后ubuntu没有办法联网,(本篇博客适用的版本为ubuntu20.04)且针对情况为无线网卡驱动未安装的情况 此时没有网络,可以使用手机数据线连接,使用USB共享网络便可解决无法下载的问题。 打开终端使用命令lshw -C …...
Sqoop的安装配置及使用
Sqoop安装前需要检查之前是否安装了Tez,否则会产生版本或依赖冲突,我们需要移除tez-site.xml,并将hadoop中的mapred-site.xml配置文件中的mapreduce驱动改回成yarn,然后分发到其他节点,hive里面配置的tez也要移除,然后…...
R语言机器学习算法实战系列(十三)随机森林生存分析构建预后模型 (Random Survival Forest)
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程加载R包案例数据数据预处理数据描述构建randomForestSRC模型评估模型C-indexBrier score特征重要性构建新的随机森林生存模型风险打分高低风险分组的生存分析时间依赖的ROC(Ti…...
三款计算服务器配置→如何选择科学计算服务器?
科学计算在众多领域都扮演着关键角色,无论是基础科学研究还是实际工程应用,强大的计算能力都是不可或缺的。而选择一台合适的科学计算服务器,对于确保科研和工作的顺利进行至关重要。 首先,明确自身需求是重中之重。要仔细考虑计算…...
Oracle 19c RAC删除多余的PDB的方式
文章目录 一、删除PDB并删除数据文件二、删除PDB并保留数据文件三、插拔PDB 一、删除PDB并删除数据文件 所删除的pdb必须是mount的状态才可以删除: #1、关闭pdb alter pluggable database pdb_name close immediate instancesall; #2、删除pdb以及数据文件 drop p…...
什么是云渲染?云渲染有什么用?一篇看懂云渲染意思
你知道云渲染是怎么回事吗? 其实就是把3D模型变成2D图像的过程,只不过这个过程是在云端完成的。我们在本地啥都不用做,只需要等结果就行。 现在云渲染主要有两种类型:一种是物理机房云渲染,另一种是服务器机房云渲染。…...
MATLAB中 exist函数用法
目录 语法 说明 示例 检查工作区变量是否存在 检查文件夹是否存在 检查 MATLAB 函数是否为内置函数 exist函数的功能是检查变量、脚本、函数、文件夹或类的存在情况。 语法 exist name exist name searchType A exist(___) 说明 exist name 以数字形式返回 name 的类…...
在银河麒麟系统中Qt连接达梦数据库
解决在银河麒麟系统中使用Qt连接达梦数据库提示:project Error library odbc is not defined问题 一、编译ODBC 下载解压unixODBC(http://www.unixodbc.org/unixODBC-2.3.1.tar.gz) 打开终端,切换到unixODBC-2.3.1目录下&#x…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
