Results 1 to 8 of 8

Thread: Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

  1. #1
    Join Date
    Jun 2014
    Posts
    5
    Thanks
    1
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    MacOS X Unix/X11

    Default Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

    So, I'm trying to develop a plugin model for my app. Idea is simple:

    1. Have an interface that all plugins implement. I load/discover plugins at runtime.
    2. My host application would have dedicated areas in the UI, within which, these plugins would display their UI.


    The excellent Plug & Paint tutorial covers step (1) above pretty well. I have created an interface, developed an example plugin and the host is able to discover, load and invoke methods in them at runtime.

    For step (2), I have figured out how to have the plugin's UI (described via. QML) appear in the parents user interface (also described via. QML). I can use a QML Loader component in the main application QML, to load an external QML file into specific areas of the host application UI by setting the Loader.source at runtime. My main.qml looks like this:

    Qt Code:
    1. Rectangle {
    2. Item {
    3. width: card_1_1.width
    4. height: card_1_1.height
    5. Loader {
    6. id: loader
    7. source: <will be set dynamically>
    8. }
    9. }
    To copy to clipboard, switch view to plain text mode 

    However, I do not know how to make the plugin's C++ model available to the plugin's QML.

    In a normal non-plugin scenario, I would make my model available to QML using

    Qt Code:
    1. QQuickView.rootContext()->setContextProperty(...)
    To copy to clipboard, switch view to plain text mode 

    I do not know how to do this when the model I wish to expose will be discovered by the main app at runtime. My plugin interface looks like this:

    Qt Code:
    1. class IMediaSource : public QObject
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. virtual ~IMediaSource() {}
    7. virtual QObject* getModel() = 0;
    8. virtual QString getQMLPath() = 0;
    9. };
    To copy to clipboard, switch view to plain text mode 

    I wish to expose the QObject* returned by IMediaSource::getModel() to the plugin's QML which is returned by IMediaSource::getQMLPath().

    My main app QML is loaded like so:

    Qt Code:
    1. QGuiApplication app(argc, argv);
    2. QQuickView viewer;
    3.  
    4. viewer.setSource(QUrl("qrc:///..."));
    5. viewer.showExpanded();
    6. return app.exec();
    To copy to clipboard, switch view to plain text mode 

    What I have tried:
    I've tried to use the following on the Loader elements' instance:

    Qt Code:
    1. QQmlContext *context = mEngine->contextForObject(item); // item is an instance of Loader I'm interested in
    2. if (context != NULL)
    3. {
    4. context->setContextProperty("cardPlugin", this);
    5. context->setContextObject(this);
    6. }
    To copy to clipboard, switch view to plain text mode 

    Both methods return:

    Qt Code:
    1. QQmlContext: Cannot set property on internal context.
    2. QQmlContext: Cannot set context object for internal context.
    To copy to clipboard, switch view to plain text mode 

    Workaround:
    One solution would be to iterate over all plugins and use QQuickView.rootContext()->setContextProperty("xxx", IMediaSource->getModel()) to pass on the models to the application QML's root context so they're available to all QML's loaded via. Loader.
    This apart from being clumsy also has the problem of name collisions. Two plugins could expose their models using the same name.

    I'm looking for a more elegant solution. Ideas are welcome.
    Last edited by gmanish; 1st June 2014 at 19:33. Reason: updated contents

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

    You could register a QML singleton type using a plugin specific namespace and then let the QML code "instantiate" the model.

    Cheers,
    _

  3. #3
    Join Date
    Jun 2014
    Posts
    5
    Thanks
    1
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    MacOS X Unix/X11

    Default Re: Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

    Thanks for your time on this. Do you mean using qmlRegisterType<X>("com.mycompany.X", 1, 0, "X")?

  4. #4
    Join Date
    Jun 2014
    Posts
    5
    Thanks
    1
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    MacOS X Unix/X11

    Default Re: Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

    Quote Originally Posted by anda_skoa View Post
    You could register a QML singleton type using a plugin specific namespace and then let the QML code "instantiate" the model.

    Cheers,
    _
    Thanks for your time on this. Do you mean using qmlRegisterType<X>("com.mycompany.X", 1, 0, "X")?

  5. #5
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

    I meant qmlRegisterSingletonType()

    However, there might be another option that is closer to what you tried.
    I assume you are using QQmlComponent to create the UI. You can pass a context to its create method.
    E.g. something like this (not tested)
    Qt Code:
    1. QQmlContext *pluginContext = new QQmlContext(view.engine());
    2. pluginContext->setContextProperty("model", plugin->getModel());
    3.  
    4. QQmlComponent component(view.engine(), plugin->getQMLPath());
    5. component.create(pluginContext);
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

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

    gmanish (3rd June 2014)

  7. #6
    Join Date
    Jun 2014
    Posts
    5
    Thanks
    1
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    MacOS X Unix/X11

    Default Re: Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

    Quote Originally Posted by anda_skoa View Post
    I meant qmlRegisterSingletonType()
    However, there might be another option that is closer to what you tried.
    I assume you are using QQmlComponent to create the UI. You can pass a context to its create method.
    _
    I'm using the following to create the main UI (i.e. loading main.qml). It is in this view that I want to load the plugins QML components:

    Qt Code:
    1. QGuiApplication app(argc, argv);
    2. QQuickView viewer;
    3.  
    4. viewer.setSource(QUrl("qrc:///..."));
    5. viewer.showExpanded();
    6. return app.exec();
    To copy to clipboard, switch view to plain text mode 

    Also, I found this thread that seems pertinent to my problem. However, I cannot fully comprehend it. Specifically, what are window1, window2 & window3 in the given solution.

    How do I create my main UI using QQmlComponent and later add the QQmlComponent created using the method you specify to the main UI's QQmlComponent? I found a possible implementation here. But when I run it, I get a crash because:

    Qt Code:
    1. QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
    To copy to clipboard, switch view to plain text mode 

    evaluates to window = NULL
    Last edited by gmanish; 3rd June 2014 at 20:47.

  8. #7
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

    Quote Originally Posted by gmanish View Post
    Qt Code:
    1. QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
    To copy to clipboard, switch view to plain text mode 

    evaluates to window = NULL
    Is your top level item a Window element? If not, cast it to whatever you are using, e.g. QQuickItem

    Cheers,
    _

  9. #8
    Join Date
    Jun 2014
    Posts
    5
    Thanks
    1
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    MacOS X Unix/X11

    Default Re: Load a portion of UI from a plugin QML (dynamic GUI) and expose C++ models to it

    Mostly for future visitors, I did manage to get this working. Following is a tiny code fragment that highlights the solution:

    Qt Code:
    1. QQmlContext* pluginContext = new QQmlContext(mView->engine());
    2. QmlComponent* component(new QQmlComponent(mView->engine(), "/PATH/TO/QML.qml"));
    3. QObject* compRoot = NULL;
    4.  
    5. pluginContext->setContextProperty("model", myModelObject);
    6. compRoot = component->create(pluginContext);
    7. if (component->isReady()) {
    8. QQuickItem* item = qobject_cast<QQuickItem*>(compRoot);
    9. QPointF point(posHelper.getLeft(), posHelper.getTop());
    10. QSizeF size(posHelper.getWidth(), posHelper.getHeight());
    11.  
    12. item->setParentItem(mRoot); // The item pointer obtained through QQuickView.rootObject
    13. item->setPosition(point);
    14. item->setSize(size);
    15.  
    16. qDebug() << "Card (" << posHelper.getCurRow() << ", " << posHelper.getCurCol() << "): " <<
    17. "(" << point.x() << ", " << point.y() << ") - " <<
    18. "(" << size.width() << ", " << size.height() << ")";
    19. return component;
    20. } else {
    21. qWarning() << "Failed to create component from C++:" << component->errorString();
    22. }
    23. }
    To copy to clipboard, switch view to plain text mode 

    The thing that did the trick was:

    Qt Code:
    1. item->setParentItem(mRoot)
    To copy to clipboard, switch view to plain text mode 

  10. The following user says thank you to gmanish for this useful post:

    anda_skoa (17th June 2014)

Similar Threads

  1. Link to plugin as dynamic lib in another plugin
    By alizadeh91 in forum Installation and Deployment
    Replies: 5
    Last Post: 16th December 2012, 22:16
  2. Replies: 1
    Last Post: 23rd June 2011, 23:09
  3. Dynamic load QT Plugin - symbol lookup error
    By qlands in forum Qt Programming
    Replies: 4
    Last Post: 2nd May 2010, 19:37
  4. Load objects from dynamic library
    By Trok in forum Qt Programming
    Replies: 10
    Last Post: 17th July 2009, 20:04

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.