PDA

View Full Version : Same size items with grid positions



MathFurious
1st March 2018, 15:34
Hi,

I want to create list of items(custom class) with same size(200*300px) positioning like grid with items centered, for illustration:
12785

I want items(blue rectangles) have always same size and just jump line if window is scale down.

I tried with QGridLayout but items are on others.

It is possible to do this with layouts?
How can I do what I want?

d_stranz
1st March 2018, 18:29
The Qt Flow Layout example (https://doc.qt.io/qt-5/qtwidgets-layouts-flowlayout-example.html) will do what you want. If all of your items are the same size, it will arrange them into a rectangular grid which will change its dimensions to fit the number of items and the size of the widget holding the layout.

MathFurious
2nd March 2018, 16:12
It's working well but it is possible to center items vertically?

d_stranz
2nd March 2018, 18:46
It's working well but it is possible to center items vertically?

You mean, if the window width is not an even multiple of the items' widths you want equal space on the left and right sides of each row of items? You would have to modify the code in the FlowLayout doLayout() method. The critical section is this bit of code:



int nextX = x + item->sizeHint().width() + spaceX;
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
x = effectiveRect.x();
y = y + lineHeight + spaceY;
nextX = x + item->sizeHint().width() + spaceX;
lineHeight = 0;
}

if (!testOnly)
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));

x = nextX;
lineHeight = qMax(lineHeight, item->sizeHint().height());


The first if() clause is checking to see if there is enough space on the current line to fit the current item. If not, the contents of the clause are executed, which sets the x coordinate of the item to the left side of the layout rectangle (which has been adjusted for margins) and the y coordinate to the top of the next line. After this clause is complete, the geometry for the item is set to whatever has been calculated (eg. further along the current line or at the start of the next line).

The problem with this code is that each item gets laid out, one after the other, and once an item is positioned it is forgotten. What you will need to do instead is accumulate the items and their widths until the line is full, then calculate how much space remains in the width of the "effectiveRect" after subtracting the width of each item, and inter-item spacing. Divide that by two, add it to the x coordinates you've saved, then set the geometry for each item in the line. Clear the arrays of saved items, positions, and sizes and move to the next row.

Alternatively, you can make a two-pass algorithm. Let doLayout() do its thing. After the foreach() loop, make a second pass over the items. As long as the y-coordinate of the item's position is the same, accumulate the widths of the items. That's a row. At the end of the row, do the calculation to determine how much space is left over, and go back over those items to shift their x positions again. Then clear out the stuff you've saved and do the next row, etc. Be sure you don't forget the last row by exiting the loop too soon.

MathFurious
2nd March 2018, 21:58
Sorry, I did not express myself correctly, I want items spread, on each line the spaces between items are all the same.

d_stranz
2nd March 2018, 23:37
OK, that isn't a whole lot different. To keep the layout class as generic as possible, you still need to calculate the width of all the items in each row, then adjust the x positions so that the space between each item is the same. This padding space will be equal to the leftover width / (nItems - 1). So, item 0 has no adjustment (it sits at the left margin of the layout), item 1 sits at item0.x + item0.width + padding, item 2 at item1.x + item1.width + padding, etc.

MathFurious
3rd March 2018, 15:30
Ok, thanks.