QWidget失去了它的父母

时间:2016-09-22 10:19:13

标签: c++ qt qt5 qwidget qdialog

在我的应用程序中,我有一个QDialog,它本身包含一个复杂的,QWidget派生的GUI元素。 QDialog是模态的,用exec()打开,嵌入式GUI元素处理所有用户交互。

所以只有这个child-QWidget知道QDialog何时可以关闭,这是这样做的:

QDialog* parent=qobject_cast<QDialog*>(parentWidget());
if (parent) parent->close();

这是必要的,因为QDialog必须关闭,而不仅仅是QWidget。

现在,用户报告了QDialog-&gt; exec()已返回但是Dialog(或仅GUI元素?)仍然可见的情况。从日志文件中我可以看到QDialog-&gt; exec()确实已经返回并且在执行此调用后立即编码。

所以我目前的假设是:GUI元素丢失了它的父元素,因此上面显示的close()调用没有被调用,因为“parent”是NULL。

知道如何发生这种情况吗?是否有一种常规的方式,QWidget的父母可以消失?

谢谢!

1 个答案:

答案 0 :(得分:1)

一般来说,使用QDialog::exec重新进入事件循环会导致麻烦,因为突然主线程中运行的所有代码都必须是可重入的。很可能你面临着后果。不要重新进入事件循环,你会没事或问题会变得可重现。

如果您需要对正在接受或拒绝的对话做出反应,请将代码连接到相关的插槽。即改变这个:

void do() {
  MyDialog dialog{this};
  auto rc = dialog.exec();
  qDebug() << "dialog returned" << rc;
}

到那个:

class Foo : public QWidget {
  MyDialog dialog{this};
  ...
  Foo() {
    connect(&dialog, &QDialog::done, this, &Foo::dialogDone);
  }
  void do() {
    dialog.show();
  }
  void dialogDone(int rc) {
    qDebug() << "dialog returned" << rc;
  }
};

或者,如果你想懒洋洋地初始化对话框:

class Foo : public QWidget {
  MyDialog * m_dialog = nullptr;
  MyDialog * dialog() {
    if (! m_dialog) {
      m_dialog = new MyDialog{this};
      connect(m_dialog, &QDialog::done, this, &Foo::dialogDone);
    }
    return m_dialog;
  }
  ...
  void do() {
    dialog()->show();
  }
  void dialogDone(int rc) {
    qDebug() << "dialog returned" << rc;
  }
};

对于子窗口小部件来说,尝试插入父窗口是一个可怕的反模式。 小部件具有父级的知识不应该泄漏到小部件中,它应该本地化到父级。因此,子小部件应该发出指示例如,数据被接受了。创建对话框时,请将此信号连接到对话框的accept()close()位置:

class MyWidget : public QWidget {
  Q_OBJECT
public:
  Q_SIGNAL void isDone();
  ...
};

class MyDialog : public QDialog {
  QGridLayout layout{this};
  MyWidget widget;
public:
  MyDialog() {
    layout.addWidget(&widget, 0, 0);
    connect(&widget, &MyWidget::isDone, this, &QDialog::accepted);
  }
};