QWidget 失去了它的父级

Posted

技术标签:

【中文标题】QWidget 失去了它的父级【英文标题】:QWidget loses its parent 【发布时间】: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 仅在对话框隐藏(或关闭)时返回。你能告诉我们对话框是否有可能被创建了两次? 【参考方案1】:

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

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

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

到那个:

class Foo : public QWidget 
  MyDialog dialogthis;
  ...
  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 MyDialogthis;
      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 layoutthis;
  MyWidget widget;
public:
  MyDialog() 
    layout.addWidget(&widget, 0, 0);
    connect(&widget, &MyWidget::isDone, this, &QDialog::accepted);
  
;

【讨论】:

我很惊讶文档中没有提到它,如果可能的话,应该避免嵌套事件循环,例如 QDialog::exec。在一些博客中提到过,但我认为应该更明显。

以上是关于QWidget 失去了它的父级的主要内容,如果未能解决你的问题,请参考以下文章

qwidget.setGeometry() 在 linux 上的位置不正确

创建 QWidget 宽度 HWND 父级

QWidget 如何获得“整个”父级?

由父级绘制 QWidget

PyQt5 - 在 QMainMenu 中,如何使 QWidget 成为父级(暂时)?

如何从父级不是 QMainWindow 的 QWidget 访问 QMainWindow