Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Algorithm animation(QPainter)

Algorithm animation(QPainter)

Scheduled Pinned Locked Moved Solved General and Desktop
algorith animatqpainter
15 Posts 2 Posters 4.0k Views
  • 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.
  • M Offline
    M Offline
    mandruk1331
    wrote on 24 Jan 2016, 14:50 last edited by
    #1

    I'm trying to make an animation of an algorithm, so far I could only add some rectangles with the scene->addRect(20+(i*30),0-random_numbers_[i],28,random_numbers_[i],Pen,darkMagentaBrush);
    I'm a little bit confused, how I can change the color of the rectangle, for example the fifth one and the sixth, to show that this two will swap. Is it better to use the QPainter??

    Mandruk1331

    1 Reply Last reply
    0
    • C Offline
      C Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on 24 Jan 2016, 15:11 last edited by
      #2

      Hi,
      It would be nice if you provided more info or ocde, but I'll just assume scene in your code is QGraphicsScene (am I right?).
      If so, then the addRect()method returns a pointer to QGraphicsRectItem representing your rectangle.
      You should store these pointers in some array, like QVector<QGraphicsRectItem*>.
      Then you can get to any of the items and use its setBrush method to set any brush you want on it. The QBrush you set can be a solid color, gradient , texture or a pattern, whatever you need.

      M 1 Reply Last reply 24 Jan 2016, 16:10
      1
      • C Chris Kawa
        24 Jan 2016, 15:11

        Hi,
        It would be nice if you provided more info or ocde, but I'll just assume scene in your code is QGraphicsScene (am I right?).
        If so, then the addRect()method returns a pointer to QGraphicsRectItem representing your rectangle.
        You should store these pointers in some array, like QVector<QGraphicsRectItem*>.
        Then you can get to any of the items and use its setBrush method to set any brush you want on it. The QBrush you set can be a solid color, gradient , texture or a pattern, whatever you need.

        M Offline
        M Offline
        mandruk1331
        wrote on 24 Jan 2016, 16:10 last edited by
        #3

        @Chris-Kawa, Thank you. BTW can I draw a number inside of a rectangle? I tried to use QPainter but no luck

        Mandruk1331

        1 Reply Last reply
        0
        • C Offline
          C Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on 24 Jan 2016, 17:08 last edited by
          #4

          You can create a QGraphicsSimpleTextItem and put it inside of you rectangle.
          Beware though that you're creating rectangles with an anchor outside of them so the text item won't align properly.

          You could use something like this instead:

          for(int i = 0; i < whatever; ++i)
          {
             QGraphicsRectItem* rectangle = scene->addRect(0, 0, someWidth, someHeight);
             QGraphicsSimpleTextItem* text = new QGraphicsSimpleTextItem("hello", rectangle);
             
             rectangle->moveBy(someOffsetX, someOffsetY);
          }
          
          M 1 Reply Last reply 24 Jan 2016, 18:06
          1
          • C Chris Kawa
            24 Jan 2016, 17:08

            You can create a QGraphicsSimpleTextItem and put it inside of you rectangle.
            Beware though that you're creating rectangles with an anchor outside of them so the text item won't align properly.

            You could use something like this instead:

            for(int i = 0; i < whatever; ++i)
            {
               QGraphicsRectItem* rectangle = scene->addRect(0, 0, someWidth, someHeight);
               QGraphicsSimpleTextItem* text = new QGraphicsSimpleTextItem("hello", rectangle);
               
               rectangle->moveBy(someOffsetX, someOffsetY);
            }
            
            M Offline
            M Offline
            mandruk1331
            wrote on 24 Jan 2016, 18:06 last edited by
            #5

            @Chris-Kawa And the last question. How I can do smth like this, for example, I have a red rectangle and after 5 sec it becomes blue during run time?

            Mandruk1331

            1 Reply Last reply
            0
            • C Offline
              C Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on 24 Jan 2016, 18:25 last edited by
              #6

              I have a red rectangle and after 5 sec it becomes blue during run time?

              One way would be with a timer:

              QGraphicsRectItem* rectangle = ... //get it from somewhere
              QTimer::singleShot(5000, [=]{ rectangle->setBrush(Qt::blue); });
              
              
              M 2 Replies Last reply 24 Jan 2016, 18:28
              1
              • C Chris Kawa
                24 Jan 2016, 18:25

                I have a red rectangle and after 5 sec it becomes blue during run time?

                One way would be with a timer:

                QGraphicsRectItem* rectangle = ... //get it from somewhere
                QTimer::singleShot(5000, [=]{ rectangle->setBrush(Qt::blue); });
                
                
                M Offline
                M Offline
                mandruk1331
                wrote on 24 Jan 2016, 18:28 last edited by
                #7

                @Chris-Kawa said:

                QTimer::singleShot(5000, [=]{ rectangle->setBrush(Qt::blue); });

                MOTHER OF GOD! Thank you so much now I can continue with the app :-)

                Mandruk1331

                1 Reply Last reply
                0
                • C Chris Kawa
                  24 Jan 2016, 18:25

                  I have a red rectangle and after 5 sec it becomes blue during run time?

                  One way would be with a timer:

                  QGraphicsRectItem* rectangle = ... //get it from somewhere
                  QTimer::singleShot(5000, [=]{ rectangle->setBrush(Qt::blue); });
                  
                  
                  M Offline
                  M Offline
                  mandruk1331
                  wrote on 24 Jan 2016, 19:16 last edited by
                  #8

                  @Chris-Kawa Ok, got a little bit stuck again how I can update the scene view. For example I found that one rectangle is bigger than the other one how I can animate the swap. I have a list of pointers to the rectangles, after I swapped the pointers in the list, how I can repaint the GraphicsView with the new pointers?

                  Mandruk1331

                  1 Reply Last reply
                  0
                  • C Offline
                    C Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on 24 Jan 2016, 19:26 last edited by
                    #9

                    one rectangle is bigger than the other one how I can animate the swap

                    Sorry, I can't make sense of what you're asking. What swap? What does a rectangle size have to do with it?

                    after I swapped the pointers in the list, how I can repaint the GraphicsView with the new pointers?

                    Again this makes no sense. Moving a pointer in a list has nothing to do with graphics view. Do you mean you want to move the rectangle in the scene or what? A pointer to a graphics item has nothing to do with its position on the scene.

                    What are you trying to do exactly? I mean conceptually.

                    M 1 Reply Last reply 24 Jan 2016, 19:31
                    0
                    • C Chris Kawa
                      24 Jan 2016, 19:26

                      one rectangle is bigger than the other one how I can animate the swap

                      Sorry, I can't make sense of what you're asking. What swap? What does a rectangle size have to do with it?

                      after I swapped the pointers in the list, how I can repaint the GraphicsView with the new pointers?

                      Again this makes no sense. Moving a pointer in a list has nothing to do with graphics view. Do you mean you want to move the rectangle in the scene or what? A pointer to a graphics item has nothing to do with its position on the scene.

                      What are you trying to do exactly? I mean conceptually.

                      M Offline
                      M Offline
                      mandruk1331
                      wrote on 24 Jan 2016, 19:31 last edited by
                      #10

                      @Chris-Kawa I thought I could repaint the new List which contains the pointers. I want to swap two rectangles. The first one is = 3(height) the second one is = 2; I want to swap them, so that on the first position would be rectangle number two with the height of 2, and on the second position would rectangle number one with height = 3. But I want it to swap with some pause, so I could see it, smth like a timer.

                      Mandruk1331

                      1 Reply Last reply
                      0
                      • C Offline
                        C Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on 24 Jan 2016, 19:58 last edited by
                        #11

                        You don't need to repaint anything manually. You just change the position of the item in the scene and it will refresh the view automatically. To animate the move you can use a QGraphicsItemAnimation.

                        Here's a simple example:

                        void moveItemTo(QGraphicsItem* item, const QPointF& endPoint)
                        {
                            QTimeLine* t= new QTimeLine(2000);
                            t->setEasingCurve(QEasingCurve::InOutCubic);
                            QObject::connect(t, &QTimeLine::finished, t, &QTimeLine::deleteLater);
                        
                            QGraphicsItemAnimation* a = new QGraphicsItemAnimation(t);
                            a->setTimeLine(t);
                            a->setItem(item);
                        
                            a->setPosAt(0.0, item->pos());
                            a->setPosAt(1.0, endPoint);
                        
                            timeLine->start();
                        }
                        
                        M 1 Reply Last reply 24 Jan 2016, 20:11
                        1
                        • C Chris Kawa
                          24 Jan 2016, 19:58

                          You don't need to repaint anything manually. You just change the position of the item in the scene and it will refresh the view automatically. To animate the move you can use a QGraphicsItemAnimation.

                          Here's a simple example:

                          void moveItemTo(QGraphicsItem* item, const QPointF& endPoint)
                          {
                              QTimeLine* t= new QTimeLine(2000);
                              t->setEasingCurve(QEasingCurve::InOutCubic);
                              QObject::connect(t, &QTimeLine::finished, t, &QTimeLine::deleteLater);
                          
                              QGraphicsItemAnimation* a = new QGraphicsItemAnimation(t);
                              a->setTimeLine(t);
                              a->setItem(item);
                          
                              a->setPosAt(0.0, item->pos());
                              a->setPosAt(1.0, endPoint);
                          
                              timeLine->start();
                          }
                          
                          M Offline
                          M Offline
                          mandruk1331
                          wrote on 24 Jan 2016, 20:11 last edited by mandruk1331
                          #12

                          @Chris-Kawa I'll give it a try. Thank you a lot. And the last question, for sure, How I can emit a SingleShot every second in a loop, because
                          for(int i=0;i<random_numbers_.size()-1;i++){
                          for(int j=0;j<random_numbers_.size()-1;j++){
                          QTimer::singleShot(1000, [=]{ rectan[i]->setBrush(Qt::green); });
                          }
                          During the executing, after a second it makes every rectangle till the 9-th green, it loops and SingleShots every second in a loop. But how I can do this with a pause, liek: The first one is green, after a second the second becomes green, so I could see it?
                          }

                          Mandruk1331

                          1 Reply Last reply
                          0
                          • C Offline
                            C Offline
                            Chris Kawa
                            Lifetime Qt Champion
                            wrote on 24 Jan 2016, 20:14 last edited by
                            #13
                            for(int i = 0; i < random_numbers_.size(); ++i)
                            {
                                QTimer::singleShot(1000 + i * 1000, [=]{ rectan[i]->setBrush(Qt::green); });
                            }
                            
                            M 1 Reply Last reply 24 Jan 2016, 20:17
                            0
                            • C Chris Kawa
                              24 Jan 2016, 20:14
                              for(int i = 0; i < random_numbers_.size(); ++i)
                              {
                                  QTimer::singleShot(1000 + i * 1000, [=]{ rectan[i]->setBrush(Qt::green); });
                              }
                              
                              M Offline
                              M Offline
                              mandruk1331
                              wrote on 24 Jan 2016, 20:17 last edited by
                              #14

                              @Chris-Kawa I thought about that but is there a way that SingleShot won't be chained by time, because In the future I will need to set the second one green and the first one red, So it'l look like that the rectangle is crawling till the end

                              Mandruk1331

                              1 Reply Last reply
                              0
                              • C Offline
                                C Offline
                                Chris Kawa
                                Lifetime Qt Champion
                                wrote on 24 Jan 2016, 20:41 last edited by Chris Kawa
                                #15

                                Ok, I think you're going deeper and deeper into the woods but it's a totally bad direction.
                                So if I'm getting this right you are making some algorithm that does stuff (sorting?) to some items represented by rectangles and you want to visualize the steps. Is that right?
                                In that case setting up hardcoded timers and single shots is going against the wind because you're effectively tying to predict the whole thing and set timers for it. That's just gonna give you a headache and you won't know what you did the next day.

                                Step back and look at the problem. You've got some algorithm that operates on an array. Conceptually:

                                while(!done())
                                {
                                    doAnotherStep();
                                }
                                

                                Now you want to visualize the steps, conceptually:

                                while(!done())
                                {
                                    doAnotherStep();
                                    visualizeTheStep();
                                }
                                

                                The problem is that the visualization should take time, so this approach is not gonna work. What you need to do is make it event driven, i.e. conceptually:

                                   stepEnded -> visualize
                                   visualizationEnded ->  done ? exit : doAnotherStep
                                

                                For this you can use the signal/slot mechanism of Qt. Make a class that does the algorithm and has a step method. At the end of the method emit a signal. Make another class for visualization and give it a visualize method. At the end of it emit a signal. Then just connect the two.

                                Rough concept:

                                class Algo : public QObject
                                {
                                    Q_OBJECT
                                public:
                                    Algo(Vector<stuff>* data) : dataPtr(data) {}
                                    bool done() {  return /* check if more steps needed */ }
                                    void doStep() { /* do stuff to dataPtr */; emit stepFinished(someStuffToSwap, someOtherStuffToSwap);  }
                                
                                signal:
                                   void stepFinished(stuff* item1, stuff* item2);
                                private:
                                    Vector<stuff>* dataPtr;
                                };
                                
                                class Vis : public QObject
                                {
                                    Q_OBJECT
                                public:
                                    Vis(Vector<stuff>* data) { /*create graphics items and whatnot */   }
                                    void visualizeStep(stuff* item1, stuff* item2) { /* do the animations here and emit finished() when they're done*/ }
                                
                                signals:
                                   void finished();
                                };
                                
                                //and then you can use it like this:
                                Vector<stuff> data = ...
                                Algo algo(&data);
                                Vis vis(&data);
                                
                                connect(algo, &Algo::stepFinished, vis, &Vis::visualizeStep);
                                connect(vis, &Vis::finished(), [&]{ if(!algo.done()) algo.doStep(); });
                                
                                algo.doStep(); /start the first step
                                
                                1 Reply Last reply
                                0

                                1/15

                                24 Jan 2016, 14:50

                                • Login

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