Results 1 to 12 of 12

Thread: Dynamically loading and unloading 2 qml files from cpp

  1. #1
    Join Date
    May 2015
    Posts
    26
    Thanks
    11
    Qt products
    Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Dynamically loading and unloading 2 qml files from cpp

    Hello,
    I have requirement to launch 2 different Qml files "mainwindow.qml" and "basic.qml" ,wheras both are independent of each other.
    Initially i need to launch qml window based on flag bSettingMainWindow, based on this i will be launching any one of the qml file.
    After launching I need to switch between these 2 qml files anytime. It should be like loading and unloading of "mainwindow.qml" and "basic.qml", based on the user action.
    Since because memory concern , i need load any of them at a time. and i dont want to play with visible true or false.
    Below is the code, I have written for to do this operation.
    whereas from this below code I can able to load any one of the qml file based on the flag bSettingMainWindow. and also after loading
    i can able to switch to another qml file window.
    Assume first I have launched in Mainwindow.qml then i clicked the mouse button over Rectangle of mainwindow.qml and moved to basic.qml and now if i click on the Rectangle of basic.qml it is not
    switching to mainwindow.qml.
    and vice versa.
    Only one time i can able to switch b/w these 2 . I want to switch multiple times.
    Below is the code , requesting to please provide your answers

    Qt Code:
    1. //** windowLoader.hpp **//
    2. class WindowLoader : public QObject{
    3. Q_OBJECT
    4. QQmlApplicationEngine loadQMlEngine;
    5.  
    6. public:
    7. explicit WindowLoader(QObject * parent = 0);
    8. void loadWindow();
    9.  
    10.  
    11. public slots:
    12. void loadMainWindow();
    13. void loadBasicWindow();
    14. void connectToMain(QObject *object = nullptr, const QUrl &url = QUrl(""));
    15. void connectToBasic(QObject *object = nullptr, const QUrl &url = QUrl(""));
    16.  
    17. private:
    18. };
    19.  
    20. //** windowLoader.cpp **//
    21. WindowLoader::WindowLoader(QObject *parent) : QObject(parent) {
    22.  
    23. }
    24.  
    25. void WindowLoader::loadWindow() {
    26. if(bSettingMainWindow){ //this will be from a internal flag, this check is only one time during launch
    27. connect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToBasic(QObject *, const QUrl &)),Qt::QueuedConnection);
    28. loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    29. loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/mainWindow.qml")));
    30. } else {
    31. connect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToMain(QObject *, const QUrl &)),Qt::QueuedConnection);
    32. loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    33. loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/basic.qml")));
    34. }
    35. }
    36.  
    37. void WindowLoader::connectToBasic(QObject *object, const QUrl &url) {
    38. if(object){
    39. connect(object, SIGNAL(switchToBasicSignal()), this, SLOT(loadBasicWindow()));
    40. }
    41. }
    42.  
    43. void WindowLoader::connectToMain(QObject *object, const QUrl &url) {
    44. if(object){
    45. connect(object, SIGNAL(switchToMainSignal()), this, SLOT(loadMainWindow()));
    46. }
    47. }
    48.  
    49. void WindowLoader::loadBasicWindow() {
    50. loadQMlEngine.rootObjects()[0]->deleteLater();
    51. loadQMlEngine.destroyed();
    52.  
    53. loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    54. loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/basic.qml")));
    55. }
    56.  
    57. void WindowLoader::loadMainWindow() {
    58. loadQMlEngine.rootObjects()[0]->deleteLater();
    59. loadQMlEngine.destroyed();
    60.  
    61. loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    62. loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/mainWindow.qml")));
    63.  
    64. }
    65.  
    66.  
    67. //** main.cpp **//
    68. int main( int argc, char *argv[] ) {
    69. QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    70. QApplication app(argc, argv);
    71. WindowLoader root;
    72. root.loadWindow();
    73. return app.exec();
    74. }
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. // ** mainWindow.qml **//
    2. ApplicationWindow {
    3. visible: true
    4. width: 1200
    5. height: 800
    6. title: qsTr("MainWindow")
    7.  
    8. signal switchToBasicSignal()
    9.  
    10. Rectangle {
    11. anchors.fill: parent
    12. MouseArea{
    13. anchors.fill: parent
    14. onClicked: {
    15. switchToBasicSignal()
    16. }
    17. }
    18. }
    19. }
    20.  
    21. //** basic.qml **//
    22. ApplicationWindow {
    23. visible: true
    24. width: 640
    25. height: 480
    26. title: qsTr("basic")
    27.  
    28. signal switchToMainSignal()
    29.  
    30. Rectangle {
    31. anchors.fill: parent
    32. MouseArea{
    33. anchors.fill: parent
    34. onClicked: {
    35. switchToMainSignal()
    36. }
    37. }
    38. }
    39. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,229
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    Since because memory concern , i need load any of them at a time. and i dont want to play with visible true or false.
    What evidence do you have that keeping two widget instances in memory at the same time is a "memory concern"? Or are you just optimizing based on an untested assumption? The amount of memory each window allocates is probably negligible compared to the memory other parts of your program are using.

    In any case, your WindowLoader:: loadWindow() method only connects to one of the two signals based on your startup flag, so once you switch to the other window, the signals it sends aren't connected to anything.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    May 2015
    Posts
    26
    Thanks
    11
    Qt products
    Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    Thank you for pointing out the issue. Reconnecting the signal resolved the issue.
    And yes I have tried on making visible true or false. It actually consuming almost 40mb more compare to loading and unloading like above.
    Thank you very much....

  4. #4
    Join Date
    May 2015
    Posts
    26
    Thanks
    11
    Qt products
    Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    I have observed one more issue in my code after implementation, actually switching b/w each window that is Basic and mainwindow is adding some extra size in memory .
    for example assume basic window is launched by default , and then i will switch to MainWindow and then i will switch back to basic window like that...., please find the memory consumption in task manager.
    Basic Window - 160 Mb
    Main Window - 200 Mb
    Basic Window - 170 Mb
    Main Window - 210 Mb
    Basic Window - 180 Mb
    Main Window - 220 Mb
    Basic Window - 190 Mb
    Main Window - 230 Mb
    It will keep on increase while switching until we close and reopen.
    Whereas in CPP side both consumes almost same data. But UI is little more graphical representation in main window at qml side.
    Where as above memory readings are taken by only pressing switching button in both the windows, and no cursor playing or keyboard playing on the window anywhere apart from switching button.
    for each switching i have taken 5 seconds break until memory comes and settle down with some fixed value.

    So I thought the memory consumption is increasing since i am not clearing some caches, so then I started consuming trimComponentCache() or clearComponentCache() in
    both the functions loadBasicWindow() and loadMainWindow() I have added this cache clearing functions immediately after destroyed(), even after that result is same.

    It should remain same b/w each switching. Suppose if the user performing any action in Basic or Advance window then we can say yes memory increases during some action . If we keep it idle it will come back to idle memory.
    Requesting to help me in fixing this memory issue which I can see in task manager.

  5. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,229
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    Task Manager is not a very accurate way of measuring memory use. It can be an indicator of a memory leak, but it can be misleading.

    In Windows, freeing memory (using free() in C or operator delete() in C++) does not shrink the size of your program in memory. The freed memory is not released back to the OS for use by other programs, instead it is freed to the local heap used by your program so that it can be reused within your program. So the typical behavior for a leak-free C++ program if you watch Task Manager is that it will grow to a certain size and then stay there. It doesn't shrink even if it frees all of the memory allocated from the heap.

    However, if you program allocates and frees varying size chunks of memory repeatedly, the heap can become fragmented to the point that there is not enough contiguous free memory available for the next allocation, so the program has to ask for more heap from Windows. So even though there is no leak, the program continues to grow.

    QML is implemented in C++ on top of Qt's C++ libraries, as far as I know, so the same rules should apply. If you are using pure QML in your program, then the memory leak is either within the QML implementation itself or in the way you are using it.

    I think that what is likely happening with your program is that each time you swap windows, QML must ask for more memory because it is unable to find enough contiguous free memory to create the new window and all of its widgets. If you are loading the window from QML source each time you switch, then the QML engine must go through the loading, parsing, and byte code compilation each time you switch, and that probably consumes some memory. The QML engine doesn't "remember" that you are using the same two files over and over again; each one is a brand new file as far as it is concerned.

    These kinds of problems are why I advised against doing this in my first answer to your thread.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  6. The following user says thank you to d_stranz for this useful post:

    gowreesh (1st June 2020)

  7. #6
    Join Date
    May 2015
    Posts
    26
    Thanks
    11
    Qt products
    Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    Yes I agree playing with Visibility, resolved this issue of memory consumption as per your first answer.
    and also thanks for this detailed explanation on memory consumption.

    Once after changing my code to play with visibility I am facing one issue that is previously made visible false window getting settled backside(beyond some other opened application window) after a first launch, and it will not come on top if i make that window as visible true. For Every switch it will be settled backside in the screen , beyond some other application.
    I tried changing it to "show" and "hide" by replacing visible true or false. and also I have tried using raise() and activatewindow() even after that i am facing the same issue.
    Requesting to please help me out how to fix this issue.

  8. #7
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,229
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    If I understand your code correctly, your MainWindow and BaseWindow are both top-level windows (they have no "parent" - they are children of the desktop window). This makes them "sibling" windows, and so you may be able to use the QWidget::stackUnder() method. When you make BaseWindow visible, call MainWindow->stackUnder( BaseWindow ) and vice-versa. I don't know if it will work, but it is worth trying.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  9. The following user says thank you to d_stranz for this useful post:

    gowreesh (2nd June 2020)

  10. #8
    Join Date
    May 2015
    Posts
    26
    Thanks
    11
    Qt products
    Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    Thank you for the reply.

    I am using QQuickWindow and i am not using QWidget.
    I have created a custom window i.e "class CustomWindow : public QQuickWindow {...}"
    This CustomWindow only i have used in QML side. and sorry in my first thread i have mentioned ApplicationWindow
    So only I am not able to access or pass QQuickWindow to QWidget::stackUnder(QWidget *w).
    Requesting you to please let me know if there is any other solution.

  11. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,229
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    Sorry, I don't have any other ideas. I do not have much experience with QWindow and QML, so maybe someone else here can give some advice.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  12. The following user says thank you to d_stranz for this useful post:

    gowreesh (3rd June 2020)

  13. #10
    Join Date
    May 2015
    Posts
    26
    Thanks
    11
    Qt products
    Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    its OK and thank you very much for replying.
    If i don't find any solution i need to go back to that previous method of loading and unloading concept even if it consumes more memory since I don't have any other option.

    Could anyone please help me out for the issue I have mentioned above.?????

  14. #11
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,229
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    Could anyone please help me out for the issue I have mentioned above.?????
    Maybe you should post your current code for loading the windows and switching between them. I am sure it is not the same as the code in your first post and might contain some clues about why it isn't working correctly.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  15. The following user says thank you to d_stranz for this useful post:

    gowreesh (4th June 2020)

  16. #12
    Join Date
    May 2015
    Posts
    26
    Thanks
    11
    Qt products
    Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Dynamically loading and unloading 2 qml files from cpp

    Ya sure , I will put my latest code here.
    I have designed this below code like if the user launches the application for the first time , then the application will load Mainwindow.qml or basic.qml based on the flag "bSettingMainWindow" .
    Next time based on the switch button click from application will load another window (other than first one) and making the first launched qml window visible false.
    Once both of them launched once, then 2 windows will play with visibility true or false on click of switch button or signal is emitted.
    This below code is working perfectly fine except the window is not coming on top after making visible true. I have tried using raise() and activatewindow() even after that i am facing the same issue.
    Please find the code below


    Qt Code:
    1. //CustomWindow.h
    2. class CustomWindow : public QQuickWindow {
    3. //Custom QQuick window used in QML
    4. }
    5.  
    6.  
    7.  
    8. //** windowLoader.hpp **//
    9. class WindowLoader : public QObject{
    10. Q_OBJECT
    11. QQmlApplicationEngine loadQMlEngine;
    12.  
    13. public:
    14. explicit WindowLoader(QObject * parent = 0);
    15. void loadWindow();
    16.  
    17.  
    18. public slots:
    19. void loadMainWindow();
    20. void loadBasicWindow();
    21. void connectToMain(QObject *object = nullptr, const QUrl &url = QUrl(""));
    22. void connectToBasic(QObject *object = nullptr, const QUrl &url = QUrl(""));
    23.  
    24. private:
    25. };
    26.  
    27.  
    28.  
    29. //** windowLoader.cpp **//
    30. WindowLoader::WindowLoader(QObject *parent) : QObject(parent) {
    31.  
    32. }
    33.  
    34. //This function will be called only one time during launch
    35. void WindowLoader::loadWindow() {
    36. if(bSettingMainWindow){ //this will be from a internal flag, this check is only one time during launch
    37. connect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToBasic(QObject *, const QUrl &)),Qt::QueuedConnection);
    38. loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    39. loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/mainWindow.qml")));
    40. m_iMainWindowIndex = 0;
    41. m_iBasicWindowIndex = 1;
    42. } else {
    43. connect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToMain(QObject *, const QUrl &)),Qt::QueuedConnection);
    44. loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    45. loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/basic.qml")));
    46. m_iMainWindowIndex = 1;
    47. m_iBasicWindowIndex = 0;
    48. }
    49. }
    50.  
    51. void WindowLoader::connectToBasic(QObject *object, const QUrl &url) {
    52. if(object){
    53. connect(object, SIGNAL(switchToBasicSignal()), this, SLOT(loadBasicWindow()));
    54. }
    55. }
    56.  
    57. void WindowLoader::connectToMain(QObject *object, const QUrl &url) {
    58. if(object){
    59. connect(object, SIGNAL(switchToMainSignal()), this, SLOT(loadMainWindow()));
    60. }
    61. }
    62.  
    63. void WindowLoader::loadBasicWindow() {
    64.  
    65. if(loadQMlEngine.rootObjects().size() <= 2) {
    66. disconnect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToBasic(QObject *, const QUrl &)));
    67. }
    68.  
    69. if(loadQMlEngine.rootObjects().size() < 2) {
    70. connect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToMain(QObject *, const QUrl &)),Qt::QueuedConnection);
    71. loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    72. loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/basic.qml")));
    73. loadQMlEngine.rootObjects()[m_iMainWindowIndex]->setProperty("visible",false);
    74. } else {
    75. //QMetaObject::invokeMethod(loadQMlEngine.rootObjects()[m_iBasicWindowIndex],"show");
    76. //QMetaObject::invokeMethod(loadQMlEngine.rootObjects()[m_iMainWindowIndex],"hide");
    77. loadQMlEngine.rootObjects()[m_iBasicWindowIndex]->setProperty("visible",true);
    78. loadQMlEngine.rootObjects()[m_iMainWindowIndex]->setProperty("visible",false);
    79. }
    80. }
    81.  
    82. void WindowLoader::loadMainWindow() {
    83.  
    84. if(loadQMlEngine.rootObjects().size() <= 2) {
    85. disconnect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToMain(QObject *, const QUrl &)));
    86. }
    87.  
    88. if(loadQMlEngine.rootObjects().size() < 2) {
    89. connect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToBasic(QObject *, const QUrl &)),Qt::QueuedConnection);
    90. loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    91. loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/mainWindow.qml")));
    92. loadQMlEngine.rootObjects()[m_iBasicWindowIndex]->setProperty("visible",false);
    93. } else {
    94. //QMetaObject::invokeMethod(loadQMlEngine.rootObjects()[m_iBasicWindowIndex],"hide");
    95. //QMetaObject::invokeMethod(loadQMlEngine.rootObjects()[m_iMainWindowIndex],"show");
    96. loadQMlEngine.rootObjects()[m_iBasicWindowIndex]->setProperty("visible",false);
    97. loadQMlEngine.rootObjects()[m_iMainWindowIndex]->setProperty("visible",true);
    98. }
    99. }
    100.  
    101.  
    102. //** main.cpp **//
    103. int main( int argc, char *argv[] ) {
    104. QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    105. QApplication app(argc, argv);
    106. qmlRegisterType<CustomWindow>("CNQml", 1, 0, "CustomWindow");
    107. WindowLoader root;
    108. root.loadWindow();
    109. return app.exec();
    110. }
    To copy to clipboard, switch view to plain text mode 


    Qt Code:
    1. // ** mainWindow.qml **//
    2. CustomWindow {
    3. visible: true
    4. width: 1200
    5. height: 800
    6. title: qsTr("MainWindow")
    7.  
    8. signal switchToBasicSignal()
    9.  
    10. Rectangle {
    11. anchors.fill: parent
    12. MouseArea{
    13. anchors.fill: parent
    14. onClicked: {
    15. switchToBasicSignal()
    16. }
    17. }
    18. }
    19. }
    20.  
    21. //** basic.qml **//
    22. CustomWindow {
    23. visible: true
    24. width: 640
    25. height: 480
    26. title: qsTr("basicwindow")
    27.  
    28. signal switchToMainSignal()
    29.  
    30. Rectangle {
    31. anchors.fill: parent
    32. MouseArea{
    33. anchors.fill: parent
    34. onClicked: {
    35. switchToMainSignal()
    36. }
    37. }
    38. }
    39. }
    To copy to clipboard, switch view to plain text mode 

Similar Threads

  1. Active Qt: crash while unloading Qt Core DLL
    By ivigasin in forum Qt Programming
    Replies: 4
    Last Post: 2nd April 2015, 12:58
  2. Dynamically loading libraries
    By januszmk in forum Newbie
    Replies: 5
    Last Post: 4th February 2013, 17:44
  3. Remove library after unloading
    By mvw in forum Qt Programming
    Replies: 1
    Last Post: 23rd April 2010, 11:06
  4. Dynamically Loading UI With Unspecified Slots
    By spraff in forum Qt Programming
    Replies: 2
    Last Post: 11th April 2010, 11:46
  5. Dynamically Loading a QMainWindow?
    By natron in forum Newbie
    Replies: 10
    Last Post: 21st July 2006, 02:15

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.