How to calculate positions in a QGridLayout?
-
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: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); }
-
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: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); }
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?
-
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?
@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 thedummy
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 isSetDefaultConstraint
. -
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: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); }
@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?
-
@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?
@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? -
@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? -
@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?@Ylvy
If the goal is to find out how the position of aQWidget
is calculated in aQGridLayout
, the answer is straight forward: Look at the code ofQGridLayout
. 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. -
@Ylvy
If the goal is to find out how the position of aQWidget
is calculated in aQGridLayout
, the answer is straight forward: Look at the code ofQGridLayout
. 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.Hi,
Did you already took a look at the Flow Layout Example ?
It might also be of interest for what you want to do.