Maya like grid layout in qt

qt
python

#1

Hi everyone,

I’m building a widget that is behaving like the maya grid layout that allows to dinamically realign the children.
In maya commands would be something like:

cmds.window()
cmds.scrollLayout(childResizable=1)
aform = cmds.formLayout()
agrid = cmds.gridLayout(nc=1, cr=1, cellWidthHeight=(100,100))
for x in xrange(9): cmds.button(label=x)
cmds.formLayout( aform, e=True, af=(agrid, 'left', 0) )
cmds.formLayout( aform, e=True, af=(agrid, 'top', 0) )
cmds.formLayout( aform, e=True, af=(agrid, 'right', 0) )
cmds.formLayout( aform, e=True, af=(agrid, 'bottom', 0) )
cmds.showWindow()

Now I have made something similar in PySide, that seems to work the same.
The problem is that I’m having a glitch whenever I resize the widget, and that’s annoying.
Maybe I’m doing it in the wrong way… or maybe there is some feature that is already doing the same thing
in Qt that I’m not aware of… but if someone have an hint it would be much appreciated.
Below my code so far:

from PySide2 import QtCore, QtGui, QtWidgets


class GridWidget(QtWidgets.QScrollArea):

    def __init__(self, parent=None):
        super(GridWidget, self).__init__(parent)

        # Internal memory
        self._widgets = []
        self.columns_num = 0
        self._cell_size = QtCore.QSize(60, 60)

        # Internal widgets
        self._internal_widget = QtWidgets.QWidget()
        self._grid = QtWidgets.QGridLayout()
        self._grid.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft)

        # Options
        self._internal_widget.setLayout(self._grid)
        self.setWidget(self._internal_widget)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.setWidgetResizable(True)

    def addWidget(self, widget):
        self._grid.addWidget(widget)
        widget.setFixedSize(self._cell_size)
        self._widgets.append(widget)

    def resizeEvent(self, event):
        """Whenever this widget is resized, the children widget are realigned"""
        super(GridWidget, self).resizeEvent(event)

        # Determinate how many widgets are visible in the current resize event
        self.columns_num = self.size().width() / (self._cell_size.width() + self._grid.margin())

        widget_iter = 0
        col_iter = 0
        row_iter = 0

        while not widget_iter == len(self._widgets):
            self._grid.addWidget(self._widgets[widget_iter], row_iter, col_iter)

            if col_iter != self.columns_num-1:
                col_iter += 1
            else:
                col_iter = 0
                row_iter += 1

            # Place the next widget
            widget_iter += 1


test = GridWidget()

for x in range(50):
    test.addWidget(QtWidgets.QPushButton('hello'))

test.show()

#2

Can you describe the glitch? I just ran it in Max’s python interpreter and it worked as I would expect - unless there’s some behaviour it’s doing that I’m unaware isn’t correct?


#3

Hi Dan,

thanks for the reply!
Look at the attached GIF, with the low framerate is less annoying than it looks when working with it in maya.
But you can see that the resizing has a problem at frame 13


#4

I think you just need to add a bit more to the margin as I think it’s not taking the scroll bar width into consideration.

Quick dirty fix for me is add +20 to this line. You can also disable horizontal scroll bar to prevent it from popping in 'n out annoyingly.

self.columns_num = self.size().width() / (self._cell_size.width() + self._grid.margin() +20)

#5

Totally forgot about this, I found out that was actually the scroll bar like you pointed out.
By computing better the required space the flicker disappeared :slight_smile:
Thank you!