【问题标题】:How do I share objects between a closed QDialog and newly opened QMainWindow?如何在关闭的 QDialog 和新打开的 QMainWindow 之间共享对象?
【发布时间】:2011-05-27 02:54:09
【问题描述】:

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

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

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

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    一种方法是在堆上分配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 classesQSharedPointer就是其中之一。它基本上是一个线程安全、引用计数的指针,这意味着如果你抓住一个指向 QDialog 的共享对象的指针,只要有任何其他 QSharedPointers 指向它,它就不会被释放.请记住,如果您不小心,这可能会导致循环引用。

    例子:

    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 超出范围(即被销毁),您仍然会有一个指向共享数据的有效指针(当然,除非您明确执行某些操作使其无效)。

    【讨论】:

      【解决方案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 :)。

      【讨论】:

        【解决方案3】:

        在 QDialog 中你有所有者,它可能是 QMainWindow。 (如果没有,你可以在那里添加它,或者获取父对象,直到你来到 QMainWindow 类)。创建新对象时可以参考它...

        【讨论】:

          【解决方案4】:

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

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

          this mailing list discussion which also contains an example

          【讨论】:

          • 另见QCoreApplication::instance(),它适用于没有宏的语言。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-11-24
          • 2014-04-08
          • 2011-04-20
          • 2018-02-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多