如何在关闭的QDialog和新打开的QMainWindow之间共享对象?

时间:2011-05-27 02:54:10

标签: c++ qt

我有一个应用程序为某个流打开一个QDialog,当它关闭时,QMainWindow被打开。

在QDialog中,我创建了一些我想作为指针(或其他方式)传递给QMainWindow的对象。例如,我创建了一个需要从QMainWindow更改其状态的SysTray对象。什么是最好的方法?单身?

更新。
实施闷热后,另一个问题是上升,QDialog是否从内存中清除,意味着,调用了它的析构函数?我认为不是这样的。我必须做一些对象清理,并且从不调用析构函数

4 个答案:

答案 0 :(得分:3)

一种方法是在堆上分配QMainWindow作为父级。 QObject-hierarchy将负责释放内存,您将在QMainWindow的生命周期内访问该对象。

如果您在任何时候确定不再需要QDialog或共享对象,则可以致电deleteLater

示例:

class MyDialog : public QDialog
{
    Q_OBJECT

    QObject* _objToShare;

public:    
    QObject* objToShare() const { return _objToShare; }

    MyDialog(QObject* parent = 0) : QDialog(parent)
    {
        _objToShare = new QObject(this); // either use this as the parent
                                         // or free by hand in the destructor
    }

    // ...
 };

 class MyWindow : public QMainWindow
 {
     Q_OBJECT
     // ...

     QObject* ptrToSharedObj; // alternatively you can hold a pointer
                              // to your MyDialog instance
 };

您使用QDialog的地方:

 MyDialog* d = new MyDialog(this);
 d->exec();
 ptrToSharedObj = d->objToShare();
 // don't delete d explicitly, the QObject hierarchy will take care of that

更好(并且可能更加内存友好)的方法是使用共享指针实现。 Qt有各种smart pointer classes,其中一个是QSharedPointer。它基本上是一个线程安全的引用计数指针,这意味着如果你抓住一个指向QDialog的共享对象的指针,只要有任何其他QSharedPointer它就不会被释放s指向它。请记住,如果您不小心,这可能会导致循环引用。

示例:

class MyDialog : public QDialog
{
    Q_OBJECT

    QSharedPointer<QObject> _objToShare; 
                                 // ^ don't delete in the destructor
public:

    QSharedPointer<QObject> objToShare() const { return _objToShare; }

    MyDialog(QObject* parent = 0) : QDialog(parent)
    {
        _objToShare = QSharedPointer<QObject>(new QObject); 
        // no parent to avoid destruction when the dialog is destructed
    }

    // ...
 };

 class MyWindow : public QMainWindow
 {
     Q_OBJECT
     // ...

     QSharedPointer<QObject> ptrToSharedObj;
 };

您使用QDialog的地方:

MyDialog d;
d.exec();
ptrToSharedObj = d.objToShare(); 

从这一点开始,即使d超出范围(即销毁),你仍然会有一个指向共享数据的有效指针(当然,除非你明确地做了一些事情来使它无效)。

答案 1 :(得分:2)

你有很多不同的选择。其中一些可能不适用于您的情况:

案例1:来电者最了解(即程序式编程)

定义一个可以控制排序的控制器。然后,该控件可以充当中介并在对话框关闭后获取数据:

void FlowController::displayFlow()
{
  MyDialog *dialog = new MyDialog();
  YourSharedData *data = NULL;
  int result = dialog->exec();
  if (result == QDialog::Accepted) {
    data = dialog->sharedDataAccessor();
  }

  MyMainWindow *window = new MyMainWindow();
  window->setSharedData(data);
  window->exec();
}

案例2:消息传递

预先创建对话框和主窗口。连接相应的信号和插槽,让它们彼此无知。这通常更容易测试并保持解耦:

void AppLauncher::launch()
{
  MyDialog *dialog = new MyDialog();
  MyMainWindow *window = new MyMainWindow();
  window->connect(
    dialog,
    SIGNAL(dialogResult(int, const SharedData&)),
    SLOT(setDialogResult(int,const SharedData&))
    );
}

void MyMainWindow::setDialogResult(int result, const SharedData& sharedData)
{
  if (result == Dialog::Accepted) // something domain-specific would be better
  {
    this->processSharedData(sharedData); // do whatever with it.
  }
}

案例3:共享状态依赖

预先定义您的共享数据,并使其成为每个表单的依赖项。然后,每个表单定义状态,基于该状态的行为,或两者的某种组合:

void AppLauncher::launch()
{
  SharedData *data = this->createSharedData();
  MyDialog *dialog = new MyDialog(data);
  MyMainWindow *window = new MyMainWindow();
  dialog->exec(); // does what it needs with shared data
  window->exec(); // checks shared data and acts accordingly
}

案例4:MVC / MVP / MVVM

您可以将共享状态定义为他们都采取行动的模型。这可能与上面的案例三没有太大的不同。

案例4:单身人士或全球国家

它会起作用,但please don't do it:)。

答案 2 :(得分:0)

在QDialog中你拥有所有者,可能是QMainWindow。 (如果没有,你可以在那里添加它,在获得QMainWindow类之前获取父对象)。您可以在创建新对象时引用它...

答案 3 :(得分:0)

您可以将QApplication子类化,使其保留指向systray对象的指针,或者应该在“应用程序范围内”可用的其他对象。

在Qt应用程序中,只有一个QApplication实例,可以在任何地方使用qApp宏。

请参阅this mailing list discussion which also contains an example