Loading

QWidget的isHidden和isVisible

QWidget的isHidden和isVisible

问题的出现

最近在写代码的时候,出现了一个问题,我新建了两个类,分别是Chapter2ConsecutiveCurtain

// ConsecutiveCurtain.cpp
ConsecutiveCurtain::ConsecutiveCurtain(QWidget *parent)
    :QWidget(parent)
{
    number = 1;
    this->setFixedSize(1920, 1080);
}

void ConsecutiveCurtain::start()
{
    if (m_curtainList.isEmpty()) {
        qDebug() << "显示列表为空";
        return;
    }

    m_curtain = new Curtain(m_curtainList.at(0), this);
    connect(m_curtain, &Curtain::signal_pageEnd,
            this, &ConsecutiveCurtain::slot_nextPage, Qt::UniqueConnection);
    m_curtain->start();
}
// chapter2.cpp
Chapter2::Chapter2(QWidget *parent)
    :QWidget(parent)
{
    m_curtains = new ConsecutiveCurtain(this);
    this->start();
}

void Chapter2::slot_Curtains1()
{
    m_phone->close();

    QStringList curtains;
    curtains.push_back("chapter2_4.png");
    curtains.push_back("chapter2_5.png");
    curtains.push_back("chapter2_6.png");
    curtains.push_back("chapter2_7.png");

    m_curtains->setCurtainList(curtains);

    connect(m_curtains, &ConsecutiveCurtain::signal_consecutiveCurtainEnd,
            this, &Chapter2::slot_Phone2);

    m_curtains->start();
    m_curtains->show();
}

,这几个的结构如图所示:
在这里插入图片描述

但是在我新建ConsecutiveCurtain这个类的实例,并在chapter2.cppshow()时,什么都没有显示。

我左思右想,发现了两种解决方法:

第一种方法是:

ConsecutiveCurtain::ConsecutiveCurtain(QWidget *parent)
    :QWidget(parent)
{
    number = 1;
    this->setFixedSize(1920, 1080);
    this->hide();
}

ConsecutiveCurtain类里调用this->hide(),之后就可以正常显示了。

第二种方法是:

void ConsecutiveCurtain::start()
{
    if (m_curtainList.isEmpty()) {
        qDebug() << "显示列表为空";
        return;
    }

    m_curtain = new Curtain(m_curtainList.at(0), this);
    connect(m_curtain, &Curtain::signal_pageEnd,
            this, &ConsecutiveCurtain::slot_nextPage, Qt::UniqueConnection);
    m_curtain->show();
    m_curtain->start();
}

start()函数里调用m_curtain->show()

两种方法都可以显示出来,于是我开始纠结,为啥会显示。第二方法我还是能理解的,因为直接把m_curtain显示出来了。但是第一种方法的调用hide()函数后,就可以显示的问题,使我百思不得其解。

QWidget的show()函数

在我印象中,show()是会将调用者和调用者的子窗口也一起show出来,于是我就有了一个疑问,在chapter2::slot_Curtains1函数中,我调用了m_curtains->show(),按道理是会将Consecutive中的m_curtain一起show()出来的。
在这里插入图片描述

于是我去看QWidget的源码,发现所有的show()函数,都是调用的setVisible()这一个函数。

void QWidgetPrivate::setVisible(bool visible)
{
    Q_Q(QWidget);
    if (visible) { // show
        // Designer uses a trick to make grabWidget work without showing
        if (!q->isWindow() && q->parentWidget() && q->parentWidget()->isVisible()
            && !q->parentWidget()->testAttribute(Qt::WA_WState_Created))
            q->parentWidget()->window()->d_func()->createRecursively();

        //create toplevels but not children of non-visible parents
        QWidget *pw = q->parentWidget();
        if (!q->testAttribute(Qt::WA_WState_Created)
            && (q->isWindow() || pw->testAttribute(Qt::WA_WState_Created))) {
            q->create();
        }

这里的createRecursively则是去递归的show子窗口,这里是否创建子窗口有一个判断依据,那就是子窗口的isHidden是不是返回的false,也就是说子窗口是不是没有被隐藏。

void QWidgetPrivate::createRecursively()
{
    Q_Q(QWidget);
    q->create(0, true, true);
    for (int i = 0; i < children.size(); ++i) {
        QWidget *child = qobject_cast<QWidget *>(children.at(i));
        if (child && !child->isHidden() && !child->isWindow() && !child->testAttribute(Qt::WA_WState_Created))
            child->d_func()->createRecursively();
    }
}

QWidget的isVisible和isHidden

在找寻为什么调用hide()之后,就能正常显示时,我发现了这两个函数isVisibleisHidden,然后我用这两个函数加到代码里做测试(得到正确的测试方法不知道走了多少弯路)

void Chapter2::slot_Curtains1()
{
    m_phone->close();

    qDebug() << m_curtains->isVisible();

    QStringList curtains;
    curtains.push_back("chapter2_4.png");
    curtains.push_back("chapter2_5.png");
    curtains.push_back("chapter2_6.png");
    curtains.push_back("chapter2_7.png");

    m_curtains->setCurtainList(curtains);

    connect(m_curtains, &ConsecutiveCurtain::signal_consecutiveCurtainEnd,
            this, &Chapter2::slot_Phone2);

    m_curtains->start();
    m_curtains->show();

    qDebug() << m_curtains->isVisible();
}
void ConsecutiveCurtain::start()
{
    if (m_curtainList.isEmpty()) {
        qDebug() << "显示列表为空";
        return;
    }

    m_curtain = new Curtain(m_curtainList.at(0), this);
    connect(m_curtain, &Curtain::signal_pageEnd,
            this, &ConsecutiveCurtain::slot_nextPage, Qt::UniqueConnection);
    qDebug() << "m_curtain visible :" << m_curtain->isVisible();
    qDebug() << "m_curtain hidden :" << m_curtain->isHidden();
    m_curtain->start();
}

在不调用hide()函数时,输出如下:

 true

 m_curtain visible : false

 m_curtain hidden : true

 true

调用hide()函数后,输出如下:

false

m_curtain visible : false

m_curtain hidden : false

true

然后我在查阅isHidden这个函数的手册时,发现如下解释:

在这里插入图片描述

到这里,我就恍然大悟:

如果不调用hide()函数,ConsecutiveCurtain的实例就不会隐藏,这样,m_curtain也就会被设置成隐藏,哪怕你show出父窗口,子窗口也会因为被隐藏这个原因,而不显示。

源码追溯

于是我又试着去源码里找这一部分的实现方法:

这是QWidget类的构造函数
在这里插入图片描述

我又溯源到init()函数…
在这里插入图片描述
这里我发现了一个q->setAttribute(Qt::WA_WState_Hidden);,这里相当于默认就给新建的窗口设置为隐藏,但是也没有找到帮助文档里所说的,于是我又继续往下寻找,我发现了一个setParent()函数
在这里插入图片描述
我找到这个setParent函数,
在这里插入图片描述
然后再setParent里找到了这个setParent_sys
在这里插入图片描述
最终,我在这个setParent_sys里找到了这一句代码,也就是说,如果新设置的parent是可见的,就将当前窗口设置成隐藏属性。
在这里插入图片描述
至此,就找出了所有问题的答案…
第一次看源码来找问题,虽然找了大半个下午,但是找到的那一瞬间真的是超级开心…

posted @ 2022-09-03 19:46  师从名剑山  阅读(131)  评论(0编辑  收藏  举报