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. How to calculate positions in a QGridLayout?
Forum Updated to NodeBB v4.3 + New Features

How to calculate positions in a QGridLayout?

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 5 Posters 642 Views 2 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.
  • Y Offline
    Y Offline
    Ylvy
    wrote on last edited by Ylvy
    #1

    I write this code to create a 'transition' animation, to when new items are added or hidden in the layout
    and also when the number of items per column has changed:

    gif.gif

    As seen on the right, by default the layout just abrupt adjust the frame position
    while on the left it smoothly (the gif lost a lot of the animation quality) move the frame to the adjusted position.

    To achieve this i have created a dummy QScrollArea in which i needed to replicate everything from the
    "original" QScrollArea just to calculate what would be the destination position of the frame.

    I have blow my mind trying to understand how does the layout calculate these positions, appreciate any help
    in how to calculate this, then i wouldnt need a dummy QScrollArea.

    main.cpp

    #include "mainwindow.h"
    #include <QtWidgets/QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        w.dummyWidget->move(w.x() + w.width() + 200, w.y());
        w.dummyWidget->show();
        return a.exec();
    }
    

    mainwindow.h

    #include <QtWidgets/QMainWindow>
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindowClass; };
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        
        bool eventFilter(QObject* obj, QEvent* event);
        void setAnimation(int framePerColumn = 0);
        void setframeCount(int value);
        void setframePerColumn(int value);
    
        QWidget* dummyWidget = nullptr;
        QScrollArea* dummyScrollArea = nullptr;
        QGridLayout* dummyScrollAreaLayout = nullptr;
    
        QScrollArea* scrollArea = nullptr;
        QGridLayout* scrollAreaLayout = nullptr;
    private:
        Ui::MainWindowClass *ui;
    };
    

    mainwindow.cpp

    #include "mainwindow.h"
    
    
    // This eventFilter is just to resize the dummyScrollArea
    // to the same size of the scrollArea.
    bool MainWindow::eventFilter(QObject* obj, QEvent* event)
    {
        if (event->type() == QEvent::Resize)
        {
            QResizeEvent *resizeEvent = dynamic_cast<QResizeEvent*>(event);
            dummyScrollArea->setFixedSize(resizeEvent->size());
            dummyScrollArea->topLevelWidget()->resize(resizeEvent->size());
        }
    
        return false; // false: allow other event filters to process the event.
    }
    
    
    
    void MainWindow::setAnimation(int framePerColumn)
    {
        // Necessary to disable the layout while the 
        // animation is running.
        scrollAreaLayout->setEnabled(false);
    
        QParallelAnimationGroup* animationGroup = new QParallelAnimationGroup();
        QVariantAnimation* frame_ani = nullptr;
        QEasingCurve::Type curve = QEasingCurve::Type::Linear;
        int duration = 400;
        int i = 0;
    
        QVector<QWidget*> frameList;
    
        for (int row = 0; row < dummyScrollAreaLayout->rowCount(); row++)
        {
            for (int col = 0; col < dummyScrollAreaLayout->columnCount(); col++)
            {
                QLayoutItem* dummyItem = dummyScrollAreaLayout->itemAtPosition(row, col);
                if (dummyItem)
                {
                    QLayoutItem* item = scrollAreaLayout->itemAt(i);
                    if (item)
                    {
                        frameList << item->widget();
                        frame_ani = new QPropertyAnimation(item->widget(), "pos");
                        frame_ani->setEasingCurve(curve);
                        frame_ani->setDuration(duration);
                        frame_ani->setStartValue(item->widget()->pos());
                        frame_ani->setEndValue(dummyItem->widget()->pos());
                        animationGroup->addAnimation(frame_ani);
                    }
    		i++;
    	    }
            }
        }
    
    
    
        animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
    
        connect(animationGroup, &QAbstractAnimation::finished, this, [=] 
        {
    	// Readjust the widgets into the rows/ columns.
            if (framePerColumn)
            {
                for (int i = 0; i < frameList.size(); i++)
                    scrollAreaLayout->addWidget(frameList[i], i / framePerColumn, i % framePerColumn);
            }
    
            // Reactivate the layout.
            scrollAreaLayout->setEnabled(true);
            scrollAreaLayout->activate();
        });
    }
    
    
    
    void MainWindow::setframeCount(int value)
    {
        QList<QWidget*> dummyFrameList = 
            dummyScrollArea->viewport()->findChildren<QWidget*>(Qt::FindDirectChildrenOnly);
    
        int frameCount = dummyFrameList.size();
        int framePerColumn = findChild<QSpinBox*>("framePerColumn")->value();
    
    
    
        // Create new frames.
        if (value > frameCount)
        {
            for (int i = 0; i < value; i++)
            {
                if (i < frameCount)
                    dummyFrameList[i]->show();
                else
                {
                    QFrame* frame = new QFrame(dummyScrollArea->viewport());
                    frame->setStyleSheet("QFrame { background-color: rgba(70, 70, 70, 70); border: 0px; }");
                    frame->setFixedSize(100, 100);
                    frame->show();
    
                    QLabel* label = new QLabel(QString::number(i), frame);
                    label->setStyleSheet("font: 24px; font-weight: 900; color: red;");
                    label->show();
    
                    dummyScrollAreaLayout->addWidget(frame, i / framePerColumn, i % framePerColumn);
                }
            }
    
        }
        else
        {
            for (int i = 0; i < frameCount; i++)
            {
                if (i < value)
                    dummyFrameList[i]->show();
                else
                    dummyFrameList[i]->hide();
            }
        }
    
    
    
        // Necessary to force the dummyScrollAreaLayout
        // to update the position of the widgets.
        dummyScrollAreaLayout->activate();
    
    
    
        QList<QWidget*> frameList = 
            scrollArea->viewport()->findChildren<QWidget*>(Qt::FindDirectChildrenOnly);
        frameCount = frameList.size();
    
        // Create new frames.
        if (value > frameCount)
        {
            for (int i = 0; i < value; i++)
            {
                if (i < frameCount)
                    frameList[i]->show();
                else
                {
                    QFrame* frame = new QFrame(scrollArea->viewport());
                    frame->setStyleSheet("QFrame { background-color: rgba(70, 70, 70, 70); border: 0px; }");
                    frame->setGeometry(dummyScrollAreaLayout->itemAt(i)->widget()->geometry());
                    frame->setFixedSize(100, 100);
                    frame->show();
    
                    QLabel* label = new QLabel(QString::number(i), frame);
                    label->setStyleSheet("font: 24px; font-weight: 900; color: red;");
                    label->show();
    
                    frameList << frame;
                    scrollAreaLayout->addWidget(frame, i / framePerColumn, i % framePerColumn);
                }
            }
        }
        else
        {
            for (int i = 0; i < frameCount; i++)
            {
                if (i < value)
                    frameList[i]->show();
                else
                    frameList[i]->hide();
            }
        }
    
    
    
        setAnimation();
    }
    
    
    
    void MainWindow::setframePerColumn(int framePerColumn)
    {
        // Remove all frames and reappend according to
        // framePerColumn value.
        QVector<QLayoutItem*> itemList;
    	while (dummyScrollAreaLayout->count())
    		itemList << dummyScrollAreaLayout->takeAt(0);
    
    	for (int i = 0; i < itemList.size(); i++)
    		dummyScrollAreaLayout->addItem(itemList[i], i / framePerColumn, i % framePerColumn);
    
        // Necessary to force the dummyScrollAreaLayout
        // update the position of the widgets.
        dummyScrollAreaLayout->activate();
    
        setAnimation(framePerColumn);
    }
    
    
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindowClass())
    {
        ui->setupUi(this);
    
        QSpinBox* frameCount = new QSpinBox(this);
        frameCount->setObjectName("frameCount");
        frameCount->setMinimum(1);
        frameCount->setMaximum(100);
        frameCount->setValue(9);
        frameCount->setMaximumWidth(60);
        QLabel* label = new QLabel("Frame count", this);
    
        connect(frameCount, &QSpinBox::valueChanged, this, &MainWindow::setframeCount);
    
    
    
        QSpinBox* framePerColumn = new QSpinBox(this);
        framePerColumn->setObjectName("framePerColumn");
        framePerColumn->setMinimum(1);
        framePerColumn->setMaximum(100);
        framePerColumn->setValue(5);
        framePerColumn->setMaximumWidth(60);
        QLabel* label_2 = new QLabel("Frame per column", this);
    
        connect(framePerColumn, &QSpinBox::valueChanged, this, &MainWindow::setframePerColumn);
    
    
    
        scrollArea = new QScrollArea(this);   
        QWidget* widget = new QWidget(scrollArea);
        scrollArea->installEventFilter(this);
        scrollArea->setViewport(widget);
        scrollArea->setStyleSheet("QScrollArea { background-color: rgba(70, 70, 70, 70); border: 0px; }");
        scrollAreaLayout = new QGridLayout(widget);
    
    
    
         QGridLayout* layout = new QGridLayout(ui->centralWidget);
         layout->addWidget(frameCount, 0, 0);
         layout->addWidget(label, 0, 1);
         layout->addWidget(framePerColumn, 0, 2);
         layout->addWidget(label_2, 0, 3);
    
         QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
         layout->addItem(spacer, 0, 4);
    
         layout->addWidget(scrollArea, 1, 0, 2, 5);
    
    
    
         dummyWidget = new QWidget();
         dummyWidget->setWindowTitle("Dummy QScrollArea");
         dummyScrollArea = new QScrollArea(dummyWidget);   
         widget = new QWidget(dummyScrollArea);
         dummyScrollArea->setViewport(widget);
         dummyScrollArea->setStyleSheet("QScrollArea { background-color: rgba(70, 70, 70, 70); border: 0px; }");
         dummyScrollAreaLayout = new QGridLayout(widget);
       
    }
    
    R JonBJ 2 Replies Last reply
    0
    • Y Ylvy

      I write this code to create a 'transition' animation, to when new items are added or hidden in the layout
      and also when the number of items per column has changed:

      gif.gif

      As seen on the right, by default the layout just abrupt adjust the frame position
      while on the left it smoothly (the gif lost a lot of the animation quality) move the frame to the adjusted position.

      To achieve this i have created a dummy QScrollArea in which i needed to replicate everything from the
      "original" QScrollArea just to calculate what would be the destination position of the frame.

      I have blow my mind trying to understand how does the layout calculate these positions, appreciate any help
      in how to calculate this, then i wouldnt need a dummy QScrollArea.

      main.cpp

      #include "mainwindow.h"
      #include <QtWidgets/QApplication>
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
          MainWindow w;
          w.show();
      
          w.dummyWidget->move(w.x() + w.width() + 200, w.y());
          w.dummyWidget->show();
          return a.exec();
      }
      

      mainwindow.h

      #include <QtWidgets/QMainWindow>
      
      QT_BEGIN_NAMESPACE
      namespace Ui { class MainWindowClass; };
      QT_END_NAMESPACE
      
      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          MainWindow(QWidget *parent = nullptr);
          
          bool eventFilter(QObject* obj, QEvent* event);
          void setAnimation(int framePerColumn = 0);
          void setframeCount(int value);
          void setframePerColumn(int value);
      
          QWidget* dummyWidget = nullptr;
          QScrollArea* dummyScrollArea = nullptr;
          QGridLayout* dummyScrollAreaLayout = nullptr;
      
          QScrollArea* scrollArea = nullptr;
          QGridLayout* scrollAreaLayout = nullptr;
      private:
          Ui::MainWindowClass *ui;
      };
      

      mainwindow.cpp

      #include "mainwindow.h"
      
      
      // This eventFilter is just to resize the dummyScrollArea
      // to the same size of the scrollArea.
      bool MainWindow::eventFilter(QObject* obj, QEvent* event)
      {
          if (event->type() == QEvent::Resize)
          {
              QResizeEvent *resizeEvent = dynamic_cast<QResizeEvent*>(event);
              dummyScrollArea->setFixedSize(resizeEvent->size());
              dummyScrollArea->topLevelWidget()->resize(resizeEvent->size());
          }
      
          return false; // false: allow other event filters to process the event.
      }
      
      
      
      void MainWindow::setAnimation(int framePerColumn)
      {
          // Necessary to disable the layout while the 
          // animation is running.
          scrollAreaLayout->setEnabled(false);
      
          QParallelAnimationGroup* animationGroup = new QParallelAnimationGroup();
          QVariantAnimation* frame_ani = nullptr;
          QEasingCurve::Type curve = QEasingCurve::Type::Linear;
          int duration = 400;
          int i = 0;
      
          QVector<QWidget*> frameList;
      
          for (int row = 0; row < dummyScrollAreaLayout->rowCount(); row++)
          {
              for (int col = 0; col < dummyScrollAreaLayout->columnCount(); col++)
              {
                  QLayoutItem* dummyItem = dummyScrollAreaLayout->itemAtPosition(row, col);
                  if (dummyItem)
                  {
                      QLayoutItem* item = scrollAreaLayout->itemAt(i);
                      if (item)
                      {
                          frameList << item->widget();
                          frame_ani = new QPropertyAnimation(item->widget(), "pos");
                          frame_ani->setEasingCurve(curve);
                          frame_ani->setDuration(duration);
                          frame_ani->setStartValue(item->widget()->pos());
                          frame_ani->setEndValue(dummyItem->widget()->pos());
                          animationGroup->addAnimation(frame_ani);
                      }
      		i++;
      	    }
              }
          }
      
      
      
          animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
      
          connect(animationGroup, &QAbstractAnimation::finished, this, [=] 
          {
      	// Readjust the widgets into the rows/ columns.
              if (framePerColumn)
              {
                  for (int i = 0; i < frameList.size(); i++)
                      scrollAreaLayout->addWidget(frameList[i], i / framePerColumn, i % framePerColumn);
              }
      
              // Reactivate the layout.
              scrollAreaLayout->setEnabled(true);
              scrollAreaLayout->activate();
          });
      }
      
      
      
      void MainWindow::setframeCount(int value)
      {
          QList<QWidget*> dummyFrameList = 
              dummyScrollArea->viewport()->findChildren<QWidget*>(Qt::FindDirectChildrenOnly);
      
          int frameCount = dummyFrameList.size();
          int framePerColumn = findChild<QSpinBox*>("framePerColumn")->value();
      
      
      
          // Create new frames.
          if (value > frameCount)
          {
              for (int i = 0; i < value; i++)
              {
                  if (i < frameCount)
                      dummyFrameList[i]->show();
                  else
                  {
                      QFrame* frame = new QFrame(dummyScrollArea->viewport());
                      frame->setStyleSheet("QFrame { background-color: rgba(70, 70, 70, 70); border: 0px; }");
                      frame->setFixedSize(100, 100);
                      frame->show();
      
                      QLabel* label = new QLabel(QString::number(i), frame);
                      label->setStyleSheet("font: 24px; font-weight: 900; color: red;");
                      label->show();
      
                      dummyScrollAreaLayout->addWidget(frame, i / framePerColumn, i % framePerColumn);
                  }
              }
      
          }
          else
          {
              for (int i = 0; i < frameCount; i++)
              {
                  if (i < value)
                      dummyFrameList[i]->show();
                  else
                      dummyFrameList[i]->hide();
              }
          }
      
      
      
          // Necessary to force the dummyScrollAreaLayout
          // to update the position of the widgets.
          dummyScrollAreaLayout->activate();
      
      
      
          QList<QWidget*> frameList = 
              scrollArea->viewport()->findChildren<QWidget*>(Qt::FindDirectChildrenOnly);
          frameCount = frameList.size();
      
          // Create new frames.
          if (value > frameCount)
          {
              for (int i = 0; i < value; i++)
              {
                  if (i < frameCount)
                      frameList[i]->show();
                  else
                  {
                      QFrame* frame = new QFrame(scrollArea->viewport());
                      frame->setStyleSheet("QFrame { background-color: rgba(70, 70, 70, 70); border: 0px; }");
                      frame->setGeometry(dummyScrollAreaLayout->itemAt(i)->widget()->geometry());
                      frame->setFixedSize(100, 100);
                      frame->show();
      
                      QLabel* label = new QLabel(QString::number(i), frame);
                      label->setStyleSheet("font: 24px; font-weight: 900; color: red;");
                      label->show();
      
                      frameList << frame;
                      scrollAreaLayout->addWidget(frame, i / framePerColumn, i % framePerColumn);
                  }
              }
          }
          else
          {
              for (int i = 0; i < frameCount; i++)
              {
                  if (i < value)
                      frameList[i]->show();
                  else
                      frameList[i]->hide();
              }
          }
      
      
      
          setAnimation();
      }
      
      
      
      void MainWindow::setframePerColumn(int framePerColumn)
      {
          // Remove all frames and reappend according to
          // framePerColumn value.
          QVector<QLayoutItem*> itemList;
      	while (dummyScrollAreaLayout->count())
      		itemList << dummyScrollAreaLayout->takeAt(0);
      
      	for (int i = 0; i < itemList.size(); i++)
      		dummyScrollAreaLayout->addItem(itemList[i], i / framePerColumn, i % framePerColumn);
      
          // Necessary to force the dummyScrollAreaLayout
          // update the position of the widgets.
          dummyScrollAreaLayout->activate();
      
          setAnimation(framePerColumn);
      }
      
      
      
      MainWindow::MainWindow(QWidget *parent)
          : QMainWindow(parent)
          , ui(new Ui::MainWindowClass())
      {
          ui->setupUi(this);
      
          QSpinBox* frameCount = new QSpinBox(this);
          frameCount->setObjectName("frameCount");
          frameCount->setMinimum(1);
          frameCount->setMaximum(100);
          frameCount->setValue(9);
          frameCount->setMaximumWidth(60);
          QLabel* label = new QLabel("Frame count", this);
      
          connect(frameCount, &QSpinBox::valueChanged, this, &MainWindow::setframeCount);
      
      
      
          QSpinBox* framePerColumn = new QSpinBox(this);
          framePerColumn->setObjectName("framePerColumn");
          framePerColumn->setMinimum(1);
          framePerColumn->setMaximum(100);
          framePerColumn->setValue(5);
          framePerColumn->setMaximumWidth(60);
          QLabel* label_2 = new QLabel("Frame per column", this);
      
          connect(framePerColumn, &QSpinBox::valueChanged, this, &MainWindow::setframePerColumn);
      
      
      
          scrollArea = new QScrollArea(this);   
          QWidget* widget = new QWidget(scrollArea);
          scrollArea->installEventFilter(this);
          scrollArea->setViewport(widget);
          scrollArea->setStyleSheet("QScrollArea { background-color: rgba(70, 70, 70, 70); border: 0px; }");
          scrollAreaLayout = new QGridLayout(widget);
      
      
      
           QGridLayout* layout = new QGridLayout(ui->centralWidget);
           layout->addWidget(frameCount, 0, 0);
           layout->addWidget(label, 0, 1);
           layout->addWidget(framePerColumn, 0, 2);
           layout->addWidget(label_2, 0, 3);
      
           QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
           layout->addItem(spacer, 0, 4);
      
           layout->addWidget(scrollArea, 1, 0, 2, 5);
      
      
      
           dummyWidget = new QWidget();
           dummyWidget->setWindowTitle("Dummy QScrollArea");
           dummyScrollArea = new QScrollArea(dummyWidget);   
           widget = new QWidget(dummyScrollArea);
           dummyScrollArea->setViewport(widget);
           dummyScrollArea->setStyleSheet("QScrollArea { background-color: rgba(70, 70, 70, 70); border: 0px; }");
           dummyScrollAreaLayout = new QGridLayout(widget);
         
      }
      
      R Offline
      R Offline
      Roberrt
      wrote on last edited by
      #2

      I am not sure I understand. Your animation and the text with it is about how widgets teleport from one place (which appears to be correct) to another (which also appears to be correct). It does not looks like you have any trouble using the layout to place widgets in it, as your question title suggest. Could you please clarify?

      Y 1 Reply Last reply
      1
      • R Roberrt

        I am not sure I understand. Your animation and the text with it is about how widgets teleport from one place (which appears to be correct) to another (which also appears to be correct). It does not looks like you have any trouble using the layout to place widgets in it, as your question title suggest. Could you please clarify?

        Y Offline
        Y Offline
        Ylvy
        wrote on last edited by
        #3

        @Roberrt
        To be more precise my question is how to calculate what will be the widgets positions after the layout has been modified.

        For example, when there's 6 widget in the GridLayout, 3 per column:

        |--| (0,0)       |--| (150,0)       |--| (250, 0)
        |--| (0,150)     |--| (150,150)     |--| (250, 150)
        

        and it will be changed to 2 widget per column:

        |--| (?,?)       |--| (?,?)
        |--| (?,?)       |--| (?,?)
        |--| (?, ?)      |--| (?, ?)
        

        How to calculate what will be the new position of each widgets in the layout? In my example code above I have created the dummy QScrollArea just to get these (?,?) positions because I didn't understand how to calculate it.

        All widgets have a fixed size, the layout size constraint is SetDefaultConstraint.

        1 Reply Last reply
        0
        • Y Ylvy

          I write this code to create a 'transition' animation, to when new items are added or hidden in the layout
          and also when the number of items per column has changed:

          gif.gif

          As seen on the right, by default the layout just abrupt adjust the frame position
          while on the left it smoothly (the gif lost a lot of the animation quality) move the frame to the adjusted position.

          To achieve this i have created a dummy QScrollArea in which i needed to replicate everything from the
          "original" QScrollArea just to calculate what would be the destination position of the frame.

          I have blow my mind trying to understand how does the layout calculate these positions, appreciate any help
          in how to calculate this, then i wouldnt need a dummy QScrollArea.

          main.cpp

          #include "mainwindow.h"
          #include <QtWidgets/QApplication>
          
          int main(int argc, char *argv[])
          {
              QApplication a(argc, argv);
              MainWindow w;
              w.show();
          
              w.dummyWidget->move(w.x() + w.width() + 200, w.y());
              w.dummyWidget->show();
              return a.exec();
          }
          

          mainwindow.h

          #include <QtWidgets/QMainWindow>
          
          QT_BEGIN_NAMESPACE
          namespace Ui { class MainWindowClass; };
          QT_END_NAMESPACE
          
          class MainWindow : public QMainWindow
          {
              Q_OBJECT
          
          public:
              MainWindow(QWidget *parent = nullptr);
              
              bool eventFilter(QObject* obj, QEvent* event);
              void setAnimation(int framePerColumn = 0);
              void setframeCount(int value);
              void setframePerColumn(int value);
          
              QWidget* dummyWidget = nullptr;
              QScrollArea* dummyScrollArea = nullptr;
              QGridLayout* dummyScrollAreaLayout = nullptr;
          
              QScrollArea* scrollArea = nullptr;
              QGridLayout* scrollAreaLayout = nullptr;
          private:
              Ui::MainWindowClass *ui;
          };
          

          mainwindow.cpp

          #include "mainwindow.h"
          
          
          // This eventFilter is just to resize the dummyScrollArea
          // to the same size of the scrollArea.
          bool MainWindow::eventFilter(QObject* obj, QEvent* event)
          {
              if (event->type() == QEvent::Resize)
              {
                  QResizeEvent *resizeEvent = dynamic_cast<QResizeEvent*>(event);
                  dummyScrollArea->setFixedSize(resizeEvent->size());
                  dummyScrollArea->topLevelWidget()->resize(resizeEvent->size());
              }
          
              return false; // false: allow other event filters to process the event.
          }
          
          
          
          void MainWindow::setAnimation(int framePerColumn)
          {
              // Necessary to disable the layout while the 
              // animation is running.
              scrollAreaLayout->setEnabled(false);
          
              QParallelAnimationGroup* animationGroup = new QParallelAnimationGroup();
              QVariantAnimation* frame_ani = nullptr;
              QEasingCurve::Type curve = QEasingCurve::Type::Linear;
              int duration = 400;
              int i = 0;
          
              QVector<QWidget*> frameList;
          
              for (int row = 0; row < dummyScrollAreaLayout->rowCount(); row++)
              {
                  for (int col = 0; col < dummyScrollAreaLayout->columnCount(); col++)
                  {
                      QLayoutItem* dummyItem = dummyScrollAreaLayout->itemAtPosition(row, col);
                      if (dummyItem)
                      {
                          QLayoutItem* item = scrollAreaLayout->itemAt(i);
                          if (item)
                          {
                              frameList << item->widget();
                              frame_ani = new QPropertyAnimation(item->widget(), "pos");
                              frame_ani->setEasingCurve(curve);
                              frame_ani->setDuration(duration);
                              frame_ani->setStartValue(item->widget()->pos());
                              frame_ani->setEndValue(dummyItem->widget()->pos());
                              animationGroup->addAnimation(frame_ani);
                          }
          		i++;
          	    }
                  }
              }
          
          
          
              animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
          
              connect(animationGroup, &QAbstractAnimation::finished, this, [=] 
              {
          	// Readjust the widgets into the rows/ columns.
                  if (framePerColumn)
                  {
                      for (int i = 0; i < frameList.size(); i++)
                          scrollAreaLayout->addWidget(frameList[i], i / framePerColumn, i % framePerColumn);
                  }
          
                  // Reactivate the layout.
                  scrollAreaLayout->setEnabled(true);
                  scrollAreaLayout->activate();
              });
          }
          
          
          
          void MainWindow::setframeCount(int value)
          {
              QList<QWidget*> dummyFrameList = 
                  dummyScrollArea->viewport()->findChildren<QWidget*>(Qt::FindDirectChildrenOnly);
          
              int frameCount = dummyFrameList.size();
              int framePerColumn = findChild<QSpinBox*>("framePerColumn")->value();
          
          
          
              // Create new frames.
              if (value > frameCount)
              {
                  for (int i = 0; i < value; i++)
                  {
                      if (i < frameCount)
                          dummyFrameList[i]->show();
                      else
                      {
                          QFrame* frame = new QFrame(dummyScrollArea->viewport());
                          frame->setStyleSheet("QFrame { background-color: rgba(70, 70, 70, 70); border: 0px; }");
                          frame->setFixedSize(100, 100);
                          frame->show();
          
                          QLabel* label = new QLabel(QString::number(i), frame);
                          label->setStyleSheet("font: 24px; font-weight: 900; color: red;");
                          label->show();
          
                          dummyScrollAreaLayout->addWidget(frame, i / framePerColumn, i % framePerColumn);
                      }
                  }
          
              }
              else
              {
                  for (int i = 0; i < frameCount; i++)
                  {
                      if (i < value)
                          dummyFrameList[i]->show();
                      else
                          dummyFrameList[i]->hide();
                  }
              }
          
          
          
              // Necessary to force the dummyScrollAreaLayout
              // to update the position of the widgets.
              dummyScrollAreaLayout->activate();
          
          
          
              QList<QWidget*> frameList = 
                  scrollArea->viewport()->findChildren<QWidget*>(Qt::FindDirectChildrenOnly);
              frameCount = frameList.size();
          
              // Create new frames.
              if (value > frameCount)
              {
                  for (int i = 0; i < value; i++)
                  {
                      if (i < frameCount)
                          frameList[i]->show();
                      else
                      {
                          QFrame* frame = new QFrame(scrollArea->viewport());
                          frame->setStyleSheet("QFrame { background-color: rgba(70, 70, 70, 70); border: 0px; }");
                          frame->setGeometry(dummyScrollAreaLayout->itemAt(i)->widget()->geometry());
                          frame->setFixedSize(100, 100);
                          frame->show();
          
                          QLabel* label = new QLabel(QString::number(i), frame);
                          label->setStyleSheet("font: 24px; font-weight: 900; color: red;");
                          label->show();
          
                          frameList << frame;
                          scrollAreaLayout->addWidget(frame, i / framePerColumn, i % framePerColumn);
                      }
                  }
              }
              else
              {
                  for (int i = 0; i < frameCount; i++)
                  {
                      if (i < value)
                          frameList[i]->show();
                      else
                          frameList[i]->hide();
                  }
              }
          
          
          
              setAnimation();
          }
          
          
          
          void MainWindow::setframePerColumn(int framePerColumn)
          {
              // Remove all frames and reappend according to
              // framePerColumn value.
              QVector<QLayoutItem*> itemList;
          	while (dummyScrollAreaLayout->count())
          		itemList << dummyScrollAreaLayout->takeAt(0);
          
          	for (int i = 0; i < itemList.size(); i++)
          		dummyScrollAreaLayout->addItem(itemList[i], i / framePerColumn, i % framePerColumn);
          
              // Necessary to force the dummyScrollAreaLayout
              // update the position of the widgets.
              dummyScrollAreaLayout->activate();
          
              setAnimation(framePerColumn);
          }
          
          
          
          MainWindow::MainWindow(QWidget *parent)
              : QMainWindow(parent)
              , ui(new Ui::MainWindowClass())
          {
              ui->setupUi(this);
          
              QSpinBox* frameCount = new QSpinBox(this);
              frameCount->setObjectName("frameCount");
              frameCount->setMinimum(1);
              frameCount->setMaximum(100);
              frameCount->setValue(9);
              frameCount->setMaximumWidth(60);
              QLabel* label = new QLabel("Frame count", this);
          
              connect(frameCount, &QSpinBox::valueChanged, this, &MainWindow::setframeCount);
          
          
          
              QSpinBox* framePerColumn = new QSpinBox(this);
              framePerColumn->setObjectName("framePerColumn");
              framePerColumn->setMinimum(1);
              framePerColumn->setMaximum(100);
              framePerColumn->setValue(5);
              framePerColumn->setMaximumWidth(60);
              QLabel* label_2 = new QLabel("Frame per column", this);
          
              connect(framePerColumn, &QSpinBox::valueChanged, this, &MainWindow::setframePerColumn);
          
          
          
              scrollArea = new QScrollArea(this);   
              QWidget* widget = new QWidget(scrollArea);
              scrollArea->installEventFilter(this);
              scrollArea->setViewport(widget);
              scrollArea->setStyleSheet("QScrollArea { background-color: rgba(70, 70, 70, 70); border: 0px; }");
              scrollAreaLayout = new QGridLayout(widget);
          
          
          
               QGridLayout* layout = new QGridLayout(ui->centralWidget);
               layout->addWidget(frameCount, 0, 0);
               layout->addWidget(label, 0, 1);
               layout->addWidget(framePerColumn, 0, 2);
               layout->addWidget(label_2, 0, 3);
          
               QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
               layout->addItem(spacer, 0, 4);
          
               layout->addWidget(scrollArea, 1, 0, 2, 5);
          
          
          
               dummyWidget = new QWidget();
               dummyWidget->setWindowTitle("Dummy QScrollArea");
               dummyScrollArea = new QScrollArea(dummyWidget);   
               widget = new QWidget(dummyScrollArea);
               dummyScrollArea->setViewport(widget);
               dummyScrollArea->setStyleSheet("QScrollArea { background-color: rgba(70, 70, 70, 70); border: 0px; }");
               dummyScrollAreaLayout = new QGridLayout(widget);
             
          }
          
          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #4

          @Ylvy said in How to calculate positions in a QGridLayout?:

          I have blow my mind trying to understand how does the layout calculate these positions

          I think the simple answer will be "with a lot of code"! I imagine looking at the sources would confirm this :) I came across https://robertknight.me.uk/posts/qt-widget-layout/, which is a decade old, but probably gives some idea of the complexities.

          Your current solution seems to be pretty clever, if it produces the animation you show!

          There is a QWidget::moveEvent(). Does the re-layout cause this to be called? It says "When the widget receives this event, it is already at the new position.", I don't know if that is too late for your animated move?

          There is also QLayoutItem::setGeometry(), which is virtual.

          Both of these would involve subclassing, not sure you would want to do this. You could place an event filter to see whether e.g. move events are sent to each widget which you could recognise and act on?

          Y 1 Reply Last reply
          0
          • JonBJ JonB

            @Ylvy said in How to calculate positions in a QGridLayout?:

            I have blow my mind trying to understand how does the layout calculate these positions

            I think the simple answer will be "with a lot of code"! I imagine looking at the sources would confirm this :) I came across https://robertknight.me.uk/posts/qt-widget-layout/, which is a decade old, but probably gives some idea of the complexities.

            Your current solution seems to be pretty clever, if it produces the animation you show!

            There is a QWidget::moveEvent(). Does the re-layout cause this to be called? It says "When the widget receives this event, it is already at the new position.", I don't know if that is too late for your animated move?

            There is also QLayoutItem::setGeometry(), which is virtual.

            Both of these would involve subclassing, not sure you would want to do this. You could place an event filter to see whether e.g. move events are sent to each widget which you could recognise and act on?

            Y Offline
            Y Offline
            Ylvy
            wrote on last edited by
            #5

            @JonB said in How to calculate positions in a QGridLayout?:

            There is a QWidget::moveEvent(). Does the re-layout cause this to be called? It says "When the widget receives this event, it is already at the new position.", I don't know if that is too late for your animated move?

            I didnt understand how to use QWidget::moveEvent() in this case, what you mean re-layout?

            JonBJ Axel SpoerlA 2 Replies Last reply
            0
            • Y Ylvy

              @JonB said in How to calculate positions in a QGridLayout?:

              There is a QWidget::moveEvent(). Does the re-layout cause this to be called? It says "When the widget receives this event, it is already at the new position.", I don't know if that is too late for your animated move?

              I didnt understand how to use QWidget::moveEvent() in this case, what you mean re-layout?

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #6

              @Ylvy
              By "re-layout" I mean whatever has triggered your need to change the layout as you show

              when new items are added or hidden in the layout

              and also when the number of items per column has changed:

              1 Reply Last reply
              0
              • Y Ylvy

                @JonB said in How to calculate positions in a QGridLayout?:

                There is a QWidget::moveEvent(). Does the re-layout cause this to be called? It says "When the widget receives this event, it is already at the new position.", I don't know if that is too late for your animated move?

                I didnt understand how to use QWidget::moveEvent() in this case, what you mean re-layout?

                Axel SpoerlA Offline
                Axel SpoerlA Offline
                Axel Spoerl
                Moderators
                wrote on last edited by
                #7

                @Ylvy
                If the goal is to find out how the position of a QWidget is calculated in a QGridLayout, the answer is straight forward: Look at the code of QGridLayout. That's where the calculation you are looking for takes place.

                That said, I see neither benefit nor use-case of replicating that calculation elsewhere. If the goal is to know where the widgets are after a resize and a possible re-arrangement: QWindow::geometry() will tell. Since resizing can happen asynchronously, it may be useful to connect to one of the widget's window handle's signals firing when x, y, height or width have changed.

                Software Engineer
                The Qt Company, Oslo

                SGaistS 1 Reply Last reply
                1
                • Axel SpoerlA Axel Spoerl

                  @Ylvy
                  If the goal is to find out how the position of a QWidget is calculated in a QGridLayout, the answer is straight forward: Look at the code of QGridLayout. That's where the calculation you are looking for takes place.

                  That said, I see neither benefit nor use-case of replicating that calculation elsewhere. If the goal is to know where the widgets are after a resize and a possible re-arrangement: QWindow::geometry() will tell. Since resizing can happen asynchronously, it may be useful to connect to one of the widget's window handle's signals firing when x, y, height or width have changed.

                  SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  Hi,

                  Did you already took a look at the Flow Layout Example ?

                  It might also be of interest for what you want to do.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  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