我有一个应用程序,它为某个流打开一个QDialog,当它关闭时,QMainWindow就会打开。
在QDialog中,我创建了一些对象,希望将其作为指向QMainWindow的指针(或其他方式)传递。例如,我创建了一个SysTray对象,该对象需要从QMainWindow更改其状态。最好的方法是什么?单身汉?
更新
在实现了sulotion之后,另一个问题是rises,QDialog是否从内存中清除,也就是说,调用了它的析构函数?我认为情况并非如此。我必须进行一些对象清理,那里的析构函数从未调用
一种方法是将QMainWindow
作为父级在堆上进行分配。QObject层次结构将负责释放内存,并且您将在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有多种智能指针类,其中之一就是QSharedPointer
。它基本上是一个线程安全的、引用计数的指针,这意味着如果你获取一个指向QDialog
的共享对象的指针,只要有其他QSharedPointer
指向它,它就不会被释放。请记住,如果你不小心,这可能会导致循环引用。
示例:
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:呼叫者最清楚(即程序性编程)
定义一个可以控制排序的控制器。然后,该控件可以充当中介,并在对话框关闭后获取数据:
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/MVM
您可以将您的共享状态定义为一个模型,它们都可以根据该模型进行操作。这可能与上面的第三种情况没有太大区别。
案例4:辛格尔顿或全球状态
它会起作用,但请不要这样做:)。
在QDialog中,您有一个所有者,可能是QMainWindow。(如果没有,您可以在那里添加它,或者获取父对象,直到您进入QMainWindow类)。您可以在创建新对象时参考它。。。
您可以将QApplication子类化,使其保持指向您的systray对象或其他应该在"应用程序范围"内可用的对象的指针。
在Qt应用程序中,只有一个QApplication实例,可以使用qApp宏在任何地方使用。
请参阅此邮件列表讨论,其中还包含一个示例。