Qt 绘图QPainter < 一 >

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. 设置画笔和画刷:

可以通过 QPenQBrush 来设置画笔和画刷的属性,如颜色、线宽、样式等。

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 派生类上进行绘制。
  • 20
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
画出GraphItem类的UML类图: #ifndef GRAPHITEM_H #define GRAPHITEM_H #include <QGraphicsItem> #include <QVector> #include <QPointF> #include <QtMath> #include <QTimer> #include <QPaintEvent> #include <QPushButton> #include "mainwindow.h" #include <QObject> class MainWindow; // 前向声明 class GraphItem : public QGraphicsItem { public: //构造函数,接受带权无向图临界矩阵adjMatrix和一个parent GraphItem(const QVector<QVector<int>> &adjMatrix, const QVector<int> &shortestPath, QGraphicsItem *parent = nullptr); //纯虚函数,在.cpp中重新编写以实现图形项的边界框绘制 QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; QVector<QPointF> m_nodePositions;//存储节点的位置信息 QVector<int> m_shortestPath; // 最短路径 QVector<int> m_userCity; QVector<int> m_userSchool; bool m_drawArrow; // 是否需要绘制箭头 bool m_draw1; bool m_draw2; bool m_draw3; private: MainWindow * m_mainWindow; // 指向MainWindow对象的指针 QVector<QVector<int>> m_adjMatrix;//存储带权无向图的邻接矩阵 QPointF startPoint; QPointF endPoint; QPainter * m_painter; QPainter * m_drawNodes; void initializeNodePositions();//初始化节点位置信息 void drawEdges(QPainter * painter);//用于绘制边 void drawNodes1(QPainter * painter);//用于绘制节点 void drawNodes2(QPainter * painter);//用于绘制节点 void drawNodes3(QPainter * painter);//用于绘制节点 void paintArrow(QPainter * painter); }; #endif // GRAPHITEM_H
07-14
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值