Qt Window incorrect size until user event

I'm creating a screen where users can add certain tiles to use in an editor, but when adding a tile the window does not correctly resize to fit the content. Except that when I drag the window or resize it even just a little then it snaps to the correct size immediately.

在这里输入图像描述
And when just dragging the window it snaps to the correct size.

在这里输入图像描述

I tried using resize(sizeHint()); which gave me an incorrect size and the following error, but the snapping to correct size still happens when resizing/dragging.

QWindowsWindow::setGeometry: Unable to set geometry 299x329+991+536 on QWidgetWindow/'TileSetterWindow'. Resulting geometry:  299x399+991+536 (frame: 8, 31, 8, 8, custom margin: 0, 0, 0, 0, minimum size: 259x329, maximum size: 16777215x16777215).

I also tried using updateGeometry() and update(), but it didn't seem to do much if anything.

When setting the window to fixedSize it will immediately resize, but then the user cannot resize the window anymore. What am I doing wrong here and where do I start to solve it?

Edit Minimal verifiable example and the .ui file. selected_layout is of type Flowlayout The flowlayout_placeholder_1 is only there because I can't place a flowlayout directly into the designer.

Edit2 Here is a minimal Visual Studio example. I use Visual Studio for Qt development. I tried creating a project in Qt Creator, but I didn't get that to work.

Edit3 Added a little video (80 KB).

Edit4 Here is the updated Visual Studio example. It has the new changes proposed by jpo38. It fixes the issue of the bad resizing. Though now trying to downsize the windows causes issues. They don't correctly fill up vertical space anymore if you try to reduce the horizontal space even though there is room for more rows.


Great MCVE, exactly what's needed to easily investigate the issue.

Looks like this FlowLayout class was not designed to have it's minimum size change on user action. Layout gets updated 'by chance' by QWidget kernel when the window is moved.

I could make it work smartly by modifying FlowLayout::minimumSize() behaviour, here are the changes I did:

  • Added QSize minSize; attribute to FlowLayout class
  • Modifed FlowLayout::minimumSize() to simply return this attribute
  • Added a third parameter QSize* pMinSize to doLayout function. This will be used to update this minSize attribute
  • Modified doLayout to save computed size to pMinSize parameter if specified
  • Had FlowLayout::setGeometry pass minSize attribute to doLayout and invalidate the layout if min size changed
  • The layout then behaves as expected.

    int FlowLayout::heightForWidth(int width) const {
        const int height = doLayout(QRect(0, 0, width, 0), true,NULL); // jpo38: set added parameter to NULL here
        return height;
    }
    
    void FlowLayout::setGeometry(const QRect &rect) {
        QLayout::setGeometry(rect);
    
        // jpo38: update minSize from here, force layout to consider it if it changed
        QSize oldSize = minSize;
        doLayout(rect, false,&minSize);
        if ( oldSize != minSize )
        {
            // force layout to consider new minimum size!
            invalidate();
        }
    }
    
    QSize FlowLayout::minimumSize() const {
        // jpo38: Simply return computed min size
        return minSize;
    }
    
    int FlowLayout::doLayout(const QRect &rect, bool testOnly,QSize* pMinSize) const {
        int left, top, right, bottom;
        getContentsMargins(&left, &top, &right, &bottom);
        QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
        int x = effectiveRect.x();
        int y = effectiveRect.y();
        int lineHeight = 0;
    
        // jpo38: store max X
        int maxX = 0;
    
        for (auto&& item : itemList) {
            QWidget *wid = item->widget();
            int spaceX = horizontalSpacing();
            if (spaceX == -1)
                spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
            int spaceY = verticalSpacing();
            if (spaceY == -1)
                spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
            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()));
    
            // jpo38: update max X based on current position
            maxX = qMax( maxX, x + item->sizeHint().width() - rect.x() + left );
    
            x = nextX;
            lineHeight = qMax(lineHeight, item->sizeHint().height());
        }
    
        // jpo38: save height/width as max height/xidth in pMinSize is specified
        int height = y + lineHeight - rect.y() + bottom;
        if ( pMinSize )
        {
            pMinSize->setHeight( height );
            pMinSize->setWidth( maxX );
        }
        return height;
    }
    
    链接地址: http://www.djcxy.com/p/41374.html

    上一篇: 在结构初始化中保持正确性

    下一篇: 直到用户事件,Qt窗口大小不正确