多个 QApplication 实例
Multiple QApplication instances
我想知道在同一进程中有多个QApplication
/QCoreApplication
实例的含义(问题)是什么,以及如何解决一些关于它的问题。
场景如下:我想在开源第三方应用程序上制作一个包装器,以便将其转换为可嵌入的小部件作为可选插件(该应用程序基本上由单个基于QMainWindow
的界面组成)。
这样的项目严重依赖于QCoreApplication
派生类,但基本上是因为它被用作已经存在的单例。我能够修改代码(我必须这样做才能将QMainWindow
公开为可嵌入的小部件),尽管由于该项目的复杂性,我不能简单地删除父类。
因此,最终应用程序将有自己的QApplication
(在启动时创建),然后可以选择加载上述插件(从而创建第二个QCoreApplication
)。只有第一个(主)QApplication
用于事件循环(QCoreApplication::exec()
)。
我知道QCoreApplication
是一个单身人士的事实。在我的测试中,单例总是指向最后创建的实例:
qDebug() << qApp;
auto app1 = new QApplication(argc, argv);
qDebug() << qApp;
auto app2 = new TheOtherQApplication(argc, argv);
qDebug() << qApp;
输出为
QObject(0x0)
QApplication(0x6f9400, name = "test")
QCoreApplication 中的 ASSERT 失败:"应该只有一个应用程序对象",文件内核\qcoreapplication.cpp,第 595 行
TheOtherQApplication(0x2550dc0, name = "test")
TheOtherQApplication(0x2550dc0, name = "test")TheOtherQApplication(0x2550dc0, name = "test")
可以看出,在创建第二个QApplication
后,它将替换全局实例。有什么办法可以解决这个问题吗?由于插件是可选的,因此显而易见的答案(将主QApplication
加载到第二位)不是一个合适的选项。
另外,拥有多个QApplication
实例还有其他影响吗?还是都与事件循环(选中)和单例有关?
注意:这是一个基于Qt 4.7的项目,因为第三方依赖项尚未完全更新。计划在一年左右的时间内将其迁移到最新版本,但目前我必须处理 4.7。
顺便说一句,我已经回顾了几个相关问题,包括这个问题,但没有提供任何有用的信息。
好吧,据我所知,使用两个或多个Q*Application
(QCoreApplication
,QGuiApplication
,QApplication
)意味着:
-
创建第二个(或更多)应用程序时,断言在调试模式下失败。在发布模式下不会崩溃。
-
Q*Application
的每个实例化都会更新单例(即,qApp
将始终指向最后一个实例)。 -
全局属性(如应用程序名称和版本)沿实例传输并覆盖以前的属性。
-
连接到
Q*Application
插槽的任何信号都会调用单例插槽,即使在创建最新实例之前已连接也是如此。 -
只会调用连接到最新
Q*Application
信号的插槽(它们不会传输到新实例)。 -
创建新的
Q*Application
实例时,不会传输转换器。 -
如果最后一个
Q*Application
被销毁,则单一实例变为 null(它不会回退到上一个实例)。
您可以使用以下代码和切换USE_TWO_QAPPS
来测试这些功能:
#include <QtCore>
#define USE_TWO_QAPPS
int main(int argc, char* argv[])
{
QTranslator tr1;
QCoreApplication a1(argc, argv);
a1.setApplicationName("a1");
a1.installTranslator(&tr1);
qDebug() << qApp << &a1;
qDebug() << "a1.applicationName() =" << a1.applicationName();
// qApp == &a1
QObject::connect(&a1, &QCoreApplication::aboutToQuit, []() {
// point 5, never called with Q*Application
qDebug() << "Hello world from a1!";
});
QTimer::singleShot(2000, &a1, &QCoreApplication::quit); // as if connected to latest qApp, point 4
#ifdef USE_TWO_QAPPS
// if (true) { // uncomment to test point 7
QCoreApplication a2(argc, argv);
a2.setApplicationName("a2");
qDebug() << qApp << &a1 << &a2; // test point 2
qDebug() << "a2.applicationName() =" << a2.applicationName();
qDebug() << "a1.applicationName() =" << a1.applicationName(); // as if called from qApp, point 3
QObject::connect(&a2, &QCoreApplication::aboutToQuit, []() {
qDebug() << "Hello world from a2!";
});
// } // uncomment to test point 7
#endif
qDebug() << qApp->removeTranslator(&tr1); // false if the translator is not installed, point 6
a1.installTranslator(&tr1); // it is installed in the latest instance (as if called from qApp)
qDebug() << qApp->removeTranslator(&tr1);
return qApp->exec();
}
一Q*Application
结果
主要申请(0xfafb74) 申请(0xfafb74)
a1.applicationName() = "a1">
真
真
来自a1的你好世界!
两个Q*Application
的结果
主要申请(0xbefb2c) 申请(0xbefb2c)
a1.applicationName() = "a1">
QCoreApplication 中的 ASSERT 失败:"应该只有一个应用程序对象",文件 ###\qtbase\src\corelib\kernel\qcoreapplication.cpp,第 769 行
主要申请(0xbefb1c) 申请(0xbefb2c) 申请(0xbefb1c)
a2.applicationName() = "a2">
a1.applicationName() = "a2">
假
真
来自a2的世界你好!
测试点 7 时,退出if
语句时a2
被销毁。在这种情况下,每次调用完成Q*Application
方法都会引发警告并且不会执行(它们不会崩溃,也不会中断断言)。即使从以前的应用程序调用时也会发生这种情况:a1.installTranslator(&tr1);
QApplication::installTranslator:请先实例化QApplication对象
注意:使用 Visual Studio 2010 进行测试。Qt版本是4.7和5.6.1-1,结果相同
>UPDATE:此答案的更简洁的代码版本可在 https://github.com/cbuchart/stackoverflow/blob/master/46304070-multiple-qapplication-instances/main.cpp在注释之后,此代码还测试当所有QApplication
对象被销毁然后再次创建时会发生什么。结果:正如预期的那样,没有发生任何特殊情况,似乎没有副作用。
结论
考虑到这两点,似乎可以与两个或多个Q*Application
一起工作,更关键的是,当在任何Q*Application
上完成时,与信号的连接会丢失并且没有安装转换器。此外,如果最后一个实例被销毁,则没有可用的应用程序,因此您应该处理这些情况(例如,如果卸载创建最后一个实例的 DLL)。
- 从C++实例化QML
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 如何在c++中为模板函数实例创建快捷方式
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 无法创建抽象类的实例
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 我收到以下错误:抛出'std::bad_alloc'实例后终止调用
- 建议在运行时将带有类实例的列表从c++导入qml
- 约束和显式模板实例化
- 完全删除 QApplication 实例并在另一个线程中重新创建它
- 创建真正的无头 QApplication 实例
- 多个 QApplication 实例
- 如何使用线程来实例化多个 QApplication
- 在主函数(库)外部实例化QApplication
- 确定系统是否可以实例化QApplication(GUI支持)
- 在Qt中隐藏和重新启动相同的QApplication实例