我们会发现这些编辑器控件,都是继承自 QAbstractScrollArea 类,比如 QPlainTextEdit,大名鼎鼎的 QsciScintilla 编辑器控件,小熊猫IDE的 SynEdit 编辑器控件等。
QAbstractScrollArea是提供一个可以滚动的窗口,里面可以容纳很多子控件。
文本如何实现显示的呢?
那就是我们的子类需要重新实现 paintEvent 事件函数。
void paintEvent(QPaintEvent *event) override;
这个函数里面需要我们自己定义 QPainter 对象去执行具体的绘制工作,过程如下:
- 定义一个 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(当然自制编辑器网上也有人这么干的)。
因此,当我们在编辑器中鼠标右键时,我们发现 contextMenuEvent(QContextMenuEvent *event) 函数总是能得到触发,而不管我们右键在行号栏还是文本显示区。但是我们可能希望右键在行号栏,文本显示区时候能区分出来,怎么做呢?只需要判断event->pos的和margin的区域坐标的关系,就能知道有没有右键在margin区了,从而显示不同的菜单。大家可以看我这个博客,对上述两个编辑器的分析 QsciScintilla等编辑器实现不同区域鼠标右键处理方式不同的方法_标biao的博客-CSDN博客
附录:QPainter类有哪些函数呢?
void drawPoint(const QPointF &pt); 画点函数 void drawLine(const QLineF &line); 画线函数 void drawRect(const QRectF &rect); 画矩形 drawPixmap 画图片 void drawText(const QPointF &p, const QString &s); 画文本 ...... 等