2

I have an application that opens a QDialog for some flow, and when it is closed, the QMainWindow is opened.

In the QDialog I create some objects that I'd like to pass as a pointer (or some other way) to the QMainWindow. For example I create a SysTray object that needs to change its state from the QMainWindow. What is the best way? Singletons?

update .
after implementing the sulotion another question was rises , does the QDialog is cleaned from memory that means , invoked its destructor ? i don't think its the case . i have to do some object cleaning , and there destructor never invoked

user63898
  • 26,293
  • 71
  • 223
  • 438

4 Answers4

3

One approach is to allocate on the heap with the QMainWindow as a parent. The QObject-hierarchy will take care of freeing the memory and you will access the object for the lifetime of the QMainWindow.

If at any point you know for sure that you don't need the QDialog or the shared object anymore, you can call deleteLater.

Example:

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

Where you use your QDialog:

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

A better (and likely more memory-friendly) approach is to use a shared pointer implementation. Qt has a variety of smart pointer classes, one of which is QSharedPointer. It is basically a thread-safe, reference-counted pointer which means that if you grab one that points to the shared object of your QDialog, it will not get freed as long as there are any other QSharedPointers pointing to it. Keep in mind that this might cause circular references if you are not careful.

Example:

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

Where you use your QDialog:

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

From this point on, even if d goes out of scope (i.e. destroyed), you will still have a valid pointer to the shared data (well, of course unless you do something explicitly to invalidate it).

Tamás Szelei
  • 21,352
  • 16
  • 94
  • 169
2

You have a lot of different options. Some of these may not be applicable to your situation:

Case 1: Caller knows best (i.e. procedural programming)

Define a controller that can control the ordering. That control can then act as the intermediary and get the data once the dialog has closed:

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

Case 2: Message Passing

Create both the dialog and the main window up front. Connect the corresponding signals and slots and let them both be ignorant of one another. This is usually much easier to test and keep decoupled:

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.
  }
}

Case 3: Shared State Dependency

Define your shared data up front and make it a dependency for each form. Each form then defines state, acts based on that state, or some combination of both:

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
}

Case 4: MVC / MVP / MVVM

You may be able to define your shared state as a model that they both act upon. This may not be much different than case three above.

Case 4: Singleton or global state

It will work, but please don't do it :).

Community
  • 1
  • 1
Kaleb Pederson
  • 43,537
  • 19
  • 96
  • 144
0

In QDialog you have owner, which is probably QMainWindow. (if not, you may add it there, ore get parent objects until you come to QMainWindow class). You may refer to it when creating new objects...

Raiv
  • 5,463
  • 1
  • 31
  • 50
0

You can subclass QApplication to have it keep a pointer to your systray object, or other objects which should be available "application wide".

In a Qt application, there is only a single instance of QApplication, available everywhere using the qApp macro.

See this mailing list discussion which also contains an example.

Leiaz
  • 2,717
  • 2
  • 18
  • 23