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. How can I know when a widget and layout has their final geometries?
Forum Updated to NodeBB v4.3 + New Features

How can I know when a widget and layout has their final geometries?

Scheduled Pinned Locked Moved Unsolved General and Desktop
12 Posts 4 Posters 2.4k Views 2 Watching
  • 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.
  • l3u_L Offline
    l3u_L Offline
    l3u_
    wrote on last edited by
    #1

    Hi all!

    I'm working on a program using quite complex layouts. What I want to do now is to automatically tweak the sizes of a QSplitter with two widgets, so that the widget on top (which itself has a quite complex layout) is fully shown if possible (sometimes, it's too big. Thus, it contains a QScrollArea, just like the bottom widget. But I want to avoid scroll bars in the top one if possible).

    This should happen both when the top widget is set up (it can be changed during runtime, so that widgets are deleted and re-added with different sizes) and when the window is resized.

    For resizing, it's quite simple: I only have to override the resizeEvent and call my size-setting function after passing the event to the base class.

    But all in all, this is a more general question. How can I know when some widget and
    layout actually does have it's final geoemetry?

    I played around with QApplication::processEvents() and put my stuff into a QTimer::singleShot(0, [this] { … }) lambda. This helps, but I don't always get the real final geometry, depending on if e.g. a database is loaded on startup (which causes the top widget to be set up immediately at startup), or one is created when the program already runs (in this case, the top widget is in an immediate state, some child widgets are already setup, others are added depending on user settings). Even, having the exact same situation, the reported sizes differ sometimes between two program starts.

    What always worked is to not use a 0 ms single shot, but e.g. a 100 ms one. But this can't be the right way, some older system might take slightly longer to render all the stuff.

    So … what's a best practise approach to do this?

    Thanks for all help!

    JoeCFDJ JonBJ 2 Replies Last reply
    0
    • l3u_L l3u_

      Hi all!

      I'm working on a program using quite complex layouts. What I want to do now is to automatically tweak the sizes of a QSplitter with two widgets, so that the widget on top (which itself has a quite complex layout) is fully shown if possible (sometimes, it's too big. Thus, it contains a QScrollArea, just like the bottom widget. But I want to avoid scroll bars in the top one if possible).

      This should happen both when the top widget is set up (it can be changed during runtime, so that widgets are deleted and re-added with different sizes) and when the window is resized.

      For resizing, it's quite simple: I only have to override the resizeEvent and call my size-setting function after passing the event to the base class.

      But all in all, this is a more general question. How can I know when some widget and
      layout actually does have it's final geoemetry?

      I played around with QApplication::processEvents() and put my stuff into a QTimer::singleShot(0, [this] { … }) lambda. This helps, but I don't always get the real final geometry, depending on if e.g. a database is loaded on startup (which causes the top widget to be set up immediately at startup), or one is created when the program already runs (in this case, the top widget is in an immediate state, some child widgets are already setup, others are added depending on user settings). Even, having the exact same situation, the reported sizes differ sometimes between two program starts.

      What always worked is to not use a 0 ms single shot, but e.g. a 100 ms one. But this can't be the right way, some older system might take slightly longer to render all the stuff.

      So … what's a best practise approach to do this?

      Thanks for all help!

      JoeCFDJ Offline
      JoeCFDJ Offline
      JoeCFD
      wrote on last edited by
      #2

      @l3u_ override showEvent( QShowEvent * show_event ) of your widget?
      https://doc.qt.io/qt-5/qwidget.html#showEvent

      l3u_L 1 Reply Last reply
      1
      • l3u_L l3u_

        Hi all!

        I'm working on a program using quite complex layouts. What I want to do now is to automatically tweak the sizes of a QSplitter with two widgets, so that the widget on top (which itself has a quite complex layout) is fully shown if possible (sometimes, it's too big. Thus, it contains a QScrollArea, just like the bottom widget. But I want to avoid scroll bars in the top one if possible).

        This should happen both when the top widget is set up (it can be changed during runtime, so that widgets are deleted and re-added with different sizes) and when the window is resized.

        For resizing, it's quite simple: I only have to override the resizeEvent and call my size-setting function after passing the event to the base class.

        But all in all, this is a more general question. How can I know when some widget and
        layout actually does have it's final geoemetry?

        I played around with QApplication::processEvents() and put my stuff into a QTimer::singleShot(0, [this] { … }) lambda. This helps, but I don't always get the real final geometry, depending on if e.g. a database is loaded on startup (which causes the top widget to be set up immediately at startup), or one is created when the program already runs (in this case, the top widget is in an immediate state, some child widgets are already setup, others are added depending on user settings). Even, having the exact same situation, the reported sizes differ sometimes between two program starts.

        What always worked is to not use a 0 ms single shot, but e.g. a 100 ms one. But this can't be the right way, some older system might take slightly longer to render all the stuff.

        So … what's a best practise approach to do this?

        Thanks for all help!

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #3

        @l3u_
        @JoeCFD recommends showEvent(). That would be best if it solves your "timing" situation, but I'm not sure it will.

        singleShot(0) would be next choice. But, as you say, I have found occasions where I have to specify some non-0 delay, like 100ms, to allow the UI to fully "settle down". And 100ms is indeed a "guess". You could emit your own signals after e.g. a long database operation, but it's a lot of work and won't cover every case. See if anyone says otherwise, but I think these edge cases are a bit of a "black art" in Qt, you pays your money and you takes your chances....

        1 Reply Last reply
        0
        • JoeCFDJ JoeCFD

          @l3u_ override showEvent( QShowEvent * show_event ) of your widget?
          https://doc.qt.io/qt-5/qwidget.html#showEvent

          l3u_L Offline
          l3u_L Offline
          l3u_
          wrote on last edited by
          #4

          @JoeCFD I just tried this. But overriding the showEvent is quite the same as using QTimer single shots. Sometimes, the geometry is correct, and sometimes, it's not. Also, it seems like QApplication::processEvents() helps a bit, but also not for each case …

          1 Reply Last reply
          0
          • KH-219DesignK Offline
            KH-219DesignK Offline
            KH-219Design
            wrote on last edited by
            #5

            I agree with @JonB that this is a "black art." (I came here to essentially express that very sentiment, although I didn't have as catchy of a phrase to describe it as "black art." That captures it well.)

            I work almost entirely in QML, so my widgets knowledge it not fluent, but a general concept/idea that also might apply here could be:

            watch for every QResizeEvent and/or QPaintEvent, and at those points keep track of how long the size has remained stable (either in wall clock time or in number-or-events quantity). After the "right amount" of time in a stable size, take whatever action you wanted take at the point of "final geometry reached".

            www.219design.com
            Software | Electrical | Mechanical | Product Design

            l3u_L 1 Reply Last reply
            1
            • KH-219DesignK KH-219Design

              I agree with @JonB that this is a "black art." (I came here to essentially express that very sentiment, although I didn't have as catchy of a phrase to describe it as "black art." That captures it well.)

              I work almost entirely in QML, so my widgets knowledge it not fluent, but a general concept/idea that also might apply here could be:

              watch for every QResizeEvent and/or QPaintEvent, and at those points keep track of how long the size has remained stable (either in wall clock time or in number-or-events quantity). After the "right amount" of time in a stable size, take whatever action you wanted take at the point of "final geometry reached".

              l3u_L Offline
              l3u_L Offline
              l3u_
              wrote on last edited by
              #6

              @KH-219Design In other words: The answer to the title is "you can't" ;-)

              JoeCFDJ 1 Reply Last reply
              0
              • l3u_L l3u_

                @KH-219Design In other words: The answer to the title is "you can't" ;-)

                JoeCFDJ Offline
                JoeCFDJ Offline
                JoeCFD
                wrote on last edited by
                #7

                @l3u_ Is this issue related to touch screen?

                l3u_L 1 Reply Last reply
                0
                • JoeCFDJ JoeCFD

                  @l3u_ Is this issue related to touch screen?

                  l3u_L Offline
                  l3u_L Offline
                  l3u_
                  wrote on last edited by
                  #8

                  @JoeCFD No. In this case, it's a normal classical QWidget based desktop application without any touch screen involved.

                  But as said: This was a more general question, I hit this problem several times in the past. Only that most of the time, I could work around it simply using QTimer::singleShot(0, lambda calls.

                  JonBJ 1 Reply Last reply
                  0
                  • l3u_L l3u_

                    @JoeCFD No. In this case, it's a normal classical QWidget based desktop application without any touch screen involved.

                    But as said: This was a more general question, I hit this problem several times in the past. Only that most of the time, I could work around it simply using QTimer::singleShot(0, lambda calls.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by
                    #9

                    @l3u_
                    Let's think about this :)

                    From what you describe something/whatever is going on over time which adds or changes things causing the UI layout to change. You have said that even with a 100ms delay it (mostly?) seems to work for you, but you are worried that it might take longer.

                    Let's say there were some signal for "widget and layout has their final geometries" (whatever that might mean). You would not know how long to wait for this, would you? So (presumably) you would write code to act on either that signal or some timeout eventually expiring with nothing more happening.

                    So it still comes down to timing. Hence whether there is a signal or not you probably want to:

                    • Set off a single shot. Suggest your 100ms since you say that covers most/many cases. You could also afford to make it a bit longer, do you really think the user notices if there is somewhat more than a 10th of a second delay on whatever you want to do? Or, if you want, you could make it 0/small and then follow the next point.
                    • Whatever it is you claim in your situation the geometries might change later still. So you ought cater for that. Which presumably means your code allows for the layout changing and you can redo/correct whatever you did when you thought the geometries were "final". Likely you already have to allow for resizing. So either/both of a further timer which looks at whether geometry has changed or resizeEvent can adjust for further change.
                    l3u_L 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @l3u_
                      Let's think about this :)

                      From what you describe something/whatever is going on over time which adds or changes things causing the UI layout to change. You have said that even with a 100ms delay it (mostly?) seems to work for you, but you are worried that it might take longer.

                      Let's say there were some signal for "widget and layout has their final geometries" (whatever that might mean). You would not know how long to wait for this, would you? So (presumably) you would write code to act on either that signal or some timeout eventually expiring with nothing more happening.

                      So it still comes down to timing. Hence whether there is a signal or not you probably want to:

                      • Set off a single shot. Suggest your 100ms since you say that covers most/many cases. You could also afford to make it a bit longer, do you really think the user notices if there is somewhat more than a 10th of a second delay on whatever you want to do? Or, if you want, you could make it 0/small and then follow the next point.
                      • Whatever it is you claim in your situation the geometries might change later still. So you ought cater for that. Which presumably means your code allows for the layout changing and you can redo/correct whatever you did when you thought the geometries were "final". Likely you already have to allow for resizing. So either/both of a further timer which looks at whether geometry has changed or resizeEvent can adjust for further change.
                      l3u_L Offline
                      l3u_L Offline
                      l3u_
                      wrote on last edited by l3u_
                      #10

                      @JonB For this special case, I solved it with two approaches.

                      1. The QSplitter's handle now can't be positioned too low, because I set appropriate size policies and constraints: A setSizeConstraint(QLayout::SetMaximumSize) for the layout of said "top" widget along with a setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum) for the scroll area. Using this, the handle won't travel lower as it has to to show the whole top widget when resizing the window and also can't be placed there manually. Resizing problem solved.

                      2. The widget inside the scroll area is only changed (deleted and set up again) on user interaction or when starting up the problem. So I (pragmatically) decided to fire up a 100 ms single shot lambda to adjust the splitter's sizes so that the full top widget is shown (if possible).

                      There's no noticable delay in the adjustment, and everything looks good – both when starting up, and when changing the widget.

                      I would say this is a passable solution. Worst what could happen is that the window and all the widgets won't have their final geometry within those 100 ms. In this case, the splitter handle could be positioned at a "wrong" position and the user would have to drag it where appropriate. I think one can live with this.

                      JonBJ 1 Reply Last reply
                      0
                      • l3u_L l3u_

                        @JonB For this special case, I solved it with two approaches.

                        1. The QSplitter's handle now can't be positioned too low, because I set appropriate size policies and constraints: A setSizeConstraint(QLayout::SetMaximumSize) for the layout of said "top" widget along with a setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum) for the scroll area. Using this, the handle won't travel lower as it has to to show the whole top widget when resizing the window and also can't be placed there manually. Resizing problem solved.

                        2. The widget inside the scroll area is only changed (deleted and set up again) on user interaction or when starting up the problem. So I (pragmatically) decided to fire up a 100 ms single shot lambda to adjust the splitter's sizes so that the full top widget is shown (if possible).

                        There's no noticable delay in the adjustment, and everything looks good – both when starting up, and when changing the widget.

                        I would say this is a passable solution. Worst what could happen is that the window and all the widgets won't have their final geometry within those 100 ms. In this case, the splitter handle could be positioned at a "wrong" position and the user would have to drag it where appropriate. I think one can live with this.

                        JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on last edited by
                        #11

                        @l3u_
                        OK, this is for two specific cases of your own. I thought you were looking for a general solution, allowing for anything going on in your widgets/layouts, even perhaps with third-party libraries/other code. Yours may well be fine for your case, just don't change/add any widgets/layouts ;-)

                        l3u_L 1 Reply Last reply
                        0
                        • JonBJ JonB

                          @l3u_
                          OK, this is for two specific cases of your own. I thought you were looking for a general solution, allowing for anything going on in your widgets/layouts, even perhaps with third-party libraries/other code. Yours may well be fine for your case, just don't change/add any widgets/layouts ;-)

                          l3u_L Offline
                          l3u_L Offline
                          l3u_
                          wrote on last edited by
                          #12

                          @JonB Yeah, a gerneral solution for such problems would be fine … bit it looks like it's not trivial …

                          1 Reply Last reply
                          0

                          • Login

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