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.
  • mandruk1331M Offline
    mandruk1331M Offline
    mandruk1331
    wrote on 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
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on 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.

      mandruk1331M 1 Reply Last reply
      1
      • Chris KawaC Chris Kawa

        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.

        mandruk1331M Offline
        mandruk1331M Offline
        mandruk1331
        wrote on 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
        • Chris KawaC Offline
          Chris KawaC Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on 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);
          }
          
          mandruk1331M 1 Reply Last reply
          1
          • Chris KawaC Chris Kawa

            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);
            }
            
            mandruk1331M Offline
            mandruk1331M Offline
            mandruk1331
            wrote on 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
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on 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); });
              
              
              mandruk1331M 2 Replies Last reply
              1
              • Chris KawaC Chris Kawa

                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); });
                
                
                mandruk1331M Offline
                mandruk1331M Offline
                mandruk1331
                wrote on 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
                • Chris KawaC Chris Kawa

                  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); });
                  
                  
                  mandruk1331M Offline
                  mandruk1331M Offline
                  mandruk1331
                  wrote on 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
                  • Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on 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.

                    mandruk1331M 1 Reply Last reply
                    0
                    • Chris KawaC Chris Kawa

                      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.

                      mandruk1331M Offline
                      mandruk1331M Offline
                      mandruk1331
                      wrote on 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
                      • Chris KawaC Offline
                        Chris KawaC Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on 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();
                        }
                        
                        mandruk1331M 1 Reply Last reply
                        1
                        • Chris KawaC Chris Kawa

                          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();
                          }
                          
                          mandruk1331M Offline
                          mandruk1331M Offline
                          mandruk1331
                          wrote on 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
                          • Chris KawaC Offline
                            Chris KawaC Offline
                            Chris Kawa
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13
                            for(int i = 0; i < random_numbers_.size(); ++i)
                            {
                                QTimer::singleShot(1000 + i * 1000, [=]{ rectan[i]->setBrush(Qt::green); });
                            }
                            
                            mandruk1331M 1 Reply Last reply
                            0
                            • Chris KawaC Chris Kawa
                              for(int i = 0; i < random_numbers_.size(); ++i)
                              {
                                  QTimer::singleShot(1000 + i * 1000, [=]{ rectan[i]->setBrush(Qt::green); });
                              }
                              
                              mandruk1331M Offline
                              mandruk1331M Offline
                              mandruk1331
                              wrote on 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
                              • Chris KawaC Offline
                                Chris KawaC Offline
                                Chris Kawa
                                Lifetime Qt Champion
                                wrote on 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

                                • Login

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