16、Qt对象间的父子关系

QCalculatorUI类对象在堆空间中创建了文本框和按钮,但没有对应的delete代码,是一个bug吗?

qt对象间可以存在父子关系,每一个对象都保存有它所有子对象的指针,每一个对象都有一个指向其父对象的指针。

当指定qt对象的父对象时,其父对象会在子对象链表中加入该对象的指针,该对象会保存指向其父对象的指针。

#include <QtCore/QCoreApplication>
#include <QDebug>
void fcTest()
{
    QObject* p=new QObject();
    QObject* c1=new QObject();
    QObject* c2=new QObject();
    c1->setParent(p);
    c2->setParent(p);
    qDebug() <<"c1" <<c1;
    qDebug() <<"c1" <<c2;
    const QObjectList& list=p->children();
    for(int i=0;i<list.length();i++)
    {
        qDebug()<<list[i];
    }
    qDebug() <<"p" <<p;
    qDebug() <<"c1" <<c1->parent();
    qDebug() <<"c1" <<c2->parent();
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    fcTest();
    return a.exec();

}

当qt对象被销毁时,将自己从父对象的Children List移除,将自己的Children List中的所有对象销毁。

使用qt开发时,不仅要时刻注意内存泄漏问题,还要时刻关注对象是否可能被多次销毁的问题。

利用qt对象间的父子关系可以构成对象树,删除树中的结点时会导致对应的子树被销毁。

#include <QtCore/QCoreApplication>
#include <QDebug>
class MObj : public QObject
{
    QString m_name;
public:
    MObj(const QString& name)
    {
        m_name = name;
        qDebug() << "Constructor: " << m_name;
    }
    ~MObj()
    {
        qDebug() << "Destructor: " << m_name;
    }
};
void fcTest()
{
    QObject* p = new QObject();
    QObject* c1 = new QObject();
    QObject* c2 = new QObject();
    c1->setParent(p);
    c2->setParent(p);
    qDebug() << "c1: " << c1;
    qDebug() << "c2: " << c2;
    const QObjectList& list = p->children();
    for(int i=0; i<list.length(); i++)
    {
        qDebug() << list[i];
    }
    qDebug() << "p: " << p;
    qDebug() << "c1 parent: " << c1->parent();
    qDebug() << "c2 parent: " << c2->parent();
}
void delTest()
{
    MObj* obj1 = new MObj("obj1");
    MObj* obj2 = new MObj("obj2");
    MObj* obj3 = new MObj("obj3");
    MObj* obj4 = new MObj("obj4");
    obj2->setParent(obj1);//指定父亲
    obj3->setParent(obj1);
    obj4->setParent(obj3);
    delete obj3;
    const QObjectList& list = obj1->children();
    qDebug() << "obj2: " << obj2;
    for(int i=0; i<list.length(); i++)
    {
        qDebug() << list[i];
    }
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    fcTest();
    delTest();
    return a.exec();

}

小结:qt对象间可以存在父子关系,通过父子关系能够得到qt对象树,qt对象销毁时解除和父对象间的父子关系,qt对象销毁时将同时销毁所有的子对象。

扫描二维码关注公众号,回复: 1442214 查看本文章

17、对话框是与用户进行简短交互的顶层窗口,QDialog是Qt中所有对话框窗口的基类,QDialog继承与QWidget,是一种容器类型的组件。

QDialog的意义:作为一种专用的交互窗口而存在,不能作为子部件嵌入其他容器中,是定制了窗口样式的特殊QWidget。

QWidget仅仅是一个抽象的组件,没有父组件成为独立窗口,有父组件作为可见部件嵌入到父组件中。

模态对话框(QDislog::exec()):显示后无法与父窗口进行交互,是一种阻塞式的对话框调用方式(只能和对话框交互)。

非模态对话框(QDislog::show()):显示后独立存在可以同时与父窗口进行交互,是一种非阻塞式的对话框调用方式。

一般情况下:模态对话框用于必须依赖用户选择的场合(80%):消息提示,文本选择,打印设置等。

非模态对话框用于特殊功能设置的场合(20%):查找操作,属性设置,等。

小技巧:在栈上创建模态对话框是最简单常用的方式,一般情况下非模态对话框需要在堆上创建(如果在栈上函数结束会销毁直接退出),通过QDialog::setModal函数可以创建混合特性的对话框,非模态对话框需要指定Qt::WA_DeleteOnClose属性(对话框关闭时释放资源)。

对话框的返回值:

只有模态对话框才有返回值的概念,模态对话框的返回值用于表示交互结果

QDialog::exec()的返回值为交互结果(阻塞式函数):

void QDislog::done(int i) 关闭对话框并将参数作为交互结果:

QDialog::Accepted-用户操作成功

QDialog::Rejected-用户操作失败

#ifndef DIALOG_H
#define DIALOG_H
#include <QtGui/QDialog>
#include <QPushButton>
class Dialog : public QDialog
{
    Q_OBJECT
protected:
    QPushButton ModalBtn;
    QPushButton NormalBtn;
    QPushButton MixedBtn;
protected slots:
    void ModalBtn_Clicked();
    void NormalBtn_Clicked();
    void MixedBtn_Clicked();
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
};

#endif 

#include "Dialog.h"
#include <QDebug>
Dialog::Dialog(QWidget *parent) :
        QDialog(parent), ModalBtn(this), NormalBtn(this), MixedBtn(this)
{
    ModalBtn.setText("Modal Dialog");
    ModalBtn.move(20, 20);
    ModalBtn.resize(100, 30);
    NormalBtn.setText("Normal Dialog");
    NormalBtn.move(20, 70);
    NormalBtn.resize(100, 30);
    MixedBtn.setText("Mixed Dialog");
    MixedBtn.move(20, 120);
    MixedBtn.resize(100, 30);
    connect(&ModalBtn, SIGNAL(clicked()), this, SLOT(ModalBtn_Clicked()));
    connect(&NormalBtn, SIGNAL(clicked()), this, SLOT(NormalBtn_Clicked()));
    connect(&MixedBtn, SIGNAL(clicked()), this, SLOT(MixedBtn_Clicked()));
    resize(140, 170);
}

void Dialog::ModalBtn_Clicked()
{
    qDebug() << "ModalBtn_Clicked() Begin";
    QDialog dialog(this);//指定父组件为this,顶层父类
    dialog.exec();
    // done(Accepted);
    qDebug() << "ModalBtn_Clicked() End";
}

void Dialog::NormalBtn_Clicked()
{
    qDebug() << "NormalBtn_Clicked() Begin";
    QDialog* dialog = new QDialog(this);
    dialog->setAttribute(Qt::WA_DeleteOnClose);//释放对象
    dialog->show();
    // done(Rejected);
    qDebug() << "NormalBtn_Clicked() End";
}
void Dialog::MixedBtn_Clicked()
{
    qDebug() << "MixedBtn_Clicked() Begin";
    QDialog* dialog = new QDialog(this);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->setModal(true);//设置非模态对话框行为类似模态对话框
    dialog->show();
    // done(100);
    qDebug() << "MixedBtn_Clicked() End";
}

Dialog::~Dialog()
{
    qDebug() << "~Dialog()";

}

#include <QtGui/QApplication>
#include <QWidget>
#include <QDialog>
#include <QDebug>
#include "Dialog.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog dlg;
    int r = dlg.exec();
    if( r == QDialog::Accepted )
    {
        qDebug() << "Accepted";
    }
    else if( r == QDialog::Rejected )
    {
        qDebug() << "Rejected";
    }
    else
    {
        qDebug() << r;
    }
    return r;//如果将模态对话框作为主窗口运行的话返回应该是r用户选择,a.exec();表示进入消息循环,关闭窗口还没有退出消息循环
}

小结:对话框分为模态对话框和非模态对话框,模态对话框是阻塞的,模态对话框用于依赖用户交互结果的场合,非模态对话框是非阻塞式的,非模态对话框用于功能设置的场合。

猜你喜欢

转载自blog.csdn.net/ws857707645/article/details/80517189