Maya flowLayout within a scrollLayout

So I’m working on an interface for something, and am having an issue I’m kind of hitting a wall on. In essence, what I’m trying to do is replicate the behavior similar to the top-right pane in hypershade. A variable length list of controls in a scroll area that interactively go down to new rows when the layout gets too narrow to accommodate the width. Another requirement is that it has to all be happening within a collapsible frame.

The really big problem I’m running in to is that the flowLayout doesn’t appear to be capable of interactively changing in height according to how many rows there are as far as I know. It just kind of just wraps in to nothing if the height of the layout isn’t there to support it.

What I ideally would actually have (just to throw it out there just in case anyone’s achieved it) is actually just to have the frameLayout shrink and grow in height according to the height of the flowLayout because in the actual window, I’m having all of those collapsible frames within a scrollLayout anyways. but I see that just having a box with a scrollLayout within has been done in the case of hypershade. Problem I’m running in to though is attaching the bottom of the parent formLayout to the bottom of the scrollLayout, since it doesn’t really have a bottom.

Here’s a little snippet of what I currently have that I grabbed from the script and re-formatted to work on its own. Just in case anyone’s unfamiliar with working with PyMEL, I tried to comment on the pymel specific things that are there.


import pymel.core as pm
pm.window()

pm.frameLayout('Some Folder (10 Entries)', cll=True, cl=True)
scr = pm.scrollLayout(cr=True)
formLwt = pm.horizontalLayout() # a special pymel formlayout class that can distribute all children horizontally
flowLwt = pm.flowLayout(cs=5, wr=True, p=formLwt)

pm.button()
pm.button()
pm.button()
pm.button()
pm.button()
pm.button()
pm.button()
pm.button()
pm.button()

formLwt.redistribute() # since there's only one child, it's just the same as attaching position to either edge
formLwt.attachPosition(flowLwt, 'bottom', 0, 100) #same as pm.formLayout(formLwt, e=True, ap=[flowLwt, 'bottom', 0, 100])

pm.showWindow()

Alternatively, does anyone know how to access the resizeEvent method in the QT Widget as it’s implemented in Maya? I haven’t been able to successfully do that in any Maya UI element. The ideal would be the flowLayout, but if I could just get a Maya Window, that would work as well. That’s another way I could approach it, but I keep trying unsuccessfully to make a resizeEvent trigger anything in either.

I’m running pm.toQtObject to get the instance, but can’t get the resizeEvent to do anything.

So, triple post. I think I’ve found a kind of way to work it, though I’m open to a more graceful solution should anyone think of anything. I figure I’ll post here just in case anyone else ever runs in to the problem anyways. I can just parent the Maya layouts under a Qt Widget. I tried doing it the other way around by putting a full QT widget under a Maya Layout, but I couldn’t figure out how to match and therefore track the parent width. Here’s a quick illustration of the tracking with a similar configuration. I can then get the width of the layout to change the height of the layout(s)

import pymel.core as pm
from PyQt4 import QtGui
from PyQt4 import QtCore


class QtWindow(QtGui.QWidget):

    @classmethod
    def makeShowWindow(cls):

        w = cls()
        w.winEdit()
        w.show()

    def __init__(self):

        parent = pm.toQtObject(pm.Mel.eval('$temp = $gMainWindow;'))
        QtGui.QWidget.__init__(self, parent, QtCore.Qt.Dialog | QtCore.Qt.WindowMinMaxButtonsHint | QtCore.Qt.WindowStaysOnTopHint)


    def winEdit(self):

        grid = QtGui.QGridLayout(self)

        win = pm.window()

        self.frame = pm.frameLayout('Some Folder (10 Entries)', cll=False)

        child = win.asQtObject()
        pm.showWindow(win)
        grid.addWidget(child)


    def resizeEvent(self, event):

        print self.frame.asQtObject().size()

QtWindow.makeShowWindow()

I adapted the flowLayout example from Qt to PyQt4. I ended up not using it, but maybe it can provide some insight to your problem.


"""PyQt4 port of the layouts/flowlayout example from Qt v4.x"""

from PySide import QtCore, QtGui


class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()

        flowLayout = FlowLayout()
        flowLayout.addWidget(QtGui.QPushButton("Short"))
        flowLayout.addWidget(QtGui.QPushButton("Longer"))
        flowLayout.addWidget(QtGui.QPushButton("Different text"))
        flowLayout.addWidget(QtGui.QPushButton("More text"))
        flowLayout.addWidget(QtGui.QPushButton("Even longer button text"))
        self.setLayout(flowLayout)

        self.setWindowTitle("Flow Layout")


class FlowLayout(QtGui.QLayout):
    def __init__(self, parent=None, margin=0, spacing=-1):
        super(FlowLayout, self).__init__(parent)

        if parent is not None:
            self.setMargin(margin)

        self.setSpacing(spacing)

        self.itemList = []

    def __del__(self):
        item = self.takeAt(0)
        while item:
            item = self.takeAt(0)

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

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

    def itemAt(self, index):
        if index >= 0 and index < len(self.itemList):
            return self.itemList[index]

        return None

    def takeAt(self, index):
        if index >= 0 and index < len(self.itemList):
            return self.itemList.pop(index)

        return None

    def expandingDirections(self):
        return QtCore.Qt.Orientations(QtCore.Qt.Orientation(0))

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        height = self.doLayout(QtCore.QRect(0, 0, width, 0), True)
        return height

    def setGeometry(self, rect):
        super(FlowLayout, self).setGeometry(rect)
        self.doLayout(rect, False)

    def sizeHint(self):
        return self.minimumSize()

    def minimumSize(self):
        size = QtCore.QSize()

        for item in self.itemList:
            size = size.expandedTo(item.minimumSize())

        size += QtCore.QSize(2 * self.spacing(), 2 * self.spacing())
        return size

    def doLayout(self, rect, testOnly):
        x = rect.x()
        y = rect.y()
        lineHeight = 0

        for item in self.itemList:
            wid = item.widget()
            spaceX = self.spacing() + wid.style().layoutSpacing(QtGui.QSizePolicy.PushButton, QtGui.QSizePolicy.PushButton, QtCore.Qt.Horizontal)
            spaceY = self.spacing() + wid.style().layoutSpacing(QtGui.QSizePolicy.PushButton, QtGui.QSizePolicy.PushButton, QtCore.Qt.Vertical)
            nextX = x + item.sizeHint().width() + spaceX
            if nextX - spaceX > rect.right() and lineHeight > 0:
                x = rect.x()
                y = y + lineHeight + spaceY
                nextX = x + item.sizeHint().width() + spaceX
                lineHeight = 0

            if not testOnly:
                item.setGeometry(QtCore.QRect(QtCore.QPoint(x, y), item.sizeHint()))

            x = nextX
            lineHeight = max(lineHeight, item.sizeHint().height())

        return y + lineHeight - rect.y()


if __name__ == '__main__':

    import sys

    app = QtGui.QApplication(sys.argv)
    mainWin = Window()
    mainWin.show()
    sys.exit(app.exec_())

Yeah, I actually had found another one someone else had made. But in the actual layout (which I guess I didn’t mention), I also have all that in a vertical pane layout, and I couldn’t figure out how to parent an expanding Qt layout under a Maya Layout since the only way I know of to make an expanding Qt layout is to put it under a grid layout, which then in turn wouldn’t expand. Is there a way to attach just a regular Qt layout to the sides of any other layout kind of like in a Maya formLayout? Like I said, I’m not a Qt power-user.

is it possible to insert Qt Widgets into a Maya Layout and also possible to embed Maya Widgets into a Qt Gui.

this page is a great primer on using Qt in Maya

http://nathanhorne.com/?p=451