Guillermo Ares
Guillermo Ares

Reputation: 197

QScrollArea won't acknowledge set widget's size

I'm trying to implement a pinterest-like UI and I've been experimenting with the FlowLayout example for PySide.

The problem is that I'm trying to use a QScrollArea and it won't let me scroll down enough. In other words, I can't get to the bottom of the widget I'm trying to scroll.

You can get the hole file here. If you download it and run it, the problem will become pretty obvious.

My code was taken from here, with these modifications:

Added this class: (it just let's me generate colored and numerated rectangles)

class ColoredRectangle(QLabel):
count = 0

def __init__(self, height, color):
    super(ColoredRectangle, self).__init__()

    palette = QPalette()
    palette.setColor(QPalette.Background, color)

    self.setAutoFillBackground(True)
    self.setPalette(palette)

    self.setFixedSize(200, height)
    self.setText(str(ColoredRectangle.count))
    ColoredRectangle.count += 1

Now I'm adding rectangles instead of buttons...

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

    flowLayout = FlowLayout()
    flowLayout.addWidget(ColoredRectangle(450, Qt.white))
    flowLayout.addWidget(ColoredRectangle(200, Qt.green))self.setLayout(flowLayout)

    self.setLayout(flowLayout)

    self.setWindowTitle("Flow Layout")

Changed the doLayout method like this:

def doLayout(self, rect):

    if not any(self.itemList):
        return

    firstItem = self.itemList[0]

    x = rect.x()
    y = rect.y()

    wid = firstItem.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)

    itemWidth = firstItem.sizeHint().width()

    # calculate column count

    columnCount = (rect.width() + spaceX) / (itemWidth + spaceX)
    availablePositions = [None] * columnCount

    for i in range(columnCount):
        availablePositions[i] = QPoint(x + i * (itemWidth + spaceX), y)

    for item in self.itemList:

        currentPosition = availablePositions[0]
        currentPositionColumn = 0

        positionColumn = 0
        for position in availablePositions:
            if min(currentPosition.y(), position.y()) != currentPosition.y():
                currentPositionColumn = positionColumn
                currentPosition = position

            positionColumn += 1

        # update available position in column
        itemSize = item.sizeHint()
        availablePositions[currentPositionColumn] = QPoint(currentPosition.x(),
                                                           currentPosition.y() + itemSize.height() + spaceY)

        # place item
        item.setGeometry(QtCore.QRect(currentPosition, itemSize))

And finally, I added the QScrollArea:

if __name__ == '__main__':
import sys

app = QtGui.QApplication(sys.argv)
mainWin = Window()
scrollArea = QScrollArea()
scrollArea.setWidgetResizable(True)
scrollArea.setWidget(mainWin)
scrollArea.show()
sys.exit(app.exec_())

Thanks in advance!

Upvotes: 1

Views: 105

Answers (1)

Guillermo Ares
Guillermo Ares

Reputation: 197

Well, found the answer on my own...

Apparently the layout has to define the method heightForWidth, which, as far as I understand, returns the height of the layout which results after a width resize. So... I had to store the new height at the end of doLayout so I'm able to return it when asked for.

This is what I did after doLayout:

self.heightForWidthValue = max(map(lambda position : position.y(), availablePositions))

Also, I implemented these functions in FlowLayout:

def hasHeightForWidth(self):
    return True

def heightForWidth(self, width):
    return self.heightForWidthValue

And set 0 as the default value (initialized in FlowLayout->__init__) for heightForWidthValue.

Now it works like a charm :)

Here's the proper code, if anyone is interested.

Upvotes: 1

Related Questions