Qt绘图之QWidget 您所在的位置:网站首页 qt截图子widget Qt绘图之QWidget

Qt绘图之QWidget

2023-07-17 05:04| 来源: 网络整理| 查看: 265

一、概述

我们知道当一个QWidget以另外一个QWidget作为父对象时,显示父对象会自动显示子对象,今天就对其实现过程做个简单分析。

二、测试源码 subwidget.h #ifndef SUBWIDGET_H #define SUBWIDGET_H #include #include #include #include #include class SubWidget : public QWidget { Q_OBJECT public: explicit SubWidget(QWidget *parent = nullptr); void paintEvent(QPaintEvent* event); QSize sizeHint() const { return QSize(400, 400); } void moveEvent(QMoveEvent *event) { qDebug() } void SubWidget::paintEvent(QPaintEvent* event) { QPainter painter(this); QPen pen; pen.setColor(Qt::blue); painter.setPen(pen); painter.drawText(10, 100, "This is subWidget"); } widget.h #ifndef WIDGET_H #define WIDGET_H #include #include #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); void paintEvent(QPaintEvent* event); QSize sizeHint() const { return QSize(400, 400); } }; #endif // WIDGET_H widget.cpp #include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { } Widget::~Widget() { } void Widget::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.drawText(50, 50, "This is widget"); } main.cpp #include "widget.h" #include "subwidget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; SubWidget subWidget(&w); w.show(); return a.exec(); } 三、分析父对象绘制同时其对象也会绘制情景

SubWidget 是Widget 的子对象,Widget 绘制的时候会同时绘制SubWidget ,以下是其调用堆栈: 在这里插入图片描述 从上图中可以看出,25 QWindowsContext::windowsProc会收到QtWindows::ExposeEvent事件,然后其启动对窗口进行绘制。绘制过程通过绘制事件进行驱动。QWidgetPrivate::drawWidget会绘制QWidget(最终调用paintEvent),如果QWidget有子对象,则其会通过QWidgetPrivate::drawWidget中的QWidgetPrivate::paintSiblingsRecursive嵌套调用子对象的QWidgetPrivate::drawWidget,这样就完成了各个子对象的绘制与显示。

QWidgetPrivate::drawWidget void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags, QPainter *sharedPainter, QWidgetBackingStore *backingStore) { ... if (recursive && !children.isEmpty()) { paintSiblingsRecursive(pdev, children, children.size() - 1, rgn, offset, flag & ~DrawAsRoot, sharePainter, backingStore); } } QWidgetPrivate::paintSiblingsRecursive void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& siblings, int index, const QRegion &rgn, const QPoint &offset, int flags, QPainter *sharedPainter, QWidgetBackingStore *backingStore) { ... // 如果还有兄弟对象,则调用paintSiblingsRecursive处理兄弟对象,也就是说先加入父对象的子对象 // 会先进行绘制。 如果没有兄弟对象了或者调用返回了,则调用wd->drawWidget绘制子对象。 if (index > 0) { paintSiblingsRecursive(pdev, siblings, --index, wr, offset, flag, sharePainter, backingStore); } ... // 绘制子对象,,wd是QWidgetPrivate类型的对象。 wd->drawWidget(pdev, wRegion, offset + widgetPos, flags, sharePainter, backingStore); ... } 四、分析父对象设置layout影响子对象布局的情景 修改main.cpp #include "widget.h" #include "subwidget.h" #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; QHBoxLayout layout(&w); SubWidget sw1(&w); SubWidget sw2(&w); layout.addWidget(&sw1); layout.addWidget(&sw2); w.show(); return a.exec(); } 调试 第一次layout

w.show() ==> QWidget::setVisible ==> QLayout::activate> ==> QLayoutPrivate::doResize ==> QBoxLayout::setGeometry ==> QWidgetItem::setGeometry ==> QWidget::setGeometry

第二次根据父对象空间调整子对象的layout

w.show() ==> QWidget::setVisible ==> QWidgetPrivate::show_helper> ==> QWidgetPrivate::sendPendingMoveAndResizeEvents ==> QCoreApplication::sendEvent ==> QApplicationPrivate::notify_helper ==> QLayout::widgetEvent ==> QLayoutPrivate::doResize ==> QBoxLayout::setGeometry ==> QWidgetItem::setGeometry ==> QWidget::setGeometry

void QWidget::setVisible(bool visible) { ... // QWidget上有layout则会调用此,进行第一次布局计算 if (d->layout) d->layout->activate(); ... if (isWindow() || parentWidget()->isVisible()) { d->show_helper(); ... } ... } void QWidgetPrivate::show_helper() { ... sendPendingMoveAndResizeEvents(); ... } void QWidgetPrivate::sendPendingMoveAndResizeEvents(bool recursive, bool disableUpdates) { ... // QWidget 有移动QWidget窗口位置事件,则发送事件 if (q->testAttribute(Qt::WA_PendingMoveEvent)) { QMoveEvent e(data.crect.topLeft(), data.crect.topLeft()); QApplication::sendEvent(q, &e); q->setAttribute(Qt::WA_PendingMoveEvent, false); } // QWidget 有调整QWidget窗口大小事件,则发送事件 if (q->testAttribute(Qt::WA_PendingResizeEvent)) { QResizeEvent e(data.crect.topLeft(), QSize()); QApplication::sendEvent(q, &e); q->setAttribute(Qt::WA_PendingResizeEvent, false); } ... // 调整子QWidget窗口的位置和大小 for (int i = 0; i ... // QWidget 上有layout则把事件发送到layout中进行处理 if (QLayout *layout = widget->d_func()->layout) { layout->widgetEvent(e); } ... } void QLayout::widgetEvent(QEvent *e) { ... switch (e->type()) { case QEvent::Resize: if (d->activated) { QResizeEvent *r = (QResizeEvent *)e; d->doResize(r->size()); } else { activate(); } break; case QEvent::ChildRemoved: ... break; case QEvent::LayoutRequest: if (static_cast(parent())->isVisible()) activate(); break; default: break; } } void QBoxLayout::setGeometry(const QRect &r) { ... ... }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有