QT实战--带行号的支持高亮的编辑器实现(1)

本文主要介绍了基于QPlainTextEdit实现的,带有行号的,支持高亮的编辑器实现,话不多说,先上效果图:

1.行号头文件:linenumberarea.h

#ifndef LINENUMBERAREA_H
#define LINENUMBERAREA_H


#include <QWidget>
#include <QSize>

#include "codeeditor.h"

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

#endif // LINENUMBERAREA_H

2.编辑器头文件:codeeditor.h

#ifndef CODEEDITOR_H
#define CODEEDITOR_H

#include <QPlainTextEdit>


//位置:左边LineNumberArea+右边QPlainTextEdit

class CodeEditor : public QPlainTextEdit
{
    Q_OBJECT

public:
    CodeEditor(QWidget *parent = nullptr);

    void SetPainText(QString strText);

    void lineNumberAreaPaintEvent(QPaintEvent *event);
    int lineNumberAreaWidth();

protected:
    void resizeEvent(QResizeEvent *event) override;

private slots:
    void slotBlockCountChanged(int newBlockCount);
    void slotUpdateRequest(const QRect &rect, int dy);
    void slotCursorPositionChanged();

private:
    void updateLineNumberAreaWidth(int newBlockCount);
    void highlightCurrentLine();
    void updateLineNumberArea(const QRect &rect, int dy);


private:
    QWidget *lineNumberArea;

    bool m_bInit = false;
};

#endif // CODEEDITOR_H

编辑器cpp文件:codeeditor.cpp

#include "codeeditor.h"

#include <QPainter>
#include <QTextBlock>

#include "linenumberarea.h"

#include <QDebug>

CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
{
    lineNumberArea = new LineNumberArea(this);

    connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::slotBlockCountChanged);
    connect(this, &CodeEditor::updateRequest, this, &CodeEditor::slotUpdateRequest);
    connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::slotCursorPositionChanged);

    updateLineNumberAreaWidth(0);
    highlightCurrentLine();

    m_bInit = true;
}

void CodeEditor::SetPainText(QString strText)
{
    this->blockSignals(true);//处理期间不响应各种事件
    this->setPlainText(strText);
    this->blockSignals(false);


    updateLineNumberAreaWidth(0);//更新行号(位置和显示文字)

}

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

void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
{
    setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);//宽度变化了,会触发resize,从而设置行号的位置
}

void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
{
    if (dy)
        lineNumberArea->scroll(0, dy);//滚动会用到
    else
        lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());

    QRect rctmp =viewport()->rect();

    if (rect.contains(viewport()->rect()))//
        updateLineNumberAreaWidth(0);
}

void CodeEditor::resizeEvent(QResizeEvent *e)
{
    qDebug() << "\n--resizeEvent";

    if(!m_bInit)
    {
        return;
    }

    QPlainTextEdit::resizeEvent(e);

    QRect cr = contentsRect();

    lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));//设置行号位置
}

//换行会先触发slotCursorPositionChanged,再触发这个
void CodeEditor::slotBlockCountChanged(int newBlockCount)
{
    qDebug() << "\n--slotBlockCountChanged updateLineNumberAreaWidth(0)-- newBlockCount:" << newBlockCount;

    if(!m_bInit)
    {
        return;
    }

    updateLineNumberAreaWidth(0);

}

//光标闪动,文字变化,等,都会一直触发此
void CodeEditor::slotUpdateRequest(const QRect &rect, int dy)
{
    //qDebug() << "\n--slotUpdateRequest updateLineNumberArea--x:" <<rect.x() << " y:" << rect.y() << " width:" << rect.width() << " height:" << rect.height() << " dy:"<< dy ;

    if(!m_bInit)
    {
        return;
    }

    updateLineNumberArea(rect, dy);
}

//不在同一行,在同一行,只要位置变都会触发;选中文字时位置也会变
void CodeEditor::slotCursorPositionChanged()
{
    qDebug() << "\n--slotCursorPositionChanged highlightCurrentLine" ;

    if(!m_bInit)
    {
        return;
    }

    highlightCurrentLine();
}

//当前行
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);
}

//绘制行号
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;
    }
}

代码说明:

1)实现方式:左边LineNumberArea+右边QPlainTextEdit

2)位置设置:

setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);//宽度变化了,会触发resize,从而设置行号的位置

3)信号说明:

CodeEditor::blockCountChanged://不在同一行,在同一行,只要位置变都会触发;选中文字时位置也会变

CodeEditor::cursorPositionChanged://不在同一行,在同一行,只要位置变都会触发;选中文字时位置也会变

CodeEditor::updateRequest信号: //光标闪动,文字变化,等,都会一直触发此

3.使用:

    //带行号的
    m_pnewEdit2 = new CodeEditor(this);
    m_pnewEdit2->setGeometry(360,10,341,331);
    m_pnewEdit2->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    m_pnewEdit2->setWordWrapMode(QTextOption::NoWrap);//不自动换行
    connect(m_pnewEdit2, &CodeEditor::textChanged, this, &Dialog::on_textEdit22_textChanged22);

    m_timerHighlight2.setInterval(100);
    connect(&m_timerHighlight2, &QTimer::timeout, this, &Dialog::slotTimeOutHighlight2);

void Dialog::on_pushButton_4_clicked()
{
    QString lefttext = ui->textEdit11->toPlainText();

    m_pnewEdit2->SetPainText(lefttext);

    HighlightContent2(true);



    m_bInit2 = true;

}

void Dialog::slotTimeOutHighlight2()
{
    m_timerHighlight2.stop();

    HighlightContent2(false);
}

4.高亮代码:

void Dialog::HighlightContent2(bool bWhole)
{
    //QString strTextIn = m_mytext;
    QString strTextIn = m_pnewEdit2->toPlainText();

    m_pnewEdit2->blockSignals(true);//处理期间不响应各种事件

    QTextDocument*textDocument= m_pnewEdit2->document();

    QTextCursor cursor = m_pnewEdit2->textCursor();
   // QTextCharFormat oldTextCharFormat =cursor.charFormat();
    //int nOldCursorPos = cursor.position();

    cursor.beginEditBlock();//等处理完了,再统一显示,处理卡问题

    int nLen = strTextIn.length();
    int nEnd = 0, nStart = 0;
    int nPos = m_pnewEdit2->verticalScrollBar()->value();

    QString strUpdate11;
    if (bWhole)
    {
        strUpdate11 = strTextIn;
    }
    else
    {
//        bool  bb = cursor.hasSelection();
//        QString ss = cursor.selectedText();
//        int aa1 = cursor.selectionStart();;
//        int aa2 =cursor.selectionEnd();



        //按光标所在的一行算
        int lineNumber = cursor.blockNumber();//获取光标所在列用cursor.columnNumber();
        QTextBlock textBlock = textDocument->findBlockByLineNumber(lineNumber);//通过行号找到指定行 数据块

        nStart = textBlock.position();//改行相对于最开头的开始位置
        strUpdate11 = textBlock.text();
    }


    std::wstring strUpdate = strUpdate11.toStdWString();

    //2.英文单词	3.汉字					4.+、-、*、/等符号位									6.字符串
    std::tr1::wregex pattern(L"(\\b(\\w+)\\b)|([\u4e00-\u9fa5\\w%]{1,})|([\\+\\-\\*\\=\\:\\;\\,\\/\\<\\>\\(\\)\\[\\]\\{\\}]+)|(['\"](.+?)['\"])");

    std::tr1::wsmatch result;
    std::wstring::const_iterator itB = strUpdate.begin();
    std::wstring::const_iterator itS = itB;
    std::wstring::const_iterator itE = strUpdate.end();
    QString strContent,word;

    while(regex_search(itS,itE,result,pattern))
    {
        word = QString::fromStdWString(std::wstring(result[0]).c_str());

        int wordType = -1;
        if (result[2].matched)	//英文单词
        {
            wordType = 2;
        }
        else if (result[3].matched)	//汉字
        {
            wordType = 3;
        }
        else if (result[4].matched)	//+、-、*、/等符号位
        {
            wordType = 4;
        }
        else if (result[6].matched)	//字符串
        {
            wordType = 6;
        }

        int nLen = word.length();
        if (nLen > 0)
        {
            int offset = static_cast<int>(std::distance(itB, result[0].first));
            int startPos = nStart + offset;
            if (wordType == 4)
            {
                setTextEditColor(cursor, startPos, startPos + nLen, QColor("#00C35F"));
            }
            //            else if (wordType == 6)
            //            {

            //            }
            else if (IsFunc(word))
            {
                setTextEditColor(cursor, startPos, startPos + nLen, QColor("#10B2F0"));
            }
            else if (IsParam(word))
            {
                setTextEditColor(cursor, startPos, startPos + nLen, QColor("#E6C145"));
            }
            // 变量暂时不需要着色
            //else if (IsVariable(word))
            //	SetTextFormat(startPos, startPos + nLen, m_charFormat[CF_RED]);
            else if (IsDigit(word))
            {
                setTextEditColor(cursor, startPos, startPos + nLen, QColor("#D12BD1"));
            }
            else //没有的要设置默认的颜色
            {
                setTextEditColor(cursor, startPos, startPos + nLen, QColor("#000000"));
            }

        }

        // 更新搜索起始位置,搜索剩下的字符串
        itS = result[0].second;
    }

//    cursor.setCharFormat(oldTextCharFormat);
//    cursor.setPosition(nOldCursorPos);
//    ui->textEdit11->setTextCursor(cursor);

    cursor.endEditBlock();

    m_pnewEdit2->blockSignals(false);


}

5.设置位置方法:

    QTextCursor cursor = ui->textEdit11->textCursor();
    cursor.setPosition(10, QTextCursor::MoveAnchor);
    ui->textEdit11->setTextCursor(cursor);
    ui->textEdit11->setFocus();

源码:QT实战-带行号的支持高亮的编辑器实现(1)

使用说明:

1)先把"text参考.txt"里面的内容复制到左边编辑框

2)然后点击第一个按钮

3)再点击第三个按钮

4)最后点击第4个按钮

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Matlab的卷积神经网络(CNN)苹果分级检测系统

本研究提出了一种基于卷积神经网络&#xff08;CNN&#xff09;的自动化苹果分级系统&#xff0c;该系统根据苹果的视觉特征进行分类。系统采用了预训练的深度学习模型&#xff0c;使用包含不同等级苹果的图像数据集进行训练。研究方法包括图像预处理、特征提取和苹果等级分类。…

华为、华三交换机纯Web下如何创关键VLANIF、操作STP参数

华为交换机WEB操作 使用的是真机S5735&#xff0c;目前主流的版本都适用&#xff08;V1R5~V2R1的就不在列了&#xff0c;版本太老了&#xff0c;界面完全不一样&#xff0c;这里调试线接的console口&#xff0c;电脑的网络接在ETH口&#xff09; 「模拟器、工具合集」复制整段内…

ACM:均分纸牌

主要思路 整体思路概述&#xff1a; 本题旨在解决给定N堆纸牌&#xff08;纸牌总数是N的倍数&#xff09;&#xff0c;通过按照特定移牌规则移动纸牌&#xff0c;找出用最少移动次数使每堆纸牌数量相等的方法。程序采用了一种逐步调整的思路&#xff0c;先计算出每堆纸牌应有的…

定时任务——xxl-job源码解析

摘要 本文深入解析了xxl-job的源码&#xff0c;xxl-job是一个分布式任务调度平台&#xff0c;其核心设计思想是将调度行为抽象成“调度中心”&#xff0c;而任务逻辑则由“执行器”处理&#xff0c;实现调度与任务的解耦。文章详细介绍了调度器和执行器的初始化流程、任务执行…

vxe-table 键盘操作,设置按键编辑方式,支持覆盖方式与追加方式

vxe-table 全键盘操作&#xff0c;按键编辑方式设置&#xff0c;覆盖方式与追加方式&#xff1b; 通过 keyboard-config.editMode 设置按键编辑方式&#xff1b;支持覆盖方式编辑和追加方式编辑 安装 npm install vxe-pc-ui4.3.15 vxe-table4.9.15// ... import VxeUI from v…

乾元通渠道商中标福州市人防信息化建设项目

乾元通渠道商中标福州市人防信息化建设项目&#xff0c;乾元通作为应急通讯设备厂家&#xff0c;为项目提供车载版多链路聚合通信保障设备 QYT-X1s。 青岛乾元通数码科技有限公司作为国家应急产业企业&#xff0c;深耕于数据调度算法研究&#xff0c;参与了多项国家及省部级信息…

【深度学习|地学应用-地震气溶胶异常解析3】气溶胶异常是地震的前兆现象之一!地震是如何影响气溶胶浓度和分布的异常变化的呢,我们该如何分析?

【深度学习|地学应用-地震气溶胶异常解析3】气溶胶异常是地震的前兆现象之一&#xff01;地震是如何影响气溶胶浓度和分布的异常变化的呢&#xff0c;我们该如何分析&#xff1f; 【深度学习|地学应用-地震气溶胶异常解析3】气溶胶异常是地震的前兆现象之一&#xff01;地震是…

C++析构函数和构造函数

一、构造函数 1.构造函数的基本概念 1.对构造函数的理解&#xff1a; 构造函数是类的一种特殊成员函数&#xff0c;其主要功能是在创建对象时进行初始化操作。它的名字与类名相同&#xff0c;并且没有返回值类型&#xff08;不能是void&#xff09;。例如&#xff0c;对于一个…

【python自动化四】日志打印

我们在进行自动化测试时&#xff0c;需要打印过程日志和结果日志等&#xff0c;这里记录下日志的相关配置。这里我们直接自己新建一个logger。 先贴上日志代码如下&#xff0c;可根据需要修改&#xff1a; import logging import os import timefrom logging.handlers import …

鸿蒙分享(一):添加模块,修改app名称图标

码仓库&#xff1a;https://gitee.com/linguanzhong/share_harmonyos 鸿蒙api:12 新建公共模块common 在entry的oh-package.json5添加dependencies&#xff0c;引入common模块 "dependencies": {"common": "file:../common" } 修改app名称&…

IDE如何安装插件实现Go to Definition

项目背景 框架&#xff1a;Cucumber Cypress 语言&#xff1a;Javascript IDE&#xff1a;vscode 需求 项目根目录cypress-automation的cypress/integration是测试用例的存放路径&#xff0c;按照不同模块不同功能创建了很多子目录&#xff0c;cucumber测试用例.feature文…

【机器学习】CatBoost 模型实践:回归与分类的全流程解析

一. 引言 本篇博客首发于掘金 https://juejin.cn/post/7441027173430018067。 PS&#xff1a;转载自己的文章也算原创吧。 在机器学习领域&#xff0c;CatBoost 是一款强大的梯度提升框架&#xff0c;特别适合处理带有类别特征的数据。本篇博客以脱敏后的保险数据集为例&#x…

HTML Input 文件上传功能全解析:从基础到优化

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Unity在运行状态下,当物体Mesh网格发生变化时,如何让MeshCollider碰撞体也随之实时同步变化?

旧版源代码地址&#xff1a;https://download.csdn.net/download/qq_41603955/90087225?spm1001.2014.3001.5501 旧版效果展示&#xff1a; 新版加上MeshCollider后的效果&#xff1a; 注意&#xff1a;在Unity中&#xff0c;当你动态地更改物体的Mesh时&#xff0c;通常期望…

conda create -n name python=x.x 执行失败问题解决方法

今天想在anaconda环境下创建一个指定python版本为3.9的虚拟环境&#xff0c;执行命令 conda create -n DeepLearning python3.9 但是系统竟然报错 看报错信息是在镜像源里找不到下载包&#xff0c;于是对镜像源文件处理 首先删除之前的镜像通道 conda config --remove-key …

第一个 JSP 程序

一个简单的 JSP 程序&#xff1a; 使用 IDEA 开发工具新建一个 maven 项目&#xff0c;具体操作如图所示&#xff1a; 配置 Tomcat 服务器 项目结构如下图所示&#xff1a; 3. 修改 index.jsp 页面的代码&#xff1a; <% page language"java" contentType&q…

Altium Designer学习笔记 32 DRC检查_丝印调整

基于Altium Designer 23学习版&#xff0c;四层板智能小车PCB 更多AD学习笔记&#xff1a;Altium Designer学习笔记 1-5 工程创建_元件库创建Altium Designer学习笔记 6-10 异性元件库创建_原理图绘制Altium Designer学习笔记 11-15 原理图的封装 编译 检查 _PCB封装库的创建Al…

docker学习笔记(五)--docker-compose

文章目录 常用命令docker-compose是什么yml配置指令详解versionservicesimagebuildcommandportsvolumesdepends_on docker-compose.yml文件编写 常用命令 命令说明docker-compose up启动所有docker-compose服务&#xff0c;通常加上-d选项&#xff0c;让其运行在后台docker-co…

不同类型的集成技术——Bagging、Boosting、Stacking、Voting、Blending简述

目录 一、说明 二、堆叠 2.1 堆叠的工作原理&#xff1a; 2.2 例子&#xff1a; 2.3 堆叠的优点&#xff1a; 三、投票&#xff08;简单投票&#xff09; 3.1 例子&#xff1a; 3.2 投票的优点&#xff1a; 四、装袋和投票之间的区别 五、混合 6.1 混合的主要特征&#xff1a; …

ONES 功能上新|ONES Project 甘特图再度升级

ONES Project 甘特图支持展示工作项标题、进度百分比、依赖关系延迟时间等信息。 应用场景&#xff1a; 在使用甘特图规划项目任务、编排项目计划时&#xff0c;可以对甘特图区域进行配置&#xff0c;展示工作项的工作项标题、进度百分比以及依赖关系延迟时间等维度&#xff0c…