Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Inline component in a component
Qt 6.11 is out! See what's new in the release blog

Inline component in a component

Scheduled Pinned Locked Moved QML and Qt Quick
23 Posts 4 Posters 28.9k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    giesbert
    wrote on last edited by
    #13

    Hi all,

    I red a bit about "QML and component":http://doc.qt.nokia.com/4.7/qml-component.html :

    bq. Defining a Component is similar to defining a QML document. A QML document has a single top-level item that defines the behaviors and properties of that component, and cannot define properties or behaviors outside of that top-level item. In the same way, a Component definition contains a single top level item (which in the above example is a Rectangle) and cannot define any data outside of this item, with the exception of an id (which in the above example is redSquare).

    For me that sounds like:

    When you instantiate a component TestPage and a file Testpage.qml exists, the object inside the component definition is created. This means a component of type testPage which is located inside a qml file, ...

    This is definitly a recursion, if you start instatiation.

    So for me it looks like this in qml:

    @
    item {
    id: item1 // per definition in docs not needed !
    Component {
    id: inneritem
    TestPage {
    }
    }
    }
    @

    is the same as this in C++

    @
    class Foo
    {
    public:
    Foo() {}

    Foo innerItem;
    

    };
    @

    innerItem is not a pointer, that might be instantiated somewhen. Its the object itself which is created as component!

    Nokia Certified Qt Specialist.
    Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

    1 Reply Last reply
    0
    • ? Offline
      ? Offline
      A Former User
      wrote on last edited by
      #14

      thx for you reply.

      bq. Notice that while a Rectangle by itself would be automatically rendered and displayed, this is not the case for the above rectangle because it is defined inside a Component. The component encapsulates the QML elements within, as if they were defined in a separate QML file, and is not loaded until requested (in this case, by the two Loader objects).

      Extracted from the same page.

      So, as far as i understand, a Component is just a qml file which i define a new component, as the doc says. The doc explicitly tell the component is not rendered until is explicitly load. Therefore, it really look likes a c++ pointer you assigned when you wanted to.

      Actually, it's really the "recursive instantiation" that bugs me. The more i look at it the more i feel is just a bad check in the qml engine.
      The doc says a Component is a qml file. So a component definition not an instantiation.

      1 Reply Last reply
      0
      • ? Offline
        ? Offline
        A Former User
        wrote on last edited by
        #15

        But once YOUR TestPage is instantiated, it would instantiate another TestPage within the first one!

        This IS recursion, believe it or not.

        The compiler is always right™.

        1 Reply Last reply
        0
        • G Offline
          G Offline
          giesbert
          wrote on last edited by
          #16

          [quote author="Volker" date="1301910295"]But once YOUR TestPage is instantiated, it would instantiate another TestPage within the first one!

          This IS recursion, believe it or not.

          The compiler is always right™.[/quote]

          That's exactly what I wanted to say. And it happens the same way with my example C++ code (you could also use a pointer and a c'tor that creates it):

          @
          class Foo {
          public:
          Foo() {
          member = new Foo;
          }
          Foo* member;
          };
          @

          This also crashes if you create the first Foo, not before! It's exactly the same.

          Nokia Certified Qt Specialist.
          Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

          1 Reply Last reply
          0
          • ? Offline
            ? Offline
            A Former User
            wrote on last edited by
            #17

            Your example is wrong.
            The doc says it is load when it is requested.
            so i see it more like this, in c++:
            @
            struct Foo
            {
            Foo() : m_foo(0)
            {
            }

            Foo *m_foo;
            

            };

            int main()
            {
            Foo foo;
            foo.m_foo = new Foo;
            return 0;
            }
            @

            And actually it is not accurately true. Here we said our component has a member of its type. But that is not necessarily the case. As I figure it, a Component is something like a type in C++, so, an inline component is more like a typedef or a inner class.

            @
            struct Foo
            {
            Foo() : m_foo(0)
            {
            }
            Foo *createBar() {
            struct Bar : public Foo
            {
            Bar *m_bar;
            };
            //do stuff, like init variables....
            return new Bar;
            }
            Foo *m_foo;
            };

            int main()
            {
            Foo foo;
            foo.m_foo = new Foo;
            Foo *foobar = foo.createBar();
            foobar = new Foo;

            return 0;
            

            }
            @

            1 Reply Last reply
            0
            • G Offline
              G Offline
              giesbert
              wrote on last edited by
              #18

              A type is not the same as a typedef!
              A class is a type, an int is a type.
              a typedef is only a name.

              and if you have the following:

              TestPage.qml

              @
              item {
              id: item1
              Component {
              id: inneritem
              Rectangle {
              }
              }
              }
              @

              If you create the component TestPage, the rectangle is created. The Rectangle is a client of the component. If your component contains another component, it is created when the component is created. If you contain yourself, you create yourself recursively!

              And back to my first example (which the compiler would reject!):

              @
              class Foo
              {
              Foo member;
              }
              @

              a type containing itself! Same as

              Foo.qml
              @
              item {
              Component {
              id: inneritem
              Foo {
              }
              }
              }
              @

              Nokia Certified Qt Specialist.
              Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

              1 Reply Last reply
              0
              • ? Offline
                ? Offline
                A Former User
                wrote on last edited by
                #19

                [quote author="Gerolf" date="1301917914"]A type is not the same as a typedef!
                [/quote]
                uh? Once defined, the type defined by the typedef is a type, or missed a something obvious for years.
                [quote author="Gerolf" date="1301917914"]
                A class is a type, an int is a type.
                [/quote]
                Agreed.
                [quote author="Gerolf" date="1301917914"]
                a typedef is only a name.
                [/quote]
                A typedef is a declaration, like a function prototype, a class/struct. Its purpose is to declarate a type based on another type (type aliasing) or a composite type in C.
                [quote author="Gerolf" date="1301917914"]
                and if you have the following:

                TestPage.qml

                @
                item {
                id: item1
                Component {
                id: inneritem
                Rectangle {
                }
                }
                }
                @

                If you create the component TestPage, the rectangle is created.
                [/quote]
                Again, that's not what the doc tells me! Or we have not the same defnition of "created".
                Mine says it's when the rectangle is created, whit his children, initialized and Component.onCompleted called. It's not the case until you load your component with a loader.
                [quote author="Gerolf" date="1301917914"]
                The Rectangle is a client of the component. If your component contains another component, it is created when the component is created. If you contain yourself, you create yourself recursively!
                [/quote]
                Again and again, an inline Component is (should be?) just a definition in a definition. Not a creation/instantiation.
                [quote author="Gerolf" date="1301917914"]
                And back to my first example (which the compiler would reject!):

                @
                class Foo
                {
                Foo member;
                }
                @

                a type containing itself! Same as

                Foo.qml
                @
                item {
                Component {
                id: inneritem
                Foo {
                }
                }
                }
                @[/quote]
                Yeah that's obviously wrong in c++, I fully understand that. But this it is not the translation i make of a Component. Mine is juste above and i'm pretty sure it's what the doc says and what semantically should happen in qml.

                1 Reply Last reply
                0
                • G Offline
                  G Offline
                  giesbert
                  wrote on last edited by
                  #20

                  [quote author="Tipiak" date="1301919705"][quote author="Gerolf" date="1301917914"]A type is not the same as a typedef!
                  [/quote]
                  uh? Once defined, the type defined by the typedef is a type, or missed a something obvious for years.
                  [/quote]

                  A typedef is just another name for an existing type or for example a template. So typedef itself does not create a real type, it just gives another name for a type, more like a reference does not create an object, it#s just another name :-)

                  otherwise, such things would not work:
                  @
                  class A
                  {
                  puiblic:
                  explicit A();
                  explicit A(const A&);
                  }

                  typedef B A;

                  A myObj;
                  B myObj2;
                  A myObj3(myObj2);
                  @

                  [quote author="Tipiak" date="1301919705"]
                  Again, that's not what the doc tells me! Or we have not the same defnition of "created".
                  Mine says it's when the rectangle is created, whit his children, initialized and Component.onCompleted called. It's not the case until you load your component with a loader.
                  [/quote]

                  TestPage.qml

                  @
                  item {
                  id: item1
                  Component {
                  id: inneritem
                  Rectangle {
                  color: "red"
                  width: 10
                  height: 10
                  }
                  TestPage{
                  }
                  }
                  }
                  @

                  If you instantiate the type TestPage, all inner objects are created, right? including the height, width, etc. So if Rectangle is instantiated, also TestPage sub object will be created. This is the recursion!

                  Nokia Certified Qt Specialist.
                  Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                  1 Reply Last reply
                  0
                  • ? Offline
                    ? Offline
                    A Former User
                    wrote on last edited by
                    #21

                    [quote author="Gerolf" date="1301920550"][quote author="Tipiak" date="1301919705"][quote author="Gerolf" date="1301917914"]A type is not the same as a typedef!
                    [/quote]
                    uh? Once defined, the type defined by the typedef is a type, or missed a something obvious for years.
                    [/quote]

                    A typedef is just another name for an existing type or for example a template. So typedef itself does not create a real type, it just gives another name for a type, more like a reference does not create an object, it#s just another name :-)
                    [/quote]
                    That's why i mentioned "type aliasing" few lines later. It more than a name and less a than "new" type declaration, in this case.
                    [quote author="Gerolf" date="1301920550"]
                    otherwise, such things would not work:
                    @
                    class A
                    {
                    puiblic:
                    explicit A();
                    explicit A(const A&);
                    }

                    //typedef B A; << wrong!
                    typedef A B;

                    A myObj;
                    B myObj2;
                    A myObj3(myObj2);
                    @

                    [quote author="Tipiak" date="1301919705"]
                    Again, that's not what the doc tells me! Or we have not the same defnition of "created".
                    Mine says it's when the rectangle is created, whit his children, initialized and Component.onCompleted called. It's not the case until you load your component with a loader.
                    [/quote]

                    TestPage.qml

                    @
                    item {
                    id: item1
                    Component {
                    id: inneritem
                    Rectangle {
                    color: "red"
                    width: 10
                    height: 10
                    }
                    TestPage{
                    }
                    }
                    }
                    @

                    If you instantiate the type TestPage, all inner objects are created, right? including the height, width, etc. So if Rectangle is instantiated, also TestPage sub object will be created. This is the recursion![/quote]

                    Your example is wrong (again :) ). A Component, inline or not, cannot contain more than one root item.

                    But let's say:
                    @
                    import Qt 4.7
                    Item {
                    id: item1
                    width: 20
                    height: 20
                    Component {
                    id: inneritem
                    Rectangle {
                    color: "red"
                    width: 10
                    height: 10
                    // TestPage{
                    // }
                    Component.onCompleted: {
                    console.log("Hello")
                    }
                    }
                    }
                    Loader {
                    sourceComponent: inneritem
                    }
                    }
                    @

                    if you comment the Loader, "hello" is not displayed. But if you uncomment TestPage you've got the "recursive instantiation" error.

                    1 Reply Last reply
                    0
                    • ? Offline
                      ? Offline
                      A Former User
                      wrote on last edited by
                      #22

                      One (really! - promised!) last try:

                      The big precondition is: you saved this snippet in TestPage.qml:

                      @
                      item {
                      id: item1
                      Component {
                      id: inneritem
                      TestPage {
                      }
                      }
                      }
                      @

                      If you instantiate your component (and you will instantiate it eventually, otherwise this whole discussion is plain uselsess), the interpreter eventually comes along line 5. As TestPage is no builtin thingie, it tries to resolve it. It looks into the filesystem and happily finds TestPage.qml (because it always looks for name-of-the-thingie.qml); so nice, it tries to load it, but only to find out that it is the same file as it is processing right at the moment - boom! Recursion!

                      So please do yourself a favor and rename TestPage.qml to blafasel.qml and try again. I guess you will get a "component TestPage not found" error or something similar.

                      1 Reply Last reply
                      0
                      • _ Offline
                        _ Offline
                        _kch_
                        wrote on last edited by
                        #23

                        I realize this is very old, but the explanations of why-you-cannot-do-this don't really show why-you-cannot-do-this.

                        Yes, documentation says a component is only loaded when a loader asks for it. But a component MUST BE FULLY DEFINED in order to run.

                        The original sample code does not have any syntax errors, so it compiles, but what happens when you try to instantiate (or even dynamically load) TestPage?

                        QML loads the definition for TestPage, from TestPage.qml, and starts creating the things inside of it.

                        QML gets to the Component definition, begins to instantiate THE COMPONENT, and says, "Hey, a component, I need to load and prepare the definition of this component so I can instantiate it when the loader asks for it"

                        QML starts building the definition of Component. It is not instantiating the contents of the component, but it IS still instantiating TestPage.

                        QML runs into "TestPage" as thing inside of the Component.

                        QML says "Oh, I know were that definition is, in TestPage.qml! Oh, wait a minute, I'm currently INSTANTIATING TestPage, and it looks like something inside of TestPage needs everything inside of TestPage in order to exist.... Hmmmm...."

                        At this point the QML runtime engine can either:

                        A. be stupid and just keep blindly going, or
                        B. be a little smart and realize that if it is instantiating an object and it runs into a requirement for that same object somewhere in the instantiation tree, it has recursive dependencies.

                        No, the inner TestPage is not technically instantiated.

                        But YES, the inner TestPage must be "completely known" before the Component instantiation can complete.

                        One can quibble about why the error says "recursive instantiation", but it is technically correct, since it IS instantiating and it HAS encountered a recursive dependency.

                        If the Component content is inline (and the example is inline), all of that content must be parsed and prepared (including subordinate objects) so that it "knows what to do" when loaded.

                        If you really want to dynamically load something, look at Qt.createComponent:

                        http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html

                        The object created must be stored in a 'var', so this is much more like the pointer examples called out in the discussion.

                        1 Reply Last reply
                        2

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved