Results 1 to 10 of 10

Thread: dynamically loaded components cannot reference types

  1. #1
    Join Date
    Jul 2014
    Location
    Gelnhausen, Germany
    Posts
    21
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default dynamically loaded components cannot reference types

    Hello,

    we have a component implemented in a plugin, which uses Loader to dynamicaly instantiate other components. Example:

    Qt Code:
    1. import ourcomponent 1.0
    2.  
    3. Rectangle {
    4. MyComponent {
    5. loadthis: "someother.qml"
    6. }
    7. }
    To copy to clipboard, switch view to plain text mode 

    the ourcomponent namespace and the MyComponent type are defined in a plugin. MyComponent uses Loader to instantiate the component defined in "someother.qml".

    Now it turns out that while this works well for simple cases where "someother.qml" is a self-contained component (only using stuff from the QtQuick namespace), we are facing problems when "someother.qml" references other local QML types from the same project. In that case we see messages like "AnotherItem is not a type", even though AnotherItem.qml is located right alongside the someother.qml file. It seems that components loaded from within the plugin cannot see the types defined in the calling project. What can we do?

    Heres the example someother.qml file:
    Qt Code:
    1. import QtQuick 2.0
    2.  
    3. Rectangle {
    4. width: 100
    5. height: 62
    6.  
    7. AnotherItem {} //visible at dev time in QtCreator, but not at runtime
    8. }
    To copy to clipboard, switch view to plain text mode 

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

    Default Re: dynamically loaded components cannot reference types

    That should work, at least this small example does

    main.qml
    Qt Code:
    1. import QtQuick 2.0
    2.  
    3. Rectangle {
    4. width: 200
    5. height: 200
    6. color: "lightsteelblue"
    7.  
    8. Loader {
    9. source: "loaded.qml"
    10. }
    11. }
    To copy to clipboard, switch view to plain text mode 
    loaded.qml
    Qt Code:
    1. import QtQuick 2.0
    2.  
    3. Rectangle {
    4. width: 40
    5. height: 40
    6. color: "red"
    7.  
    8. LocalItem {
    9. anchors.centerIn: parent
    10. width: 20
    11. height: 20
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 
    LocalItem.qml
    Qt Code:
    1. import QtQuick 2.0
    2.  
    3. Rectangle {
    4. color: "yellow"
    5. }
    To copy to clipboard, switch view to plain text mode 

    You could try importing the directory
    Qt Code:
    1. import "." as Local
    2.  
    3. Local.AnotherItem {
    4. }
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  3. #3
    Join Date
    Jul 2014
    Location
    Gelnhausen, Germany
    Posts
    21
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: dynamically loaded components cannot reference types

    of course, what you show does work, as long as all components are located withing the same module (or application).

    However, in our scenario, the code that uses the Loader is located in a plugin, and the loaded QML is from an application that uses the plugin. All QML resources (both in the plugin and in the application) are stored as resources.

    BTW, heres what I see if I follow your import "." suggestion:

    Qt Code:
    1. qrc:ProjectData.qml:74:5: Type Local.CustomerGrid2 unavailable
    2. ./CustomerGrid2.qml: Network error
    To copy to clipboard, switch view to plain text mode 
    interesting, eh?

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

    Default Re: dynamically loaded components cannot reference types

    Is CustomerGrid2.qml in the same resource folder as the QML file being loaded?

    Have you tried explicitly passing the qrc URL to the loader?

    Cheers,
    _

  5. #5
    Join Date
    Jul 2014
    Location
    Gelnhausen, Germany
    Posts
    21
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: dynamically loaded components cannot reference types

    yes, CustomerGrid2.qml is located right alongside the QML being loaded. Changing the Loader.source to a "qrc:" URL doesn't change anything.

    However, I have meanwhile made progress. After giving up on the attempt of creating a plugin, I copied all the QML files into a subdirectory in the project that uses the components. I then edited the QML files that use the components, changing the import moduleid 1.0 to a directory import import "subdirectory". Alas, this time even the initially loaded QML was not found, BUT the error message gave a clue:
    qrc:///navigation/t1.qml: File not found
    After adding a "/" to the QML reference, the file was found and worked normally even with nested components.

    I then returned to the plugin code, and tried the "/" as well. And lo behold - even though the error messages had been different (and totally weird at times), the solution worked just the same

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: dynamically loaded components cannot reference types

    Quote Originally Posted by doulos View Post
    Hello,

    we have a component implemented in a plugin, which uses Loader to dynamicaly instantiate other components. Example:

    Qt Code:
    1. import ourcomponent 1.0
    2.  
    3. Rectangle {
    4. MyComponent {
    5. loadthis: "someother.qml"
    6. }
    7. }
    To copy to clipboard, switch view to plain text mode 

    the ourcomponent namespace and the MyComponent type are defined in a plugin. MyComponent uses Loader to instantiate the component defined in "someother.qml".

    Now it turns out that while this works well for simple cases where "someother.qml" is a self-contained component (only using stuff from the QtQuick namespace), we are facing problems when "someother.qml" references other local QML types from the same project. In that case we see messages like "AnotherItem is not a type", even though AnotherItem.qml is located right alongside the someother.qml file. It seems that components loaded from within the plugin cannot see the types defined in the calling project. What can we do?

    Heres the example someother.qml file:
    Qt Code:
    1. import QtQuick 2.0
    2.  
    3. Rectangle {
    4. width: 100
    5. height: 62
    6.  
    7. AnotherItem {} //visible at dev time in QtCreator, but not at runtime
    8. }
    To copy to clipboard, switch view to plain text mode 
    All paths are by default resolved relatively to the path of the calling component. Therefore if your plugin tries to load url called "someother.qml" then by default this will be resolved relative to where the plugin is located. If you want to resolve the path relative to the context where you pass "someother.qml" then use Qt.resolvedUrl:

    javascript Code:
    1. import ourcomponent 1.0
    2.  
    3. Rectangle {
    4. MyComponent { loadThis: Qt.resolvedUrl("someother.qml") }
    5. }
    To copy to clipboard, switch view to plain text mode 
    If that doesn't work then it is always an option to pass not a URL but rather a component definition to your component:

    javascript Code:
    1. import ourcomponent 1.0
    2.  
    3. Rectangle {
    4. MyComponent { loadThis: Component { url: "someother.qml" } }
    5. }
    To copy to clipboard, switch view to plain text mode 

    Of course you will then need to teach MyComponent to expect a Component instead (or aside to) a url.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  7. #7
    Join Date
    Jul 2014
    Location
    Gelnhausen, Germany
    Posts
    21
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: dynamically loaded components cannot reference types

    All paths are by default resolved relatively to the path of the calling component. Therefore if your plugin tries to load url called "someother.qml" then by default this will be resolved relative to where the plugin is located. If you want to resolve the path relative to the context where you pass "someother.qml" then use Qt.resolvedUrl:
    Please notice that I was not talking about "paths" not being resolved correctly. When I passed "someother.qml" to the plugin, the component was found correctly, although it resided in the calling application. However, components nested inside were not (except those from the global namespace). I tried the Qt.resolvedUrl recipe, and it did the same as prefixing with "/" - now the component was loaded and subcomponents also. It was a tough day, however, tracking this down, and I cannot say that I can make sense of it. I dint try the Component way, but assume that it would work, also.

    Thanks for yout input, anyway.

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: dynamically loaded components cannot reference types

    Quote Originally Posted by doulos View Post
    Please notice that I was not talking about "paths" not being resolved correctly.
    In my opinion you were, e.g. here:

    we are facing problems when "someother.qml" references other local QML types from the same project.
    I'm pretty sure "other local QML types" are defined in files bearing some kind of path relations to the calling file.

    . I tried the Qt.resolvedUrl recipe, and it did the same as prefixing with "/" - now the component was loaded and subcomponents also.
    Because that's basically what Qt.resolvedUrl() does -- it turns relative paths into absolute ones.

    It was a tough day, however, tracking this down, and I cannot say that I can make sense of it.
    It is easy once you understand why this happens. Essentially this provides locality and proper encapsulation as well as a kind of security of an application. Imagine there is a "MyComponent" type in your app defined in a file which is called by your application file called MyApplication.qml. Now you can take all your files, put them into a subdirectory of another project and instantiate by calling MyApplication {}. Now imagine this "external" application also defines a type called MyComponent. If there was no locality, you'd have a clash where the "internal" application could instantiate MyComponent defined in the external application instead of its own. This would inhibit security as well (injecting a component definition into the contained namespace). Resolving paths relative to the calling document prevents these problems.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #9
    Join Date
    Jul 2014
    Location
    Gelnhausen, Germany
    Posts
    21
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: dynamically loaded components cannot reference types

    Resolving paths relative to the calling document prevents these problems.
    well, I still am not convinced. In my non-plugin scenario, I had the components in a subdirectory. If I directly referenced the root component via directory import, it was found and all nested types as well. If I load the root component through a Loader, suddenly nested components are NOT found. Again:

    Qt Code:
    1. main.qml
    2. navigation
    3. Reusable.qml <-- uses Nested
    4. Nested.qml
    To copy to clipboard, switch view to plain text mode 

    now, if in main.qml I simply do a directory import and use the Reusable type, everything works well:
    Qt Code:
    1. import "navigation"
    2. Rectangle {
    3. Reusable {
    4. }
    5. }
    To copy to clipboard, switch view to plain text mode 
    However, if I load Reusable dynamically
    Qt Code:
    1. Rectanngle {
    2. Loader {
    3. source: "navigation/Reusable.qml"
    4. }
    5. }
    To copy to clipboard, switch view to plain text mode 
    I see an error message that file "navigation/Nested.qml" was not found. In a plugin scenario, the message simply says "Nested is not a type". If this makes sense somehow, it is still almost impossible IMO to find a smooth path from that message to a solution, which may mean that the concepts are not that clear and plausible, or at least not well explained. As I said, it took a day of desperate poking for me.

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,376
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    4
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: dynamically loaded components cannot reference types

    With the first approach you are effectively importing all types defined in "navigation" into the scope of the current document (in other words "navigation" becomes a sort of plugin that contains documents present in that directory). In the second approach you get regular path resolution. Whether this works or not, depends on the scope of the containing document (i.e. the location of the file containing the last snippet).

    If you want to load "Reusable" from within main.qml, you will refer to "navigation/Reusable.qml" or "Reusable.qml" having imported "navigation" module. If you want to load "Reusable" from Nested.qml, you will have to refer to Reusable.qml directly.
    Last edited by wysota; 16th August 2014 at 16:21.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. QML list and dynamically loaded content
    By matsukan in forum Qt Quick
    Replies: 5
    Last Post: 21st November 2013, 09:41
  2. Layering components with QT
    By David Krutsko in forum Newbie
    Replies: 0
    Last Post: 27th October 2010, 00:33
  3. Replies: 4
    Last Post: 10th December 2009, 17:37
  4. ui components
    By addu in forum Qt Programming
    Replies: 0
    Last Post: 17th September 2009, 15:49
  5. Q_ARG with C++ reference types
    By RichardNixon in forum Qt Programming
    Replies: 1
    Last Post: 6th August 2008, 10:11

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
  •  
Qt is a trademark of The Qt Company.