Qt 绘图QPainter < 一 >
文章目录
学习QPainter之前先了解下它的搭档paintEvent;
paintEvent
是 Qt 中用于处理绘图事件的一个函数。每当需要重绘一个窗口部件时,paintEvent
就会被调用,允许程序员在窗口部件上进行绘图操作。这个函数是在 Qt 中用于自定义绘图的关键部分之一。
paintEvent
1. 何时调用 paintEvent
:
-
首次显示窗口部件:当窗口部件首次显示时,
paintEvent
会被调用以进行初始的绘图。 -
窗口尺寸变化:当窗口的尺寸发生变化时,
paintEvent
也会被调用,以便调整绘制的内容。 -
窗口部件被覆盖:当一个窗口部件被其他窗口部件或者系统窗口覆盖,再次可见时,
paintEvent
也会被调用。 -
手动触发:可以通过
repaint()
函数手动触发paintEvent
的调用。
2. paintEvent
的函数签名:
paintEvent
函数的典型签名如下:
void QWidget::paintEvent(QPaintEvent *event);
QPaintEvent
参数提供了关于绘图的信息,例如哪个部分需要被重新绘制等。
3. 使用 paintEvent
进行绘图:
在 paintEvent
函数中,可以使用 QPainter
对象进行绘图操作。通常,会在 paintEvent
函数内创建一个 QPainter
对象,然后使用该对象进行绘图。(QPainter部分有更详细内容)
void MyWidget::paintEvent(QPaintEvent *event) {
// 创建 QPainter 对象
QPainter painter(this);
// 绘图操作
painter.drawText(10, 10, "Hello, Qt!");
painter.drawLine(20, 20, 100, 100);
// 其他绘图操作...
}
4. 避免直接调用 paintEvent
:
通常情况下,不直接调用 paintEvent
函数。相反,可以使用 QWidget
类的 repaint()
函数来请求重绘,然后由 Qt 框架负责调用 paintEvent
。
myWidget->repaint();
5. 绘图优化:
-
只绘制需要的区域:通过
event->rect()
获取需要重绘的区域,只绘制这部分区域,避免全局重绘。 -
避免频繁的绘图:只有在需要时才进行绘图,而不是频繁地重复相同的绘图操作。
-
使用双缓冲:可以使用双缓冲技术来避免绘图时的闪烁问题,即先在一个缓冲区绘制,然后一次性将其绘制到窗口上。
1. 只绘制需要的区域:
在 paintEvent
函数中,event->rect()
返回了需要被重绘的区域,即窗口上发生变化的部分。通过利用这个信息,可以只绘制这部分区域,而不是整个窗口,从而提高绘图的效率。
void MyWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
// 只绘制需要重绘的区域
QRect dirtyRect = event->rect();
painter.drawText(dirtyRect, Qt::AlignCenter, "Hello, Qt!");
// 其他绘图操作...
}
这样做的好处是减小了绘图的范围,避免了不必要的计算和绘图操作,提高了绘图的效率。
2. 避免频繁的绘图:
频繁地进行绘图操作可能会导致性能下降,尤其是在绘制复杂图形或大量元素时。为了避免这种情况,可以选择在需要时才进行绘图,而不是在每个事件周期都进行。
通常,重绘可以通过调用 repaint()
来触发,如果在处理事件的过程中需要多次进行绘图,可以通过设置一个标志来控制绘图的时机,避免不必要的绘图。
// 在需要时触发重绘
void MyWidget::someEvent() {
// 其他操作...
update(); // 触发重绘
}
3. 使用双缓冲:
双缓冲技术是为了解决绘图时可能出现的闪烁问题。在绘制复杂图形时,由于图形是一步一步绘制的,可能会在绘制的过程中看到不完整或者闪烁的图形。
使用双缓冲技术,可以先在一个离屏的缓冲区进行绘制,然后一次性将整个缓冲区的内容绘制到屏幕上,从而避免了中间绘图的可见性。
void MyWidget::paintEvent(QPaintEvent *event) {
// 创建离屏缓冲区
QPixmap pixmap(size());
pixmap.fill(Qt::white);
// 在缓冲区上进行绘制
QPainter painter(&pixmap);
painter.drawText(rect(), Qt::AlignCenter, "Hello, Qt!");
// 将缓冲区内容绘制到窗口上
QPainter widgetPainter(this);
widgetPainter.drawPixmap(0, 0, pixmap);
}
这样做的好处是用户将在整个绘图过程中看到一个完整的图形,避免了闪烁问题。
综合来说,这些绘图优化技术可以结合使用,根据具体的应用场景选择适当的优化方法,以提高绘图性能和用户体验。
6. 示例:
下面是一个简单的 paintEvent
的示例:
void MyWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
QFont font("Arial", 12);
painter.setFont(font);
painter.drawText(10, 30, "Hello, Qt!");
QPen pen(Qt::red, 2, Qt::DashLine);
painter.setPen(pen);
painter.drawRect(50, 50, 50, 50);
}
在这个例子中,paintEvent
被用于在窗口上绘制文本和矩形。这是一个简单的用法,但可以根据需要进行更复杂的绘图操作。
总体而言,paintEvent
是实现自定义绘图逻辑的关键函数,它允许在窗口或其他 QWidget
派生类上进行灵活的绘图。
QPainter
QPainter
是 Qt 框架中用于进行2D绘图的类。它提供了一系列用于在 QWidget
或其他画布上进行绘制的方法,可以绘制图形、文本、图像等。QPainter
类通常与 paintEvent
事件处理函数一起使用,用于在窗口或其他继承自 QWidget
的类上绘制内容。
以下是关于 QPainter
的一些基本概念和用法:
1. QPainter
的基本用法:
void MyWidget::paintEvent(QPaintEvent *event) {
// 创建一个QPainter对象,用于在当前窗口上进行绘制
QPainter painter(this);
// 绘制文本
painter.drawText(10, 10, "Hello, Qt!");
// 绘制直线
painter.drawLine(20, 20, 100, 100);
// 绘制矩形
painter.drawRect(50, 50, 50, 50);
}
在上面的例子中,paintEvent
函数被调用时创建了一个 QPainter
对象,并使用该对象进行了一些基本的绘制操作。
2. 绘制基本形状:
QPainter
提供了许多用于绘制基本形状的方法,如:
drawPoint
:绘制一个点。drawLine
:绘制一条直线。drawRect
:绘制矩形。drawEllipse
:绘制椭圆。drawPolygon
:绘制多边形。
void MyWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.drawPoint(30, 30);
painter.drawLine(20, 20, 100, 100);
painter.drawRect(50, 50, 50, 50);
painter.drawEllipse(100, 100, 80, 60);
QPolygon polygon;
polygon << QPoint(200, 200) << QPoint(250, 250) << QPoint(200, 300);
painter.drawPolygon(polygon);
}
3. 绘制文本:
void MyWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
QFont font("Arial", 12);
painter.setFont(font);
painter.drawText(10, 30, "Hello, Qt!");
}
4. 绘制图像:
void MyWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
QImage image("path/to/image.png");
painter.drawImage(10, 10, image);
}
5. 绘制路径:
void MyWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
QPainterPath path;
path.moveTo(20, 20);
path.lineTo(100, 100);
path.cubicTo(200, 100, 200, 200, 100, 200);
painter.drawPath(path);
}
6. 设置画笔和画刷:
可以通过 QPen
和 QBrush
来设置画笔和画刷的属性,如颜色、线宽、样式等。
void MyWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
QPen pen(Qt::red, 2, Qt::DashLine);
painter.setPen(pen);
QBrush brush(Qt::green, Qt::CrossPattern);
painter.setBrush(brush);
painter.drawRect(50, 50, 50, 50);
}
7. 绘图的优先级和覆盖:
绘图的优先级是由窗口部件的堆叠顺序(Z-order)决定的。在 Qt 中,后创建的部件会覆盖先创建的部件,因此处于上层的部件会遮挡位于下层的部件。这与部件的添加顺序有关,后添加的部件通常会在上层。
如果需要改变绘图的顺序,可以使用 stackUnder()
或 stackOver()
等函数来调整部件的堆叠顺序。
在Qt中,默认情况下,paintEvent
的绘制位于部件的底层。这是因为在默认情况下,paintEvent
是在QWidget
的基础上直接绘制的,所以它位于部件的底层。
如果在paintEvent
中绘制了一些内容,而且这个QWidget
上还有其他子部件,那么这些子部件通常会显示在paintEvent
绘制的内容的上方。这是因为子部件是在paintEvent
之后绘制的,处于堆叠顺序的上层。
如果需要在绘图时确保paintEvent
的绘制内容位于最上层,可以使用 raise()
函数将当前的部件移到最顶层。例如:
void MyWidget::paintEvent(QPaintEvent *event) {
// 在绘图事件中绘制一些内容
QPainter painter(this);
painter.drawText(10, 10, "Hello, Qt from paintEvent!");
// 将当前部件移到最顶层
raise();
}
在这个例子中,raise()
函数会将当前的QWidget
(即this
指针所指向的窗口)移到最顶层,确保它在堆叠顺序中的位置最高,即最上层。
总结:更多内容见 < 二 >;
QPainter
提供了丰富的方法用于在 Qt 应用程序中进行绘图操作。- 它可以用于绘制基本形状、文本、图像等。
- 可以设置画笔和画刷的属性来调整绘制的样式。
QPainter
经常与paintEvent
事件处理函数一起使用,用于在窗口或其他QWidget
派生类上进行绘制。