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. [SOLVED]Making item visible taking too long when calling C++ functions from QML
Forum Updated to NodeBB v4.3 + New Features

[SOLVED]Making item visible taking too long when calling C++ functions from QML

Scheduled Pinned Locked Moved QML and Qt Quick
10 Posts 4 Posters 4.1k 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.
  • T Offline
    T Offline
    Tory Gaurnier
    wrote on last edited by
    #1

    Now this is a little bit of a complicated issue, if anyone else can think of a better title after I post my question, please do tell ;)

    Anyways, what's happening is this, I have an custom popover that I created that is invisible (visible: false), and I need to make it visible, right after it becomes visible, I have C++ functions being called from QML, so this is basically what I have:
    @
    MyItem {
    id: myItem
    visible: false
    //Other stuff
    }
    MyOtherItem {
    onSomeButtonPressed: {
    myItem.visible = true;
    myC++RegisteredObject.myMethod();
    }
    }
    @

    So when I have something like that, MyItem does not show until AFTER myMethod() is done being called, if I put if(myItem.visible == true) print("TEST"); just before the method call it prints, and if I comment out the method call, it shows instantly.

    How can I get it to wait for myItem to finish getting painted before the flow of control continues? I know there's no setTimout function, but is there something similar I can use? I tried while(myItem.busy) but that didn't seem to work, it doesn't register itself as busy while it's making itself visible.

    Any help is greately appreciated, thanks.

    1 Reply Last reply
    0
    • B Offline
      B Offline
      beemaster
      wrote on last edited by
      #2

      Simple solution is to use a "Timer":http://qt-project.org/doc/qt-4.8/qml-timer.html element:
      @
      MyItem {
      id: myItem
      visible: false
      //Other stuff
      }
      MyOtherItem {
      onSomeButtonPressed: {
      myItem.visible = true;
      myTimer.start();
      }
      Timer {
      id: myTimer
      interval: 0
      onTriggered: {
      myC++RegisteredObject.myMethod();
      }
      }
      @

      1 Reply Last reply
      0
      • S Offline
        S Offline
        stereomatching
        wrote on last edited by
        #3

        I have the same problem too and the timer can't solve the problem
        even it can, it should not be a solution
        who knows which machine should delay how many msec?

        1 Reply Last reply
        0
        • S Offline
          S Offline
          stereomatching
          wrote on last edited by
          #4

          Find out a solution which don't need to depend on the timer, but more verbose.Execute your process on another thread, you could use QtConcurrent to make your life easier.

          Don't use QtConccurrent::map under mac os x, because it may have some bug.

          "bug":https://bugreports.qt-project.org/browse/QTBUG-32315

          1 Reply Last reply
          0
          • T Offline
            T Offline
            Tory Gaurnier
            wrote on last edited by
            #5

            That looks pretty promising, I've been trying the Timer for a while with no luck, once I have a chance to implement QtConcurrent I'll post wether it worked for me or not.
            [quote author="stereomatching" date="1373959597"]Find out a solution which don't need to depend on the timer, but more verbose.Execute your process on another thread, you could use QtConcurrent to make your life easier.

            Don't use QtConccurrent::map under mac os x, because it may have some bug.

            "bug":https://bugreports.qt-project.org/browse/QTBUG-32315[/quote]

            1 Reply Last reply
            0
            • T Offline
              T Offline
              Tory Gaurnier
              wrote on last edited by
              #6

              Well, I've been trying to use QtConcurrent for this, and I haven't really been able to figure out how to get it to work for this. What I'm doing throughout my app is this:
              C++: Do some stuff, then load QML using QQuickView
              QML: Do stuff in QML, show popup with progress bar (the thing that's not getting painted because threads getting blocked) then call Q_INVOKABLE methods in C++ (the thing blocking the progress bar from showing)
              C++: in the Q_INVOKABLE methods use QFuture *future = QtConcurrent::run(myCFunction);
              myReturnValue = future->result(); (Now this is blocking the progress bar from showing until the thread returns, so it's having the same problem I was having before)

              That's a quick rundown of what's going on, is there another way I can use QtConcurrent that will fix my issue?

              If I use QtConcurrent run from the getgo to launch my QML, so the gui itself is in another thread, how will I have the Q_INVOKABLE methods called from the original thread? In other words:

              Thread 1 create Thread 2 containing QML gui
              Thread 2 call Q_INVOKABLE methods from within QML and have them run back in Thread 1

              I hope this is making sense, if it doesn't please let me know and I'll try to clarify.

              1 Reply Last reply
              0
              • C Offline
                C Offline
                chrisadams
                wrote on last edited by
                #7

                Can you use a WorkerScript element to do the C++ API calls? If it's in a loop, it can call back to the main thread at the end of each loop with progress, so that you can update your progress bar.

                That way you avoid using QtConcurrent, which adds complexity to your implementation.

                Cheers,
                Chris.

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  stereomatching
                  wrote on last edited by
                  #8

                  bq. Can you use a WorkerScript element to do the C++ API calls?

                  Thanks, I don't know qml provide us WorkerScript, would give it a try next time.

                  bq. haven’t really been able to figure out how to get it to work for this

                  If you want to upgrade progress bar, you could try QtConccurrent::map(as I said, Don’t use QtConccurrent::map under mac os x because there maybe a bug) or QtConccurrent::mapped.

                  The idea is, make your heavy job run in the thread of QtConccurrent::mapped, let your QFutureWatcher
                  1 : monitor the progress, emit the signal to the qml ProgressBar
                  2 : emit exit signal when all of the progress exit

                  Code snippets of QtConccurrent::mapped after simplify

                  @
                  //constructor
                  {
                  //progressResults_ is QFutureWatcher<int>
                  connect(&progressResults_, SIGNAL(progressValueChanged(int)), this, SLOT(setProgressValue(int)));
                  connect(&progressResults_, SIGNAL(finished()), this, SLOT(makeProgressExit()));
                  }

                  void customImage::setProgressValue(int value)
                  {
                  if(value != progressValue_){
                  progressValue_ = value;
                  emit progressValueChanged();
                  }
                  }

                  void customImage::makeProgressExit()
                  {
                  if(progressExit_ != value){
                  progressExit_ = value;
                  emit progressExitChanged();
                  }
                  }

                  //the codes which call QtConcurrent::mapped
                  void customImage::saveImages( QList<QString> names)
                  {
                  namespace ph = std::placeholders;

                  //The return type of the results  is QFuture<int>
                  auto results = QtConcurrent::mapped(names, std::bind(&customImage::saveImagesImplement, this, ph::_1));
                  progressResults_.setFuture(results);
                  

                  }

                  @

                  Hope this help you, or just try WorkerScript, maybe it could make our life easier

                  1 Reply Last reply
                  0
                  • T Offline
                    T Offline
                    Tory Gaurnier
                    wrote on last edited by
                    #9

                    Well, I wanted to keep most of my control in QML, so I tried a Workerscript, and still had no luck, I was getting segfaults and gdb was unable to pinpoint where in my file they were, when a workerscript executes Q_INVOKABLE C++ code it can't seem to be backtraced, not to mention it seemed like any variables I edited in the thread created by the workerscript weren't effected outside of the thread (which would make sense). However I decided to give Timer another look, and I think I found a solution using Timer, here is what I did:

                    @
                    Timer {
                    id: myC++Method1Timer
                    interval: 1
                    signal complete()
                    onTriggered: {
                    myInvokableC++Class.myC++Method1();
                    complete();
                    }
                    onComplete: {
                    loadScreen.init(-1, "Title", "Doing Stuff");
                    myC++Method2Timer.start();
                    }
                    }

                    Timer {
                    id: myC++Method2Timer
                    interval: 1
                    signal complete()
                    onTriggered: {
                    result = myInvokableC++Class.myC++Method2();
                    complete();
                    }
                    onComplete: {
                    if(result == 0) {
                    loadScreen.init(max /sets max of prog bar/, "Prog Bar Title", "Doing Stuff")
                    loadScreen.inc("Doing more stuff"); // Increment prog bar & setting text
                    myC++Method3Timer.start();
                    }
                    else myC++Method3Timer.complete();
                    }
                    }

                    Timer {
                    id: myC++Method3Timer
                    interval: 1
                    signal complete()
                    signal continued() // This C++ method needs to be called continuously
                    property int run: 0
                    onTriggered: {
                    myInvokableC++Class.myC++Method3(run);
                    run++;
                    if(run == max) complete();
                    else continued();
                    }
                    onContinued: {
                    loadScreen.inc("Continuing to do more stuff");
                    myC++Method3Timer.start();
                    }
                    onComplete: {
                    Finish doing stuff in QML here
                    }
                    }

                    onReady: { // ready is a signal in my root element
                    loadScreen.init(-1 /sets prog bar to indeterminate/, "Prog Bar Title", "Doing Something Intensive");
                    myC++Method1Timer.start();
                    }
                    @

                    The only downside is when my progress bar is set to indeterminite in loadScreen.init(), it's not animated, but that's not that big of a deal, because it doesn't show that long, as long as the normal progress bar is animated, and it is doing it this way, it's fine.

                    And I should probably note that loadScreen is a component I created containing progress bar, a title, and a caption. The progress bar is an "Ubuntu component":http://developer.ubuntu.com/api/ubuntu-12.10/qml/mobile/qml-ubuntu-components0-progressbar.html.

                    1 Reply Last reply
                    0
                    • T Offline
                      T Offline
                      Tory Gaurnier
                      wrote on last edited by
                      #10

                      To sum it up, the trick to using Timer for this, is having a complete signal in each Timer, in my case I have several methods, each needs the progress bar to animate before it's run, and one of the methods needs to be run multiple times incrementing the progress bar before each run, in that method I also have a continued signal. Look at my example above for more.

                      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