qwidget.cpp所在路径:D:\Qt\Qt5.9.9\5.9.9\Src\qtbase\src\widgets\kernel\qwidget.cpp
本文重点:如何理解下面这段代码?
一、类的继承和派生
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
Widget::Widget(QWidget *parent) : QWidget(parent)
{
}
Widget::~Widget()
{
}
首先,我们可以从QT的页面看出:Widget是自定义的派生类,QWidget是基类。
我们再来看QT的基类QWidget的定义。注意QWidget的构造函数是public属性,且是有2个参数的默认构造函数。注意,这里的构造函数 QWidget() ,被public关键字修饰,才能够在类外被调用。
派生类构造函数的一般形式为:
派生类构造函数名(总参数表):基类构造函数名(参数表)
{
派生类中新增加数据成员初始化语句
}
派生类的构造函数,Widget()
在类内声明,类外定义,且是public属性:
// 类内声明,类外实现
Widget(QWidget *parent = nullptr); // parent是形参变量
Widget::Widget(QWidget *parent) : QWidget(parent) // 冒号“:”后面部分是在调用基类的构造函数,parent是实参。
{
//对派生类新增的数据成员进行初始化
}
其中 parent 只是函数的形参,而不是QWidget基类的成员属性(Properties)。我们从构造函数的类外定义可以看出,Widget()构造函数的形参变量 parent 会成为实参被传入QWidget()
构造函数中。注意,QWidget(parent)
不是定义基类的构造函数,而是调用基类的构造函数。
额外补充:
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;
}
}
这里 parent 的作用是设置父窗口,构造函数中默认为0,即没有父窗口,是顶级窗口。如果指定parent值,则当前窗体将会是父窗口的一个子部件。
在构造派生类对象时,需要对基类的成员变量和新增成员变量初始化。基类的构造函数并没有继承下来,派生类对于很多基类成员对象是不能够直接访问的,因此需要调用基类的构造函数,才能完成对基类成员变量的初始化工作。
二、一个其它相似的例子
1 下方代码定义了一个基类Base,并且有两个构造函数,一个是默认构造函数,一个是有一个整型参数的构造函数,一个私有变量。
class Base
{
public:
Base() :m_a(0) {
cout << "this is Base()" << endl;
}
Base(int val) :m_a(val) {
cout << "this is Base(int val)" << endl;
}
public:
int m_a;
};
2 下方代码定义了一个BaseChild类,并继承Base类,同样的,它也定义了两个构造函数,一个默认,一个有整型参数,一个私有变量。
class BaseChild : public Base
{
public:
BaseChild() {
cout << "this is BaseChild()" << endl;
}
BaseChild(int val) : Base(val) {
cout << "this is BaseChild(val)" << endl;
}
public:
int m_b;
};
3 main函数实例化了两个子类实例,child1,child2。child1调用默认构造函数。child2调用有整型参数的构造函数。
int main(int argc, char *argv[])
{
BaseChild child1;
BaseChild child2(5);
return 0;
}
现在,我们运行程序,会有如下打印:
看到了吗,我们发现:
- 创建child1时,是先调用了Base的默认构造函数,再调用自己的默认构造函数
- 创建child2时,是先调用了Base(int)这个构造函数,再调用自己的整型参数构造函数。
所以我们回头看BaseChild的构造函数
BaseChild(int val): Base(val){
cout << "this is BaseChild(val)" << endl;
}
细心的同学,可能早就发现了,初始化列表中的Base(val)正是调用了我们Base基类的有参构造函数,而这样的写法就刚好是我们开头代码中的那段
Widget::Widget(QWidget *parent) :QWidget(parent)
所以Widget是调用了QWidget下面的构造函数
QWidget(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
所以得出如下总结:
基类的私有成员,在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们。
基类的构造函数是不能被继承的,在声明派生类时,派生类并没有把基类的构造函数继承过来。因此,对继承过来的基类成员变量的初始化工作也要由派生类的构造函数承担。
如果希望在执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。思路是:在执行派生类的构造函数时,调用基类的构造函数。
好的,那么我们又提出一个问题,“调用QWidget(parent)这个构造函数,QWidget父类都做了哪些动作呢?”
下面是QWidget源码中的一部分节选:
QWidget::QWidget( QWidget *parent, const char *name, WFlags f )
: QObject( parent, name ), QPaintDevice( PDT_WIDGET ),
pal( parent ? parent->palette() // use parent's palette
: *qApp->palette() ) // use application palette
{
if ( parent ) {
QChildEvent *e = new QChildEvent( Event_ChildInserted, this );
QApplication::postEvent( parent, e );
}
}
大家从上面可以看出,如果parent参数非空的话,那么该构造函数使用了其父窗口的调色板,并且发送了QChildEvent事件,这会让新的窗口成为parent所指窗口的子窗口,那么当父窗口被删除时,子窗口也会自动的被删除。
这其实是用到了Qt对象树的概念。
假如Base类和BaseChild类也有对象树概念的话,我们可以近似认为它们的对象树如图所示。
三、QWidget的使用
QWidget介绍
QWidget是用户操作的原子接口,它从窗口系统中接收鼠标,键盘以及其他事件,并绘制图形界面。QT提供的默认窗口基类只有QMainWindow、QWidget、和QDialog这三种,QMainWindow是带有菜单栏和工具栏的主窗口类,QDialog是各种对话框的基类,而它们全部继承自QWidget。不仅如此,所有的窗口部件都继承自QWidget,继承关系如图所示。
一个没有父窗口部件的窗口部件一直是顶级窗口部件。非顶级窗口部件是父窗口的子部件。QWidget构造函数有两个参数:QWidget *parent = 0,Qt::WindowFlags f = 0
。parent即父窗口,默认为0,即没有父窗口,是顶级窗口,如果指定parent值则当前窗体将会是一个子部件。Qt::WindowFlags是Qt::WindowType枚举值的组合,用来设置窗口的属性,f = 0表默认为Qt::Widget风格。
Widget(QWidget* parent = nullptr, Qt::WindowFlags f = 0);
自定义窗口类Widget,该类继承自QWidget基类。parent即父窗口,默认为0,即没有父窗口,是顶级窗口。如果指定parent值则当前窗体将会是一个子部件,并且被parent的几何形状所强迫。
Qt::WindowFlags f = 0 (在可用的地方)设置窗口标志;默认值适用于几乎所有窗口组件,但如果要获得一个没有窗口系统框架的窗口,则必须使用特殊的标志。
QWidget有很多成员函数需要重写
QWidget有很多成员函数,但是它们中的一些有少量的直接功能:例如,QWidget有一个字体属性,但是它自己从来不用。有很多继承它的子类提供了实际的功能,比如QPushButton、QListBox和QTabDialog等等。
参考连接:
QT部件基类——QWidget与QDialog
【QT】——QWidget窗口类