【问题标题】:Qt Window incorrect size until user eventQt 窗口大小不正确,直到用户事件
【发布时间】:2018-02-16 17:21:41
【问题描述】:

我正在创建一个屏幕,用户可以在其中添加某些图块以在编辑器中使用,但添加图块时,窗口无法正确调整大小以适应内容。除了当我拖动窗口或稍微调整它的大小时,它会立即捕捉到正确的大小。


当只是拖动窗口时,它会捕捉到正确的大小。

我尝试使用 resize(sizeHint());这给了我一个不正确的大小和以下错误,但是在调整大小/拖动时仍然会发生捕捉到正确大小的情况。

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).

我也尝试过使用 updateGeometry() 和 update(),但它似乎并没有起到什么作用。

当将窗口设置为 fixedSize 时,它​​会立即调整大小,但随后用户无法再调整窗口大小。我在这里做错了什么,我从哪里开始解决它?

编辑 Minimal verifiable example.ui file。 selected_layout 的类型为Flowlayout flowlayout_placeholder_1 之所以存在,是因为我无法将 flowlayout 直接放置到设计器中。

编辑2 这是minimal Visual Studio example。我使用 Visual Studio 进行 Qt 开发。我尝试在 Qt Creator 中创建一个项目,但没有成功。

编辑3 添加了little video (80 KB)。

编辑4 这是updated Visual Studio example。它有 jpo38 提出的新变化。它解决了错误调整大小的问题。虽然现在试图缩小窗户会导致问题。如果您尝试减少水平空间,即使有更多行的空间,它们也不会正确填充垂直空间。

【问题讨论】:

  • 分享.ui文件,不分享.ui生成的.h文件,方便管理。
  • 您是否尝试使用adjustSize()
  • @Evgeny 我做了,我得到“QWindowsWindow::setGeometry: Unable to set geometry 299x329+671+417 on QWidgetWindow/'TileSetterWindow'. 生成的几何:299x399+671+417(帧:8, 31、8、8,自定义边距:0、0、0、0,最小尺寸:259x329,最大尺寸:16777215x16777215)。除了使初始窗口大小小于设计器中设置的宽度之外,它似乎并没有多大作用。
  • 请同时提供 .pro 文件,这样示例就完成了。

标签: c++ qt qt-designer


【解决方案1】:

出色的 MCVE,正是轻松调查问题所需要的。

看起来这个FlowLayout 类的设计不是为了让用户操作的最小尺寸变化。当窗口移动时,布局会被 QWidget 内核“偶然”更新。

我可以通过修改 FlowLayout::minimumSize() 的行为使其巧妙地工作,以下是我所做的更改:

  • QSize minSize; 属性添加到FlowLayout
  • 修改 FlowLayout::minimumSize() 以简单地返回此属性
  • doLayout 函数添加了第三个参数QSize* pMinSize。这将用于更新此 minSize 属性
  • 修改 doLayout 以将计算的大小保存到 pMinSize 参数(如果指定)
  • FlowLayout::setGeometryminSize 属性传递给doLayout 并在最小尺寸更改时使布局无效

然后布局按预期运行。

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;
}

【讨论】:

  • 嘿 jpo38,干得好。它现在会自动增加所需的大小,这很棒。虽然现在试图缩小窗户会导致问题。如果您尝试减少水平空间,它们将不再正确填充垂直空间。我已经用更新后的解决方案的新链接更新了主帖子。
  • @Eejin:现在您看到问题来自minimumSize,您可能必须对其进行处理才能使其行为完全符合预期,包括缩小规模的情况(因为 minimumSize 肯定会阻止widegt从被缩小)。
猜你喜欢
  • 2012-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-06
  • 1970-01-01
相关资源
最近更新 更多