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. Calling a C++ function inside a property subclass from QML
Forum Updated to NodeBB v4.3 + New Features

Calling a C++ function inside a property subclass from QML

Scheduled Pinned Locked Moved QML and Qt Quick
13 Posts 8 Posters 20.6k 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.
  • L Offline
    L Offline
    luizpaulo
    wrote on last edited by
    #1

    Hi,

    I'm trying to do the following:

    in main.cpp: context->setContextProperty("class", new Class);;

    in qml file:

    @
    Button {
    id: btn
    image: "img.svg"
    onButtonClicked: { class.subclass().method(); }
    }
    @

    And it simply doesn't work. Subclass is a property of class, but is itselft a class with it's own methods, properties, slots and signals.
    I've tried everything: qRegisterMetaType, qmlRegisterInterface, Q_DECLARE_METATYPE, but nothing works. Something like this:

    @
    Button {
    id: btn
    image: "img.svg"
    onButtonClicked: { class.method(); }
    }
    @

    Works just fine. But it's now how I want the API to be. Is there any way for this to work, or is this a QML limitation?

    1 Reply Last reply
    0
    • D Offline
      D Offline
      DenisKormalev
      wrote on last edited by
      #2

      It should work if you have subclass() and method() as Q_INVOKABLE (or slots) and have invoked qmlRegisterUncreatableType (or another function from this set) for both classes.

      1 Reply Last reply
      0
      • T Offline
        T Offline
        thp4
        wrote on last edited by
        #3

        [quote author="luizpaulo" date="1291472959"]
        @ onButtonClicked: { class.subclass().method(); } @
        ...
        @ onButtonClicked: { class.method(); } @
        [/quote]

        While this should be possible with the suggestion by Denis, consider that in the first variant, the QML UI makes more assumptions about the class hierarchy, while the second variant does not give any information about the class hierarchy away.

        What if you decide in a few months that having subclass() as method of class is not a good idea, and you refactor the code? Then suddenly you have to make changes to your QML - there are no compiler warnings for you when you try to reference something non-existing in the QML, so the bug might not jump right in front of your eyes.

        So the second variant without the subclass() might be more suitable and future-proof and will allow you to refactor the code without changing the QML files. The only thing you have to keep stable in this case is the "public" API of your code that gets accessed directly from QML. It might also create a nicer API and a better structured code.

        1 Reply Last reply
        0
        • D Offline
          D Offline
          DenisKormalev
          wrote on last edited by
          #4

          thp, we have similar way as author has to call c++ from qml. In our design we have on class that has pointers to all objects that are needed for qml interaction and doesn't have any methods other than simple getters for this objects. This gives us ability to pass only one object as contextproperty to qml for all interaction between qml and c++.

          1 Reply Last reply
          0
          • L Offline
            L Offline
            luizpaulo
            wrote on last edited by
            #5

            Well it's not working...
            A more complete example follows:

            class1.h:

            @
            class Class1 : public QObject
            {
            Q_OBJECT
            Q_PROPERTY(SubClass1 subclass1 READ subclass1)

            private:
               SubClass1 _subclass1;
            
            public slots:
               SubClass1 subclass1() {return _subclass1;}
            

            };
            @

            subclass1.h:

            @
            class SubClass1 : public QObject
            {
            Q_OBJECT

            public:
                SubClass1(QObject *parent = 0);
                SubClass1(const SubClass1 &);
                SubClass1 &operator=(const SubClass1 &);
            
            public slots:
                void method() {qDebug("method");}
            

            };
            @

            main.cpp:
            @
            ...
            qRegisterMetaType<SubClass1>("SubClass1");
            qmlRegisterInterface<Class1>("Class1");
            qmlRegisterInterface<SubClass1>("SubClass1");

            context->setContextProperty("Class1", new Class1);;
            

            ...
            @

            qml:
            @
            Button {
            id: btn
            image: "img.svg"
            onButtonClicked: { class1.subclass1().method(); }
            }
            @

            Doesn't work. I've tried qmlRegisterUncreatableType and qmlRegisterType as well it didn't work. All I get is this:
            TypeError: Result of expression 'class1.subclass1' [QVariant(SubClass1)] is not a function.

            If I remove the MetaType stuff I get this:
            TypeError: Result of expression 'class1.subclass1' [undefined] is not a function.

            Any other ideas?

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

              Is it case sensitive? I never tried this up to now, but in C++ you have to take care of case... How is this in Qml code? Ifit is case sensitive, it should be:

              @
              Button {
              id: btn
              image: "img.svg"
              onButtonClicked: { Class1.subclass1().method(); }
              }
              @

              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
              • C Offline
                C Offline
                coderbob
                wrote on last edited by
                #7

                I believe this could be a bug and related to http://developer.qt.nokia.com/forums/viewthread/1764/
                filed as http://bugreports.qt.nokia.com/browse/QTBUG-15712 (Voting on it might get it fixed faster)

                Change your return type to a QObject and use qobject_cast<T>() in your c++ code if you need to access it there also.

                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  DenisKormalev
                  wrote on last edited by
                  #8

                  coderbob, yes qobject_cast will help author in using objects from qml, but if all methods will return qobjects or there will be duplicated methods (one return qobject, one normal type) then it can lead to design problems.

                  1 Reply Last reply
                  0
                  • C Offline
                    C Offline
                    coderbob
                    wrote on last edited by
                    #9

                    Denis, I think you misunderstood the solution. There are no duplicate functions. You have to use QObject to be able to access correctly in QML. The side effect of this is that you lose your defined types in the c++ code. To solve this you have to qcast them when accessed there. Only one function is needed but you will have to cast.

                    This is not how I want to write my code but it is the best solution I could come up with to work around this bug until it is fixed.

                    1 Reply Last reply
                    0
                    • N Offline
                      N Offline
                      Nayar
                      wrote on last edited by
                      #10

                      I'm still having this problem on my friend's windows machine.

                      Windows:-
                      It calls the function as the program loads. But when called again, the program crashes

                      Linux:-
                      It works for some times. Then it crashes.

                      Else, it would say it is not a function. I guess QML is loosing some infomation. Maybe garbage collector is destroying the link to the function after some time.

                      1 Reply Last reply
                      0
                      • X Offline
                        X Offline
                        Xander84
                        wrote on last edited by
                        #11

                        if your app is crashing it's more likely that you have an invalid pointer in the c++ code I would say, but hard to tell without seeing any code or something.
                        also just start the app in debug mode then you should see the stacktrace when the app crashes and what function it crashes etc.

                        1 Reply Last reply
                        0
                        • N Offline
                          N Offline
                          Nayar
                          wrote on last edited by
                          #12

                          Here's the QML
                          @ListView {
                          id: listViewRulesStrength
                          MouseArea {
                          anchors.fill: parent
                          onClicked: {
                          listViewRulesStrength.model = m.fce().rulesStrength();
                          }
                          }
                          model: m.fce().rulesStrength()
                          delegate: Item {
                          Row {
                          id: row2
                          Text {
                          text: modelData.rule
                          height: paintedHeight
                          }
                          }
                          }@

                          The C++ code for m.fce() in class Mixture

                          @FuzzyCompostEngine * Mixture::fce()
                          {
                          return m_engines;
                          }@

                          The C++ code for rulesStrenght in FuzzyCompostEngine

                          @
                          QList<QObject *> FuzzyCompostEngine::rulesStrength()
                          {
                          qDebug() << "Starting rule strength";
                          for(int i = 0;i<m_rulesStrength.size();i++){
                          RuleStrength *tmp = (RuleStrength *) m_rulesStrength.first();
                          m_rulesStrength.removeFirst();
                          delete tmp;
                          }

                          qDebug() << "rule strength";
                          fl::Engine *engine;
                          for(int i = 0;i < engines.size();i++){
                              engine = engines.at(i);
                              fl::RuleBlock *ruleBlock = engine->getRuleBlock(0);
                              if(ruleBlock != NULL)
                              {
                                  for(int j = 0; j < ruleBlock->numberOfRules() ; j++){
                                      fl::Rule *rule =  engine->getRuleBlock(0)->getRule(j);
                                      scalar degree = rule->firingStrength(ruleBlock->getTnorm(),ruleBlock->getSnorm());
                                      //qDebug() << "Degree" << degree;
                                      if(std::isnan(degree) == 0 && degree > 0.01){
                                          //rules << QString::fromStdString(rule->getUnparsedRule()) + " : " + QString::number(degree,'f',2);
                                          m_rulesStrength.append(new RuleStrength(QString::fromStdString(rule->getUnparsedRule()),degree));
                                      }
                                  }
                              }
                          }
                          std::sort(m_rulesStrength.begin(),m_rulesStrength.end(),RuleStrength::isGreater);
                          qDebug() << "Ending";
                          return m_rulesStrength;
                          

                          }
                          @

                          When it crashes, it doesn't even start the C++ function rulesStrength. because the qDebug doesn't get displayed

                          Sometimes when clicking a lot, i get the error

                          bq. qrc:/qml/mainwindow.qml:274: TypeError: Cannot call method 'rulesStrength' of null

                          However, the problem gets fixed when i call the function from mixture directly.

                          new QML model in listwidget
                          @
                          MouseArea {
                          anchors.fill: parent
                          onClicked: {
                          listViewRulesStrength.model = m.rulesStrength();
                          }
                          }
                          model: m.rulesStrength()
                          @

                          I added a function in Mixture like this to call fce() from inside

                          @QList<QObject *> Mixture::rulesStrength()
                          {
                          return fce()->rulesStrength();
                          }@

                          Now it runs fine on windows and doesn't crash or lose the object in QML on Linux

                          Reminder: The initial code does run fine as it should have for some time only on Linux.

                          1 Reply Last reply
                          0
                          • T Offline
                            T Offline
                            Torgeir
                            wrote on last edited by
                            #13

                            When you use a construct like
                            @m.fce().rulesStrength()@

                            you need to be careful about object ownership of the object returned by fce(). If this object has no explicit parent set or doesn't have explicit CppOwnership set, then QML will assume ownership and will destruct it when it is no longer referenced.

                            You can check if it gets destructed by setting a breakpoint in the desctructor for example.

                            1 Reply Last reply
                            0

                            • Login

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