Results 1 to 4 of 4

Thread: Moving Qt3D objects

  1. #1
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Moving Qt3D objects

    I am learning about Qt3D. Starting from one of the Qt examples, I can display a sphere and move it by QTransform::setTranslation. I want to make multiple moves, with a brief delay each time, so I have:

    void MainWindow::runMover()
    {
    QVector3D delta = QVector3D(0.0f, 0.0f, -0.1f);
    for (int i = 0; i<1000; i++) {
    mover(delta);
    QThread::msleep(10);
    }
    }

    with

    void MainWindow::mover(QVector3D delta)
    {
    modifier->moveSphere(delta);
    }

    and

    void SceneModifier::moveSphere(QVector3D delta)
    {
    QVector3D trans = sphereTransform->translation();
    trans = trans + delta;
    sphereTransform->setTranslation(trans);
    }

    The function runMover() is executed when a signal is received. I expect to see a smooth movement, but instead there is a 10 second delay then suddenly the whole movement occurs. How can I make the translation by delta occur every 10 ms?

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,123
    Thanks
    235
    Thanked 659 Times in 649 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Moving Qt3D objects

    I expect to see a smooth movement, but instead there is a 10 second delay then suddenly the whole movement occurs.
    Because this for loop does not let control return to the Qt event loop, which needs to process the translation and repaint the window for each move. Qt's event loop removes all but the last paint event when the loop contains multiple pending paint requests.

    for (int i = 0; i<1000; i++)
    {
    mover(delta);
    }
    To avoid this mistake, get rid of the loop and the sleep command in runMover(). Instead, set up a QTimer with a 10 ms timeout. Connect the timer's timeout() signal to a slot that translates the objects by one step, checks to see how many steps have been made, and starts the QTimer again if there are less than 10 second's worth of steps (1000).

    Qt Code:
    1. void MainWindow::runMover()
    2. {
    3. // elapsedSteps is a member variable of MainWindow that is inotialized to 0 before
    4. // calling runMover()
    5. if ( elapsedSteps < 1000 )
    6. {
    7. QVector3D delta = QVector3D(0.0f, 0.0f, -0.1f);
    8. mover( delta );
    9. QTimer::singleShot( 10, this, &MainWindow::runMover );
    10. elapsedSteps++;
    11. }
    12. }
    To copy to clipboard, switch view to plain text mode 

    Please use CODE tags when posting source code so it is readable. See my signature below.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: Moving Qt3D objects

    Quote Originally Posted by d_stranz View Post
    Because this for loop does not let control return to the Qt event loop, which needs to process the translation and repaint the window for each move. Qt's event loop removes all but the last paint event when the loop contains multiple pending paint requests.



    To avoid this mistake, get rid of the loop and the sleep command in runMover(). Instead, set up a QTimer with a 10 ms timeout. Connect the timer's timeout() signal to a slot that translates the objects by one step, checks to see how many steps have been made, and starts the QTimer again if there are less than 10 second's worth of steps (1000).

    Qt Code:
    1. void MainWindow::runMover()
    2. {
    3. // elapsedSteps is a member variable of MainWindow that is inotialized to 0 before
    4. // calling runMover()
    5. if ( elapsedSteps < 1000 )
    6. {
    7. QVector3D delta = QVector3D(0.0f, 0.0f, -0.1f);
    8. mover( delta );
    9. QTimer::singleShot( 10, this, &MainWindow::runMover );
    10. elapsedSteps++;
    11. }
    12. }
    To copy to clipboard, switch view to plain text mode 

    Please use CODE tags when posting source code so it is readable. See my signature below.
    That is a great help, thanks a million! Coming from a long career in old-style programming, I haven't fully grasped the event-driven nature of Qt programming.
    I now get nice smooth motion. One thing I don't understand (showing my ignorance) is why elapsedSteps needs to be a MainWindow member variable and needs to be initialised outside of runMover. I see that this is the case, since if I set it to 0 in runMover (either before or after the 'if' block) the movement goes on forever. I tried initialising there because I want to be able to generate the motion every time I click the button that triggers the signal that invokes runMover.

    Sorry about the code formatting oversight.

    Gib

    Edit: Oh, now I see that it's obvious why it is useless to set elapsedSteps=0 in runMover, because the function is called repeatedly, therefore the counter would be constantly reset. Doh! The solution is to connect the button-click signal to a function that initialises elapsedSteps then calls runMover. Thanks again.
    Last edited by gib; 18th August 2019 at 23:56.

  4. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,123
    Thanks
    235
    Thanked 659 Times in 649 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Moving Qt3D objects

    The solution is to connect the button-click signal to a function that initialises elapsedSteps then calls runMover. Thanks again.
    Exactly. And you're welcome.

    Event-driven programming takes a while to get your head around. I first started in the late 80s in an XWindows / Motif GUI after also spending years in procedural programming. The key to understanding it is to recognize that your code isn't in charge - there's another part of it that is sitting there idling away until something happens that it needs to tell your code about. It then uses the formal notification system of whatever framework you are using (in Qt's case, Qt events and signals) to tell you what has happened. If your code is interested (i.e., you have implemented a handler for that event or have connected a slot to that signal), then it'll get called.

    The trick to keeping your GUI alive is that your code has to let control return to the framework. If you have a heavy computation and your code runs it to completion, your GUI locks up until it finishes and control is returned to the framework. This is essentially what your loop / sleep was doing - a 10 second long computation.

    Wysota wrote a good article discussing this a while back that is still available.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. Right approach for moving animated objects
    By AndyQT in forum Newbie
    Replies: 5
    Last Post: 6th November 2012, 09:39
  2. Replies: 0
    Last Post: 24th May 2010, 12:19
  3. Replies: 3
    Last Post: 9th January 2010, 15:47
  4. QGraphicsView and fast moving objects
    By deMarco in forum Qt Programming
    Replies: 4
    Last Post: 26th February 2009, 11:07
  5. Replies: 7
    Last Post: 18th July 2006, 21:33

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.