SoFunction
Updated on 2025-04-23

Implementation of pandas using QGraphicsView to automatically arrange items

I want to use QGraphicsView to write a resource browser. It's slightly different from the example using QGraphicsView and QGraphicsItems because I just want to have a scrollbar and I want the item to be able to move automatically when the viewport size changes. For example, when the viewport width is large enough to display 4 assets, they should be displayed like this:

aaaa
aaaa
aa

But when the viewport is reduced and can only hold 3 in a row, it should show up like this:

aaa
aaa
aaa
a

Instead of moving these assets myself, I want to let the graphical view manage them. Is this possible?

I've written something like this once, but using QWidget and paintEvent, draw all the assets yourself and track how many assets can be displayed in a row. Can it be done easier with QGraphicsView?

Solution

Method 1: Use QGraphicsFlowLayout

QGraphicsView supports layout. What you need to do is implement your own layout manager, inherited from QGraphicsLayout.

For the layout you need, check out Qt's flow layout example. Converting this example will give you a QGraphicsFlowLayout. Add your QGraphicsItems to this layout and set the layout of your QGraphicsView to that layout, which will do the job.

Method 2: Use QListWidget

It sounds like you want a list, not a graphical view. You can set the list to display content that wraps the line like you want. See the puzzle example, note the list of puzzle pieces on the left. For the proposed situation, it is very simple to set up.

Of course, if you really want to implement it in a graphical view, I think you can add a list to the view and use it there.

Code Example

from  import QRectF
from  import QBrush, QColor, QPen
from  import QApplication, QGraphicsItem, QGraphicsRectItem, QGraphicsScene, QGraphicsView, QVBoxLayout, QWidget


class QGraphicsFlowLayout(QGraphicsLayout):
    def __init__(self):
        super().__init__()

        self.item_list = []

    def addItem(self, item):
        self.item_list.append(item)

    def count(self):
        return len(self.item_list)

    def itemAt(self, index):
        return self.item_list[index]

    def takeAt(self, index):
        item = self.item_list.pop(index)
        return item

    def boundingRect(self):
        rect = QRectF()
        for item in self.item_list:
            rect |= ()
        return rect

    def sizeHint(self, which, constraint):
        return ().size()

    def minimumSize(self):
        return (, QSizeF())

    def preferredSize(self):
        return (, QSizeF())

    def get_row_width(self):
        row_width = 0
        for item in self.item_list:
            row_width += ().width()
        return row_width

    def get_row_height(self):
        row_height = 0
        for item in self.item_list:
            row_height = max(row_height, ().height())
        return row_height

    def get_num_rows(self, view_width):
        row_width = self.get_row_width()
        num_rows = 1
        if row_width > view_width:
            num_rows = row_width // view_width + 1
        return num_rows

    def get_row_spacing(self):
        return 10

    def get_column_spacing(self):
        return 10

    def get_item_position(self, item, row, column):
        x = column * (().width() + self.get_column_spacing())
        y = row * (().height() + self.get_row_spacing())
        return QPointF(x, y)

    def setGeometry(self, rect):
        view_width = ()
        num_rows = self.get_num_rows(view_width)
        row_height = self.get_row_height()

        for i, item in enumerate(self.item_list):
            row = i // num_rows
            column = i % num_rows
            pos = self.get_item_position(item, row, column)
            (pos)


class QGraphicsFlowView(QGraphicsView):
    def __init__(self):
        super().__init__()

         = QGraphicsScene(self)
         = QGraphicsFlowLayout()
        ()

        ( | )
        ()

    def add_item(self, item):
        (item)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        (())


class QGraphicsFlowItem(QGraphicsRectItem):
    def __init__(self, color):
        super().__init__()

        (0, 0, 100, 100)
        (QBrush(color))
        (QPen(QColor(0, 0, 0), 1))


if __name__ == "__main__":
    app = QApplication([])

    view = QGraphicsFlowView()
    view.add_item(QGraphicsFlowItem(QColor(255, 0, 0)))
    view.add_item(QGraphicsFlowItem(QColor(0, 255, 0)))
    view.add_item(QGraphicsFlowItem(QColor(0, 0, 255)))
    view.add_item(QGraphicsFlowItem(QColor(255, 255, 0)))
    view.add_item(QGraphicsFlowItem(QColor(255, 0, 255)))
    view.add_item(QGraphicsFlowItem(QColor(0, 255, 255)))
    ()

    app.exec_()

This is the end of this article about the implementation of pandas using QGraphicsView to automatically arrange items. For more related pandas QGraphicsView to automatically arrange content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!