做网站郑州,敬请期待前面一句,网站建设手机登录密码是什么啊,网站做动态和静态哪个贵很可惜#xff0c;qt的几个编辑框并没有相关功能。所以我们要自己实现一个。
先讲讲原理#xff1a; QPlainTextEdit继承自QAbstractScrollArea#xff0c;编辑发生在其viewport#xff08;#xff09;的边距内。我们可以通过将视口的左边缘设置一个空白区域#xff0c;…
很可惜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继承QPlainTextEditLineNumberArea是他的私有成员变量。
此外我们还要增加几个方法用于计算左侧行号的渲染绘制的空白区域大小。
详见代码
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()
{QListQTextEdit::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