我们会发现这些编辑器控件,都是继承自 QAbstractScrollArea 类,比如 QPlainTextEdit,大名鼎鼎的 QsciScintilla 编辑器控件,小熊猫IDE的 SynEdit 编辑器控件等。
QAbstractScrollArea是提供一个可以滚动的窗口,里面可以容纳很多子控件。
那就是我们的子类需要重新实现 paintEvent 事件函数。
void paintEvent(QPaintEvent *event) override;
这个函数里面需要我们自己定义 QPainter 对象去执行具体的绘制工作,过程如下:
painter->fillRect(AClip,edit->mGutter.color()); 填充一个矩形,应该是为了设置背景色
painter->setFont(edit->mGutter.font()); 设置绘制文本的字体
painter->setPen(edit->mGutter.activeLineTextColor()); 设置画笔的颜色
painter->drawText(string) 绘制出这些文本了
同理,画其它区域也是如此,比如画编辑器的边缘margin(有的编辑器也叫做 Gutter),比如显示箭头,断点,行号等。也是通过绘制实现的,而不是直接搞个QWiget并排放置在那儿。具体过程机制如下:
通过在编辑器内里,创建两个专门管理不同区域坐标的对象(注意:这些对象不是继承自QWidget,因为它们仅仅是用于管理不同区域的坐标范围信息,比如长宽等),比如小熊猫IDE的 SynEdit 编辑器类里就有成员:
SynGutter mGutter; 其中继承关系【 class SynGutter : public QObject 】
在绘制的时候,就通过这些对象来实现分别控制绘制的动作了,比如哪些地方该绘制矩形,哪些地方该绘制指定的图片,哪些地方该绘制文本。
所以,一整个编辑器控件,只是一个QWidget,而不是说margins(或者叫做gutter栏,例如行号栏)是一个并排放置的QWidget(当然自制编辑器网上也有人这么干的,行号栏等位置就是放一个qwidget,比如qtcreator的示例项目,还有有人搞的一个QCodeEditor,这两个项目就是这样的,本文结尾会介绍一下这个编辑器)。
因此,当我们在编辑器中鼠标右键时,我们发现 contextMenuEvent(QContextMenuEvent *event) 函数总是能得到触发,而不管我们右键在行号栏还是文本显示区。但是我们可能希望右键在行号栏,文本显示区时候能区分出来,怎么做呢?只需要判断event->pos的和margin的区域坐标的关系,就能知道有没有右键在margin区了,从而显示不同的菜单。大家可以看我这个博客,对上述两个编辑器的分析 QsciScintilla等编辑器实现不同区域鼠标右键处理方式不同的方法_标biao的博客-CSDN博客
void drawPoint(const QPointF &pt); 画点函数 void drawLine(const QLineF &line); 画线函数 void drawRect(const QRectF &rect); 画矩形 drawPixmap 画图片 void drawText(const QPointF &p, const QString &s); 画文本 ...... 等
1. qtcreator的欢迎页面,搜索一下,就有这个示例工程,左侧行号栏就是一个单独的qwidget。可以参考一下 Code Editor无能为力一天_素默的博客-CSDN博客_codeeditor
2. 网上有人做了个QCodeEditor类的编辑器(注:这不是qt官方库有的,但是我估计参考了qtcreator源码中的编辑器部分),也挺好看的,但是功能还是太少了,比如自动折叠功能等都不具备的,而且缩放时候,明显卡顿。