自学内容网 自学内容网

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个按钮


原文地址:https://blog.csdn.net/wangkui1331/article/details/144312851

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!