【问题标题】:QWidget loses its parentQWidget 失去了它的父级
【发布时间】:2016-09-22 10:19:13
【问题描述】:

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

所以只有QWidget这个孩子知道QDialog什么时候可以关闭,这样做是这样的:

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

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

现在用户报告了QDialog::exec() 已返回但对话框(或仅 GUI 元素?)仍然可见的情况。从日志文件中我可以看到QDialog::exec() 确实已经返回,并且该调用执行后的代码。

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

知道这是怎么发生的吗? QWidget 的父级是否可以通过常规方式消失?

【问题讨论】:

  • 您是否有充分的理由不将您孩子的信号连接到对话框的accept()reject() 插槽?
  • @thuga 我这里无法重现这个问题,所以这个评论完全没用
  • 那么把它写在问题里。
  • @thuga 已经提到了一句“现在用户报告了一个情况......”
  • 所以用户报告的任何内容都自动意味着它不能被复制?无论如何,QDialog::exec 仅在对话框隐藏(或关闭)时返回。你能告诉我们对话框是否有可能被创建了两次?

标签: c++ qt qt5 qwidget qdialog


【解决方案1】:

一般来说,使用QDialog::exec重新进入事件循环会带来麻烦,因为突然间所有在主线程中运行的代码都必须是可重入的。你很可能正面临着由此产生的后果。不要重新进入事件循环,你会没事的,否则问题会重现。

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

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);
  }
};

【讨论】:

  • 我很惊讶文档中没有提到它,如果可能的话,应该避免嵌套事件循环,例如 QDialog::exec。在一些博客中提到过,但我认为应该更明显。
猜你喜欢
  • 1970-01-01
  • 2020-06-23
  • 1970-01-01
  • 2019-02-08
  • 1970-01-01
  • 2013-03-07
  • 2012-06-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多