> 文章列表 > 【Qt笔记】5.QWidget源码查阅

【Qt笔记】5.QWidget源码查阅

【Qt笔记】5.QWidget源码查阅

文章目录

  • 1 概述
  • 2 相关成员函数详解
    • 2.1 构造函数
    • 2.2 设置尺寸
    • 2.3 槽函数

1 概述

QWidget类是所有用户界面对象的基类。从QObject和QPaintDevice里继承过来

class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice

由上可以看出qt是把其封装成dll供外部接口调用。
我们在实际项目中使用QWidget会发现其调用到的头文件都是编译器的
形式如下:
D:\\QT\\5.14.2\\mingw73_32\\include\\QtWidgets\\qwidget.h

其实际的源码位置如下路径
D:\\QT\\5.14.2\\Src\\qtbase\\src\\widgets\\kernel\\qwidget.cpp

其中涉及的相关的文件有如下几个:

D:\\QT\\5.14.2\\Src\\qtbase\\src\\widgets\\kernel\\qtwidgetsglobal_p.h
D:\\QT\\5.14.2\\Src\\qtbase\\src\\widgets\\kernel\\qtwidgetsglobal.h
D:\\QT\\5.14.2\\Src\\qtbase\\src\\widgets\\kernel\\qwidget.cpp
D:\\QT\\5.14.2\\Src\\qtbase\\src\\widgets\\kernel\\qwidget_p.h
D:\\QT\\5.14.2\\Src\\qtbase\\src\\widgets\\kernel\\qwidget.h

【Qt笔记】5.QWidget源码查阅

2 相关成员函数详解

2.1 构造函数

看一个类我们大致都会从其构造函数出发。

QWidget::QWidget(QWidget *parent, Qt::WindowFlags f): QObject(*new QWidgetPrivate, 0), QPaintDevice()
{QT_TRY {d_func()->init(parent, f);} QT_CATCH(...) {QWidgetExceptionCleaner::cleanup(this, d_func());QT_RETHROW;}
}

这个代码有做异常处理.我们直接看init的操作即可。
init中传入父类的指针,并且传进去Qt::WindowFlags
该WindowFlags相关值如下: 可以直接看Qt助手里的描述
qt助手路径如下:
D:\\QT\\5.14.2\\mingw73_32\\bin\\assistant.exe

Value Description
Qt::Widget 是一个窗口或部件,有父窗口就是部件,没有就是窗口
Qt::Window 是一个窗口,有窗口边框和标题
Qt::Dialog 是一个对话框窗口
Qt::Sheet 是一个窗口或部件Macintosh表单
Qt::Drawer 是一个窗口或部件Macintosh抽屉,去掉窗口左上角的图标
Qt::Popup 是一个弹出式顶层窗口
Qt::Tool 是一个工具窗口
Qt::ToolTip 是一个提示窗口,没有标题栏和窗口边框
Qt::SplashScreen 是一个欢迎窗口,是QSplashScreen构造函数的默认值
Qt::Desktop 是一个桌面窗口或部件
Qt::SubWindow 是一个子窗口

init中会直接调用到

void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)

QWidget中的一些操作都是间接通过QWidgetPrivate去操作,去耦做的非常的规范.

在init中首先会创建QCoreApplication的instance

    if (Q_UNLIKELY(!qobject_cast<QApplication *>(QCoreApplication::instance())))qFatal("QWidget: Cannot create a QWidget without QApplication");

父类中插入

    Q_ASSERT(allWidgets);if (allWidgets)allWidgets->insert(q);int targetScreen = -1;if (parentWidget && parentWidget->windowType() == Qt::Desktop) {const QDesktopScreenWidget *sw = qobject_cast<const QDesktopScreenWidget *>(parentWidget);targetScreen = sw ? sw->screenNumber() : 0;parentWidget = 0;}

这是allWidgets的声明
QWidgetSet *QWidgetPrivate::allWidgets = 0; // widgets with no wid
操作完父类的一些赋值和插入后,需要设置一些相关的属性并传递相关事件

setAttribute()

分发事件

    QEvent e(QEvent::Create);QCoreApplication::sendEvent(q, &e);QCoreApplication::postEvent(q, new QEvent(QEvent::PolishRequest));extraPaintEngine = 0;

2.2 设置尺寸

最小尺寸获取

QSize QWidget::minimumSize() const
{Q_D(const QWidget);return d->extra ? QSize(d->extra->minw, d->extra->minh) : QSize(0, 0);
}

最大尺寸的获取

QSize QWidget::maximumSize() const
{Q_D(const QWidget);return d->extra ? QSize(d->extra->maxw, d->extra->maxh): QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
}

设置固定的尺寸,最大最小尺寸设置都是其中的一部分。

void QWidget::setFixedSize(int w, int h)
{Q_D(QWidget);bool minSizeSet = d->setMinimumSize_helper(w, h);bool maxSizeSet = d->setMaximumSize_helper(w, h);if (!minSizeSet && !maxSizeSet)return;if (isWindow())d->setConstraints_sys();elsed->updateGeometry_helper(true);if (w != QWIDGETSIZE_MAX || h != QWIDGETSIZE_MAX)resize(w, h);
}

2.3 槽函数

仅仅举例关闭的槽函数

bool QWidget::close()
{return d_func()->close_helper(QWidgetPrivate::CloseWithEvent);
}

关闭的时候需要把相关的事件分发下去

   if (mode == CloseWithSpontaneousEvent)QApplication::sendSpontaneousEvent(q, &e);elseQCoreApplication::sendEvent(q, &e);...
//最后通过QCoreApplicationPrivate中的方法去销毁实例QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));applicationPrivate->maybeQuit();
...
//在其使用完后,正确设置相关的关闭属性,并销毁相关的对象if (!that.isNull()) {data.is_closing = 0;if (q->testAttribute(Qt::WA_DeleteOnClose)) {q->setAttribute(Qt::WA_DeleteOnClose, false);q->deleteLater();}}            

公共槽函数有如下:
在这里插入图片描述
同时QWidget提供了如下Signals,从名字可以看出其相关的发射情况

void customContextMenuRequested(const QPoint &pos)
void windowIconChanged(const QIcon &icon)
void windowTitleChanged(const QString &title)

而bool QWidget::event(QEvent *event)用来处理鼠标按建等其他相关事件的处理。