多个QApplication实例

时间:2017-09-19 15:14:54

标签: c++ qt singleton qapplication

我想知道在同一个过程中有多个QApplication / QCoreApplication个实例有什么影响(问题),以及如何解决有关它的一些问题。

方案如下:我想在开源第三方应用程序上创建一个包装器,以便将其转换为可嵌入的小部件作为可选插件(该应用程序基本上由一个{{1}组成。基于接口)。

这样的项目很大程度上依赖于QMainWindow派生类,但主要是因为它被用作已经存在的单例。我能够修改代码(为了将QCoreApplication暴露为可嵌入的小部件,我必须这样做),尽管对于该项目的复杂性我不能简单地删除父类。

因此,最终的应用程序将拥有自己的QMainWindow(在启动时创建),然后可选择加载上述插件(从而创建第二个QApplication)。只有第一个(主要)QCoreApplication用于事件循环(QApplication)。

我知道QCoreApplication::exec()是单身人士的事实。在我的测试中,单例总是指向最后创建的实例:

QCoreApplication

输出

  

QObject的(为0x0)

     

QApplication(0x6f9400,name =“test”)

     

在QCoreApplication中ASSERT失败:“应该只有一个应用程序对象”,文件kernel \ qcoreapplication.cpp,第595行

     

TheOtherQApplication(0x2550dc0,name =“test”)

     

TheOtherQApplication(0x2550dc0,name =“test”)TheOtherQApplication(0x2550dc0,name =“test”)

可以看出,在创建第二个qDebug() << qApp; auto app1 = new QApplication(argc, argv); qDebug() << qApp; auto app2 = new TheOtherQApplication(argc, argv); qDebug() << qApp; 之后,它将替换全局实例。有什么方法可以解决这个问题吗?由于插件是可选的,明显的答案(在第二位加载主QApplication)不是一个合适的选择。

此外,有多个QApplication个实例还有其他含义吗?或者都与事件循环(已检查)和单例?

相关

注意:这是一个基于Qt 4.7的项目,因为第三方依赖尚未完全更新。计划在一年左右的时间内迁移到最新版本,但目前我必须处理4.7。

顺便说一句,我已经回顾了几个相关问题,包括this one,但这并没有提供任何有用的信息。

1 个答案:

答案 0 :(得分:2)

嗯,据我所知,使用两个或多个Q*Application s(QCoreApplicationQGuiApplicationQApplication)意味着:

  1. 创建第二个应用程序(或更多)时,断言在调试模式下失败。在发布模式下没有崩溃。

  2. Q*Application的每个实例化都会更新单例(即qApp将始终指向最后一个实例)。

  3. 应用程序名称和版本等全局属性将沿实例传输并覆盖以前的属性。

  4. 连接到Q*Application的插槽的任何信号都会调用单例的插槽,即使在创建最新实例之前已连接。

  5. 只会调用连接到最新Q*Application信号的插槽(它们不会转移到新实例)。

  6. 创建新Q*Application个实例时,转换器不会被转移。

  7. 如果最后一个Q*Application被销毁,那么单例变为空(它不会回退到前一个实例)。

  8. 您可以使用以下代码测试这些功能并切换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

    的结果
      

    QCoreApplication(0xfafb74)QCoreApplication(0xfafb74)

         

    a1.applicationName()=“a1”

         

         

         

    来自a1的Hello world!

    两个Q*Application

    的结果
      

    QCoreApplication(0xbefb2c)QCoreApplication(0xbefb2c)

         

    a1.applicationName()=“a1”

         

    QCoreApplication中的ASSERT失败:“应该只有一个应用程序对象”,文件######## \ qtbase \ src \ corelib \ kernel \ qcoreapplication.cpp,第769行

         

    QCoreApplication(0xbefb1c)QCoreApplication(0xbefb2c)QCoreApplication(0xbefb1c)

         

    a2.applicationName()=“a2”

         

    a1.applicationName()=“a2”

         

         

         

    来自a2的Hello world!

    测试第7点时,退出a2语句时会销毁if。在这种情况下,每次调用Q*Application方法都会引发警告并且不会执行(它们不会崩溃,也不会断言断言)。即使从上一个应用程序调用它也会发生:a1.installTranslator(&tr1);

      

    QApplication :: installTranslator:请先实例化QApplication对象

    注意:使用Visual Studio 2010进行测试.Qt版本为4.7和5.6.1-1,两者结果相同

    更新: https://github.com/cbuchart/stackoverflow/blob/master/46304070-multiple-qapplication-instances/main.cpp

    提供了此答案的更清晰的代码版本

    在评论之后,此代码还测试在销毁所有QApplication个对象然后再次创建时会发生什么。结果:正如预期的那样,没有任何特殊情况发生,似乎没有副作用。

    <强>结论

    似乎有可能与两个或更多Q*Application一起考虑这些要点,更为关键的事实是,除了最后Q*Application之外的任何事情,信号的连接都会丢失和翻译没有安装。此外,如果最后一个实例被销毁,那么没有可用的应用程序,因此您应该处理这些情况(例如,如果卸载创建最后一个实例的DLL)。