QWidget :: show()带有设置的父对象

时间:2018-11-08 13:22:23

标签: qt qt5

如果设置了父级,QDialog::show()不会显示窗口是预期行为吗?

背景:我想使用QMetaObject::connectSlotsByName()对其中一个对话框信号做出反应,这意味着父对象需要拥有它。没有标记为“ 这是相关行”的行,我得到一个运行时消息“ QMetaObject :: connectSlotsByName:on_child_accepted()无匹配信号”。但是有了这一行,子对话框将不再出现。

#include <QtCore/QDebug>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QVBoxLayout>

class Parent : public QDialog
{
    Q_OBJECT

public:
    Parent(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
        : QDialog{parent, f}
    {
        b.setText(tr("Show child"));
        connect(&b, &QPushButton::clicked, [&]() {
            c.show();
        });
        l.addWidget(&b);
        setLayout(&l);

        c.setParent(this);  // This is the line in question
        c.setObjectName("child");
        QMetaObject::connectSlotsByName(this);
    }

private slots:
    void on_child_accepted()
    {
        qDebug() << "I got called";
    }

private:
    QPushButton b;
    QDialog c;
    QVBoxLayout l;
};

#include "main.moc"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Parent w;
    w.show();

    return a.exec();
}

此测试在Windows的Qt 5.11上通过MSYS2 64位版本失败。

有什么建议吗?预先谢谢你。

1 个答案:

答案 0 :(得分:1)

该对话框实际上确实出现了,但是却没有显示出来:它是窗口的非窗口子窗口小部件-它是透明的,但是却遮盖了大部分“显示对话框”按钮,消耗了所有鼠标事件,而且已经显示了,因为所有的孩子都在显示父对象时显示了-因此,由于这两个原因,该按钮似乎无法正常工作。

设置小部件的父级将清除其Qt::Window标志。设置对话框的背景有助于可视化问题。因此,您需要在设置对话框的父级后将其设置为窗口。

以下内容重现了您的错误,并演示了解决方法。

// https://github.com/KubaO/stackoverflown/tree/master/questions/dialog-show-parenting-53208641
#include <QtWidgets>
class Parent : public QDialog {
   Q_OBJECT
   QVBoxLayout layout{this};
   QDialog child;
   QPushButton cShow{tr("Show child")}, cNonWindow{tr("Renew non-window child")},
       cWindow{tr("Renew window child")};
   Q_SLOT void on_child_accepted() {}
   void reChild(bool makeWindow) {
      child.~QDialog();
      new (&child) QDialog;
      Q_ASSERT(child.isWindow());
      child.setParent(this);
      child.setObjectName("child");
      child.setStyleSheet("QWidget { background: blue }");
      if (makeWindow) {
         child.setWindowFlag(Qt::Dialog);
         Q_ASSERT(child.isWindow());
      } else {
         Q_ASSERT(!child.isWindow());
         child.show();  // The child gets shown when we're shown
      }
      QMetaObject::invokeMethod(this, &Parent::updateChild, Qt::QueuedConnection);
   }
   void updateChild() {
      if (!child.isWindow()) child.move(50, cWindow.y() + cWindow.height() / 2);
      this->update();  // Work around a refresh bug (affects OS X on 5.11 at least)
   }

  public:
   Parent(QWidget *parent = nullptr, Qt::WindowFlags f = {}) : QDialog{parent, f} {
      connect(&cShow, &QPushButton::clicked, [&]() { child.show(); });
      connect(&cNonWindow, &QPushButton::clicked, [&] { reChild(false); });
      connect(&cWindow, &QPushButton::clicked, [&] { reChild(true); });
      for (auto *w : {&cShow, &cNonWindow, &cWindow}) layout.addWidget(w);
      cNonWindow.click();
      QMetaObject::connectSlotsByName(this);
   }
};

int main(int argc, char *argv[]) {
   QApplication a(argc, argv);
   Parent w;
   w.show();
   return a.exec();
}
#include "main.moc"
相关问题