Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Qt Examples / Widgets / FlowLayout not working in MainWindow

Qt Examples / Widgets / FlowLayout not working in MainWindow

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 3 Posters 250 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    SGaist
    Lifetime Qt Champion
    wrote 23 days ago last edited by
    #4

    Oh sorry ! My bad ! I was too tired when I read the patch 😅

    Which version of Qt are you using ?
    What result are you getting with your changes ?

    Interested in AI ? www.idiap.ch
    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

    F 1 Reply Last reply 23 days ago
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote 23 days ago last edited by
      #5

      I tested:

      Window::Window()
      {
          QWidget *widget = new QWidget;
          FlowLayout *flowLayout = new FlowLayout(widget);
      
          flowLayout->addWidget(new QPushButton(tr("Short")));
          flowLayout->addWidget(new QPushButton(tr("Longer")));
          flowLayout->addWidget(new QPushButton(tr("Different text")));
          flowLayout->addWidget(new QPushButton(tr("More text")));
          flowLayout->addWidget(new QPushButton(tr("Even longer button text")));
      
          setCentralWidget(widget);
      
          setWindowTitle(tr("Flow Layout"));
      }
      

      Which is just a simpler variation on what you have and it's working correctly.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • F F32_
        25 days ago

        FlowLayout implements a layout that handles different window sizes. The widget placement changes depending on the width of the application window.

        alt text

        The code is here:

        https://code.qt.io/cgit/qt/qtbase.git/tree/examples/widgets/layouts/flowlayout?h=6.7

        In the example, the "Window" class is a QWidget, and it is shown with "window.show()".

        I just noticed that if I change the "Window" from QWidget to QMainWindow, the layout will stop working:

        diff --git a/window.h b/window.h
        index fd4bf40..2f5ef22 100644
        --- a/window.h
        +++ b/window.h
        @@ -4,13 +4,13 @@
         #ifndef WINDOW_H
         #define WINDOW_H
        
        -#include <QWidget>
        +#include <QMainWindow>
        
         QT_BEGIN_NAMESPACE
         class QLabel;
         QT_END_NAMESPACE
         //! [0]
        -class Window : public QWidget
        +class Window : public QMainWindow
         {
             Q_OBJECT
        diff --git a/window.cpp b/window.cpp
        index e3f0ceb..f5991ef 100644
        --- a/window.cpp
        +++ b/window.cpp
        @@ -8,6 +8,7 @@
         //! [1]
         Window::Window()
         {
        +    QWidget *centralWidget = new QWidget;
             FlowLayout *flowLayout = new FlowLayout;
        
             flowLayout->addWidget(new QPushButton(tr("Short")));
        @@ -15,7 +16,8 @@ Window::Window()
             flowLayout->addWidget(new QPushButton(tr("Different text")));
             flowLayout->addWidget(new QPushButton(tr("More text")));
             flowLayout->addWidget(new QPushButton(tr("Even longer button text")));
        -    setLayout(flowLayout);
        +    centralWidget->setLayout(flowLayout);
        +    setCentralWidget(centralWidget);
        
             setWindowTitle(tr("Flow Layout"));
         }
        

        What is the correct way to fix it?

        J Offline
        J Offline
        JonB
        wrote 23 days ago last edited by
        #6

        @F32_ said in Qt Examples / Widgets / FlowLayout not working in MainWindow:

        I just noticed that if I change the "Window" from QWidget to QMainWindow, the layout will stop working:

        Further to @SGaist, I tried exactly your own code. For me it worked fine, just like if you use QWidget rather than QMainWindow. Ubuntu 24.04, xcb, Qt 6.4.2.

        1 Reply Last reply
        0
        • S SGaist
          23 days ago

          Oh sorry ! My bad ! I was too tired when I read the patch 😅

          Which version of Qt are you using ?
          What result are you getting with your changes ?

          F Offline
          F Offline
          F32_
          wrote 23 days ago last edited by
          #7

          @SGaist @JonB
          Qt 6.7.3 under Windows 11.

          temp6.png

          FlowLayout can wrap buttons correctly, but the minimum height of the window is incorrect and some buttons may become invisible when resizing the window.

          J 2 Replies Last reply 23 days ago
          0
          • F F32_
            23 days ago

            @SGaist @JonB
            Qt 6.7.3 under Windows 11.

            temp6.png

            FlowLayout can wrap buttons correctly, but the minimum height of the window is incorrect and some buttons may become invisible when resizing the window.

            J Offline
            J Offline
            JonB
            wrote 23 days ago last edited by
            #8

            @F32_
            I don't understand why what you are showing is wrong in your screenshot? Looks fine to me. 3rd button is "long" and does not fit on first line, so wrapped to second line. Same for final button. Yes, if buttons do not all fit vertically they will go off the bottom of what is visible. What else do you expect? Do you expect it to resize the widget vertically to fit them all? I don't think it's intended to do that, just the wrapping. And I see exactly the same whether it's QMainWindow or QWidget. Show screenshots of both cases if you are claiming they differ.

            FWIW, I did use that flowlayout code a few years ago. And I did find a "bug" in it, and had to change the code to make it "right". I suspect I may have posted in this forum saying what was wrong and what I did, but I don't recall after all this time. I don't know whether what I changed would have any relationship to whatever your issue is. I will have a look around to see if I can find it, but unless I post here shortly assume I cannot locate it.

            F 1 Reply Last reply 23 days ago
            0
            • F F32_
              23 days ago

              @SGaist @JonB
              Qt 6.7.3 under Windows 11.

              temp6.png

              FlowLayout can wrap buttons correctly, but the minimum height of the window is incorrect and some buttons may become invisible when resizing the window.

              J Offline
              J Offline
              JonB
              wrote 23 days ago last edited by JonB
              #9

              @F32_
              OK, I have located my use of flowlayout in an old Python project I wrote, when I was using that for Qt initially. I paste it below.

              Note I wrote there

              # https://code.qt.io/cgit/qt/qtbase.git/tree/examples/widgets/layouts/flowlayout/flowlayout.cpp?h=5.13
              # Modified/adapted by jon, 10/07/2019, to translate into Python/PyQt
              

              I have a feeling the "adapted" indicates I made some change. I would guess inside def doLayout(). Most lines should be a direct translation of the C++ source to Python. See if you can spot some "difference" from the corresponding C++ in that function?

              #############################################################################
              #
              # This file taken from
              # https://code.qt.io/cgit/qt/qtbase.git/tree/examples/widgets/layouts/flowlayout/flowlayout.cpp?h=5.13
              # Modified/adapted by jon, 10/07/2019, to translate into Python/PyQt
              #
              # Copyright (C) 2016 The Qt Company Ltd.
              # Contact: https://www.qt.io/licensing/
              #
              # This file is part of the examples of the Qt Toolkit.
              #
              # $QT_BEGIN_LICENSE:BSD$
              # Commercial License Usage
              # Licensees holding valid commercial Qt licenses may use this file in
              # accordance with the commercial license agreement provided with the
              # Software or, alternatively, in accordance with the terms contained in
              # a written agreement between you and The Qt Company. For licensing terms
              # and conditions see https://www.qt.io/terms-conditions. For further
              # information use the contact form at https://www.qt.io/contact-us.
              #
              # BSD License Usage
              # Alternatively, you may use this file under the terms of the BSD license
              # as follows:
              #
              # "Redistribution and use in source and binary forms, with or without
              # modification, are permitted provided that the following conditions are
              # met:
              #   * Redistributions of source code must retain the above copyright
              #     notice, this list of conditions and the following disclaimer.
              #   * Redistributions in binary form must reproduce the above copyright
              #     notice, this list of conditions and the following disclaimer in
              #     the documentation and/or other materials provided with the
              #     distribution.
              #   * Neither the name of The Qt Company Ltd nor the names of its
              #     contributors may be used to endorse or promote products derived
              #     from this software without specific prior written permission.
              #
              #
              # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
              # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
              # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
              # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
              # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
              # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
              # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
              # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
              # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
              # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
              # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
              #
              # $QT_END_LICENSE$
              #
              #############################################################################
              
              
              import typing
              
              from PyQt5.QtCore import Qt, QPoint, QRect, QSize
              from PyQt5.QtWidgets import QWidget, QLayout, QLayoutItem, QStyle, QSizePolicy
              
              
              class FlowLayout(QLayout):
                  def __init__(self, parent: QWidget=None, margin: int=-1, hSpacing: int=-1, vSpacing: int=-1):
                      super().__init__(parent)
              
                      self.itemList = list()
                      self.m_hSpace = hSpacing
                      self.m_vSpace = vSpacing
              
                      self.setContentsMargins(margin, margin, margin, margin)
              
                  def __del__(self):
                      # copied for consistency, not sure this is needed or ever called
                      item = self.takeAt(0)
                      while item:
                          item = self.takeAt(0)
              
                  def addItem(self, item: QLayoutItem):
                      self.itemList.append(item)
              
                  def horizontalSpacing(self) -> int:
                      if self.m_hSpace >= 0:
                          return self.m_hSpace
                      else:
                          return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing)
              
                  def verticalSpacing(self) -> int:
                      if self.m_vSpace >= 0:
                          return self.m_vSpace
                      else:
                          return self.smartSpacing(QStyle.PM_LayoutVerticalSpacing)
              
                  def count(self) -> int:
                      return len(self.itemList)
              
                  def itemAt(self, index: int) -> typing.Union[QLayoutItem, None]:
                      if 0 <= index < len(self.itemList):
                          return self.itemList[index]
                      else:
                          return None
              
                  def takeAt(self, index: int) -> typing.Union[QLayoutItem, None]:
                      if 0 <= index < len(self.itemList):
                          return self.itemList.pop(index)
                      else:
                          return None
              
                  def expandingDirections(self) -> Qt.Orientations:
                      return Qt.Orientations(Qt.Orientation(0))
              
                  def hasHeightForWidth(self) -> bool:
                      return True
              
                  def heightForWidth(self, width: int) -> int:
                      height = self.doLayout(QRect(0, 0, width, 0), True)
                      return height
              
                  def setGeometry(self, rect: QRect) -> None:
                      super().setGeometry(rect)
                      self.doLayout(rect, False)
              
                  def sizeHint(self) -> QSize:
                      return self.minimumSize()
              
                  def minimumSize(self) -> QSize:
                      size = QSize()
                      for item in self.itemList:
                          size = size.expandedTo(item.minimumSize())
              
                      margins = self.contentsMargins()
                      size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom())
                      return size
              
                  def smartSpacing(self, pm: QStyle.PixelMetric) -> int:
                      parent = self.parent()
                      if not parent:
                          return -1
                      elif parent.isWidgetType():
                          return parent.style().pixelMetric(pm, None, parent)
                      else:
                          return parent.spacing()
              
                  def doLayout(self, rect: QRect, testOnly: bool) -> int:
                      left, top, right, bottom = self.getContentsMargins()
                      effectiveRect = rect.adjusted(+left, +top, -right, -bottom)
                      x = effectiveRect.x()
                      y = effectiveRect.y()
                      lineHeight = 0
              
                      for item in self.itemList:
                          wid = item.widget()
                          spaceX = self.horizontalSpacing()
                          if spaceX == -1:
                              spaceX = wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
                          spaceY = self.verticalSpacing()
                          if spaceY == -1:
                              spaceY = wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)
              
                          nextX = x + item.sizeHint().width() + spaceX
                          if nextX - spaceX > effectiveRect.right() and lineHeight > 0:
                              x = effectiveRect.x()
                              y = y + lineHeight + spaceY
                              nextX = x + item.sizeHint().width() + spaceX
                              lineHeight = 0
              
                          if not testOnly:
                              item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
                  
                          x = nextX
                          lineHeight = max(lineHeight, item.sizeHint().height())
              
                      return y + lineHeight - rect.y() + bottom
              
              1 Reply Last reply
              0
              • J JonB
                23 days ago

                @F32_
                I don't understand why what you are showing is wrong in your screenshot? Looks fine to me. 3rd button is "long" and does not fit on first line, so wrapped to second line. Same for final button. Yes, if buttons do not all fit vertically they will go off the bottom of what is visible. What else do you expect? Do you expect it to resize the widget vertically to fit them all? I don't think it's intended to do that, just the wrapping. And I see exactly the same whether it's QMainWindow or QWidget. Show screenshots of both cases if you are claiming they differ.

                FWIW, I did use that flowlayout code a few years ago. And I did find a "bug" in it, and had to change the code to make it "right". I suspect I may have posted in this forum saying what was wrong and what I did, but I don't recall after all this time. I don't know whether what I changed would have any relationship to whatever your issue is. I will have a look around to see if I can find it, but unless I post here shortly assume I cannot locate it.

                F Offline
                F Offline
                F32_
                wrote 23 days ago last edited by
                #10

                @JonB In the original example, FlowLayout is in "Window" and "Window" is a QWidget.

                Under Windows 11 and Qt 6.7.3, if the user attempts to resize the window and make it shorter, the action will be blocked by the value of minimumSize(), and the user will find that the window has a minimum height.

                In the screenshot pasted in #7, the user will find that the minimum height is 3 rows. This feature is provided by:

                //! [7]
                bool FlowLayout::hasHeightForWidth() const
                {
                    return true;
                }
                
                int FlowLayout::heightForWidth(int width) const
                {
                    int height = doLayout(QRect(0, 0, width, 0), true);
                    return height;
                }
                //! [7]
                

                If the user changes "Window" from QWidget to QMainWindow, this feature disappears, and the window's minimum height is always one row. The extra buttons overflow.

                J 1 Reply Last reply 23 days ago
                0
                • F F32_
                  23 days ago

                  @JonB In the original example, FlowLayout is in "Window" and "Window" is a QWidget.

                  Under Windows 11 and Qt 6.7.3, if the user attempts to resize the window and make it shorter, the action will be blocked by the value of minimumSize(), and the user will find that the window has a minimum height.

                  In the screenshot pasted in #7, the user will find that the minimum height is 3 rows. This feature is provided by:

                  //! [7]
                  bool FlowLayout::hasHeightForWidth() const
                  {
                      return true;
                  }
                  
                  int FlowLayout::heightForWidth(int width) const
                  {
                      int height = doLayout(QRect(0, 0, width, 0), true);
                      return height;
                  }
                  //! [7]
                  

                  If the user changes "Window" from QWidget to QMainWindow, this feature disappears, and the window's minimum height is always one row. The extra buttons overflow.

                  J Offline
                  J Offline
                  JonB
                  wrote 23 days ago last edited by JonB
                  #11

                  @F32_ said in Qt Examples / Widgets / FlowLayout not working in MainWindow:

                  @JonB In the original example, FlowLayout is in "Window" and "Window" is a QWidget.

                  I know this. I do not understand what/why you are trying to say here.

                  If the user changes "Window" from QWidget to QMainWindow, this feature disappears, and the window's minimum height is always one row. The extra buttons overflow.

                  As I wrote, I have run your code where Window is either a plain QWidget or a QMainWindow. And I cannot see any difference in behaviour between the two. In both cases I can shrink the "window" vertically to minimum height, and that allows for the first line of pushbutton(s) plus I can just see the top line of the second row. I do not see either giving any minimum height of "3 rows", they both reduce to one row plus a tiny bit, as I wrote. If you see otherwise I suggested you show two screenshots, one with QMainWindow and the other with QWidget, so that we can see what you are seeing. I repeat again: if your first screenshot shows a minimum height where it is a QWidget and you cannot reduce its height any further then I do not see that. Bear in mind my platform and Qt version. I cannot say any more than that.

                  I don't know whether you can reproduce whatever your issue is without involving the flow layout at all? Maybe you are seeing some difference for minimal height between a QWidget vs a QMainWindow regardless, and it's some issue about that?

                  F 1 Reply Last reply 23 days ago
                  0
                  • J JonB
                    23 days ago

                    @F32_ said in Qt Examples / Widgets / FlowLayout not working in MainWindow:

                    @JonB In the original example, FlowLayout is in "Window" and "Window" is a QWidget.

                    I know this. I do not understand what/why you are trying to say here.

                    If the user changes "Window" from QWidget to QMainWindow, this feature disappears, and the window's minimum height is always one row. The extra buttons overflow.

                    As I wrote, I have run your code where Window is either a plain QWidget or a QMainWindow. And I cannot see any difference in behaviour between the two. In both cases I can shrink the "window" vertically to minimum height, and that allows for the first line of pushbutton(s) plus I can just see the top line of the second row. I do not see either giving any minimum height of "3 rows", they both reduce to one row plus a tiny bit, as I wrote. If you see otherwise I suggested you show two screenshots, one with QMainWindow and the other with QWidget, so that we can see what you are seeing. I repeat again: if your first screenshot shows a minimum height where it is a QWidget and you cannot reduce its height any further then I do not see that. Bear in mind my platform and Qt version. I cannot say any more than that.

                    I don't know whether you can reproduce whatever your issue is without involving the flow layout at all? Maybe you are seeing some difference for minimal height between a QWidget vs a QMainWindow regardless, and it's some issue about that?

                    F Offline
                    F Offline
                    F32_
                    wrote 23 days ago last edited by
                    #12

                    @JonB I managed to create two gif files, which should be helpful to the community.

                    The original version (Qt 6.7.3, C++, Windows 11):

                    flowlayout-widget.gif

                    I believe this is the original design because every layout should be able to claim a minimal size.

                    The patched version (Qt 6.7.3, C++, Windows 11, with QMainWindow):

                    flowlayout-mainwindow.gif

                    J 1 Reply Last reply 23 days ago
                    1
                    • F Offline
                      F Offline
                      F32_
                      wrote 23 days ago last edited by
                      #13

                      Then I tested QVBoxLayout. With both QWidget and QMainWindow, the minimum height is consistent.

                      1 Reply Last reply
                      0
                      • F F32_
                        23 days ago

                        @JonB I managed to create two gif files, which should be helpful to the community.

                        The original version (Qt 6.7.3, C++, Windows 11):

                        flowlayout-widget.gif

                        I believe this is the original design because every layout should be able to claim a minimal size.

                        The patched version (Qt 6.7.3, C++, Windows 11, with QMainWindow):

                        flowlayout-mainwindow.gif

                        J Offline
                        J Offline
                        JonB
                        wrote 23 days ago last edited by
                        #14

                        @F32_
                        To be clear for others: with Qt 6.4.2 under Ubuntu/GNOME/xcb, I am claiming both QWidget & QMainWindow cases are as per the second screenshot above. I never see a minimum height of 3 lines. Which of the two is the "correct" behaviour in the OP's case I do not claim to know :)

                        1 Reply Last reply
                        0

                        13/14

                        23 Apr 2025, 13:31

                        • Login

                        • Login or register to search.
                        13 out of 14
                        • First post
                          13/14
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved