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();
使用说明:
1)先把"text参考.txt"里面的内容复制到左边编辑框
2)然后点击第一个按钮
3)再点击第三个按钮
4)最后点击第4个按钮
原文地址:https://blog.csdn.net/wangkui1331/article/details/144312851
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!