Results 1 to 19 of 19

Thread: QMdiArea behaviour different between Qt4 and Qt5

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    121
    Thanks
    9
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default QMdiArea behaviour different between Qt4 and Qt5

    Continuing to port my Qt application from Qt4 to Qt5, I have encountered a difference in the way a QMdiArea widget is handled.
    The .ui file that is created interactively in Qt Creator includes a QStackedWidget, one member of which is a QWidget in which I have placed a QMdiArea (mdiArea) and a QTextBrowser (box_outputLog). These two windows are sized such that box_outputLog has a constant size, while the rest of the available space is occupied by mdiArea. To achieve this, each has Horizontal Policy and Vertical Policy set to Expanding, while the vertical sizes are as follows:
    mdiArea: MinimumSize Vertical = 500, MaximumSize Vertical = 16777215
    box_outputLog: MinimumSize Vertical = 200, MaximumSize Vertical = 200
    In other words the QTextBrowser window is always 200 high, and the rest of the available space is used by the QMdiArea window.

    mdiArea is populated programmatically with 20 QwtPlot objects, like this:

    Qt Code:
    1. mdiArea->addSubWindow(pGraph[i]);
    To copy to clipboard, switch view to plain text mode 

    then the area is tiled:

    Qt Code:
    1. mdiArea->tileSubWindows();
    To copy to clipboard, switch view to plain text mode 

    giving 4 rows of 5 plots. In the Qt4 version, since the plots do not all fit in the available space, a scrolling slider is displayed. (box_outputLog also gets a slider when the text sent to it exceeds the space.) This all works fine with Qt4, but in the Qt5 version the 20 plots are not constrained to the allocated space, instead they extend off the screen. There is no scrolling slider, so the last row cannot be seen, and there is no box_outputLog window.
    Screenshots of the two cases are attached.

    I wonder if somebody can tell me what I need to do to make the Qt5 version behave like the Qt4 program.

    Thanks
    Gib
    Attached Images Attached Images

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    From your description, it sounds like you have not put a layout on this widget and the attempt to position your sub-widgets manually is the problem. The MDI area is basically expanding to cover the entire QWidget, but the bottom part is being hidden by the text widget.

    Add a vertical layout (QVBoxLayout) to the QWidget, then add your MDI window to the layout as the first widget and the text widget as the second one. Set the maximumHeight property of the text widget to limit its vertical expansion.

    Also note that the default scrollbar policy for QMdiArea is "Qt::ScrollBarAlwaysOff". You probably want to change it to "Qt::ScrollBarAsNeeded".

    However, I would do it a bit differently for a better user experience. Instead of using a vertical layout, I would use a QSplitter with vertical orientation to divide the QWidget. Place the MDI area in the top pane and the text widget in the bottom pane. This would allow the user to change the relative heights of the two panes as desired, for example if they wanted to see more of the text in one go rather than having to scroll a limited number of lines up and down. You can control the initial heights with QSplitter::setSizes() and how the relative sizes change when the window is resized using QSplitter::setStretchFactor().

    Note that to get the QSplitter to resize properly when the parent widget is resized, you will have to either implement a resizeEvent() handler for the widget in which you set the splitter size to match the widget size or (easier) simply add a QVBoxLayout or QHBoxLsyout to the QWidget and then add the QSplitter as the only widget in the layout. The layout will change size when the QWidget does, and in turn it will fit the splitter widget into its new size.

    You could even get more clever and store the QSplitter pane sizes in a QSettings and restore them the next time the app starts up, so the user gets a layout exactly as they left it the last time. QSplitter has "saveState" and "restoreState" methods exactly for this purpose.
    Last edited by d_stranz; 22nd August 2019 at 18:08.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    121
    Thanks
    9
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    That's exactly the kind of advice I was hoping to get! Odd that it works like this with Qt4 - maybe some defaults have changed. I'll explore the QSplitter option. Do I need to do anything to ensure that the layout sizes itself to fit the screen?
    This brings up a related question: I set up another member of the stackedwidget programmatically. There is a QHBoxLayout (biglayout) holding a couple of QGroupBoxes containing various other things. The last thing I do, after
    Qt Code:
    1. page_FACS->setLayout(biglayout);
    To copy to clipboard, switch view to plain text mode 
    is
    Qt Code:
    1. QRect rect;
    2. rect.setWidth(1900);
    3. rect.setHeight(1000);
    4. page_FACS->layout()->setGeometry(rect);
    To copy to clipboard, switch view to plain text mode 

    I have to reset the height to fit on the screen, because if I check it after setLayout, it is 1550 (I have no idea where that number comes from). I thought this would be all I needed to do, but in fact when executing the program I enable that window, it is too big for the screen, and checking shows that the height has reverted to 1550. To fix this I had to do setGeometry in the function where something is being done on page_FACS - plots are drawn (just the first time). I'm guessing that there's something I could do when page_FACS is first created to achieve the same effect.

    Thanks again d_stranz, you are helping me a lot.
    Gib

    Edit: Something must be wrong. I decided to start trying to fix the original mdiArea problem by using a vertical layout. I added the mdiArea and the text window (with height limited), but I find the behaviour is unchanged - the mdiArea still goes off the screen. By the way I checked the docs and the default scrollbar policy for QMdiArea is actually Qt::ScrollBarAsNeeded (I am not seeing a scrollbar). Stuck again.

    Edit: I wonder if it could be significant that I'm using the 'designer' facility in Qt Creator to set up page_output (with the vertical layout, mdiArea and box_outputlog), not doing it programmatically.

    Edit: A clue! If I enable page_output before it gets populated by the 20 QwtPlot objects, it looks as it should (see the attached pic, Capture-startup.png.) It seems that adding the QwtPlots has the effect of overriding the provided size info. This is the function that does it (with some irrelevant stuff concerning the formatting of the graphs removed):
    Qt Code:
    1. void MainWindow::initializeGraphs(RESULT_SET *R)
    2. {
    3. mdiArea->closeAllSubWindows();
    4. mdiArea->show();
    5. for (int i=0; i<nGraphs; i++) {
    6. mdiArea->addSubWindow(pGraph[i]);
    7. pGraph[i]->show();
    8. }
    9. mdiArea->tileSubWindows();
    10. }
    To copy to clipboard, switch view to plain text mode 

    Edit: The plot thickens! I decided to see what the docs say about tileSubWindows(). Bafflingly, it doesn't show up in the list of all members for QMdiArea: https://doc.qt.io/qt-5/qmdiarea-members.html. So how does the code compile? I tried commenting out the call to mdiArea->tileSubWindows(), and the result (attached as Capture-notiling.png) is interesting (I've stripped out some graph formatting code.) Obviously some kind of half-effective tiling has been done, and I do get a text window. This is progress - of a kind - but raises more questions. What is going on?

    Edit: OK, tileSubWindows() is in the slot list for QMdiArea. I don't know what that implies for how it should be used. Apparently invoking it by mdiArea->tileSubWindows() messes up the sizing of the window.

    Edit: The issue seems to be related to the bug discussed here: https://bugreports.qt.io/browse/QTBUG-40821. It was reported in 2014, and the latest comment was in 2016. The bug is supposedly resolved, but I don't see a scrollbar and the windows sizing problem remains. It's annoying that this worked in Qt4, but seems to be broken in Qt5.
    Attached Images Attached Images
    Last edited by gib; 23rd August 2019 at 03:06.

  4. #4
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    121
    Thanks
    9
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    I have resorted to setting up page_output programmatically. The QVBoxLayout (verticalLayout_3) is still added to the widget in Design mode, but this is the code to add mdiArea and box_outputLog (now both declared in mainwindow.h):

    Qt Code:
    1. mdiArea = new QMdiArea;
    2. verticalLayout_3->addWidget(mdiArea);
    3. box_outputLog = new QTextBrowser;
    4. verticalLayout_3->addWidget(box_outputLog);
    To copy to clipboard, switch view to plain text mode 

    This almost works. The 20 QwtPlot objects are now constrained to an area with a scrollbar - excellent! - but although the text window has a reasonable size (I don't know what is determining the sizes, since I don't specify any), but no scrollbar, so the output text quickly disappears off the bottom of the window. (see the attached Capture-program.jpg). If I try to set the size of box_outputLog:

    Qt Code:
    1. box_outputLog->setMinimumHeight(200);
    2. box_outputLog->setMaximumHeight(200);
    To copy to clipboard, switch view to plain text mode 

    the result is back to the original problem - only mdiArea is visible, extending off the screen, with no scrollbar. I haven't found a way to set the size of the vertical layout. This is very frustrating.

    Edit: I have tried the QSplitter idea:
    Qt Code:
    1. QSplitter *splitter = new QSplitter;
    2. splitter->setOrientation(Qt::Vertical);
    3. mdiArea = new QMdiArea;
    4. box_outputLog = new QTextBrowser;
    5. splitter->addWidget(mdiArea);
    6. splitter->addWidget(box_outputLog);
    7. verticalLayout_3->addWidget(splitter);
    To copy to clipboard, switch view to plain text mode 

    Maybe I've done it wrong, but anyway it doesn't change anything - I still see only the graphs, with no scrollbar.
    Attached Images Attached Images
    Last edited by gib; 23rd August 2019 at 06:11.

  5. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    Maybe I've done it wrong, but anyway it doesn't change anything - I still see only the graphs, with no scrollbar.
    In your screenshot, I see a vertical scrollbar on the right side of the MDI area. It looks to be behaving as expected. Because you are apparently setting a minimum height for your MDI subwindows, the lowest row appears to be chopped off, when in fact if you moved the scrollbar down, they'd scroll up to be fully visible. If you are also setting a minimum width, you'd see the same effect if you squeezed the width to smaller than the minimum width. (It is not obvious, but when tiling sub windows, the MDI area will expand the widths of the sub windows to fit neatly, so the only way you can get a horizontal scrollbar is to set the entire window to be less than the minimum width of a sub window. You end up with a vertical strip of single sub windows).

    This may have been the problem all along with the original fixed positioning and with the vertical layout - the MDI subwindows are too big, and the bottom rows get clipped. At least with the scrollbar policy properly set, you have a way to see what's hidden. If you always want (within reason) the entire sub window to be visible, set a smaller minimum height. (However, like the case of the minimum width, this will result in squeezing the height of the sub windows down to the minimum before the vertical scrollbar appears).

    For the text browser problem, you probably also need to explicitly set the scrollbar policy, although the docs for the base class (QAbstractScrollArea) say that the default is ScrollBarAsNeeded.

    In my practice, the only thing I use Qt Designer for is to lay out dialogs and forms with multiple small editing widgets (line edit, push buttons, etc.) for getting user inputs. But any signals or slots needed by the resulting QDialog or QWidget-derived classes are implemented by hand, not through the Designers signal / slot editor. Any other main app-level windows are constructed entirely in code.

    My reasoning is that I want to be able to see exactly what is happening with the UI as I read my code and not have some of it hidden inside MOC- or UIC-generated gibberish code. There has been more than one post in this forum about "why is my slot being executed twice?" where the answer is that the slot was named "on_pushbutton1_clicked()" and MOC has used that signature to generate boilerplate that creates the slot and setupUi() automatically connects it at runtime. If you have also used Qt Designer's signal / slot editor to connect it, that's twice. Gotcha - and all that code is "hidden" inside what MOC or UIC generate.

    And by the way, setting geometry on a widget controlled by a layout has no effect. The layout is in charge of the geometry of widgets it contains. Generally, the only place where setting geometry works as expected is on top-level independent widgets or in child widgets that aren't controlled by a layout. However, it is almost always bad practice to not use a QLayout-based design for any compound widget. Layouts, when their child widgets and layouts are properly combined with spacers and very few constraints on size behavior result in UIs that resize in pleasing ways without clipping or other unfriendly side effects.
    Last edited by d_stranz; 23rd August 2019 at 18:08.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. QMdiArea
    By Programm3r in forum Qt Programming
    Replies: 0
    Last Post: 4th May 2009, 15:25
  2. Weird behaviour with QMdiSubWindows in a QMdiArea?
    By qt_noob in forum Qt Programming
    Replies: 2
    Last Post: 4th April 2009, 17:48
  3. QMdiArea and styleSheet
    By Raccoon29 in forum Qt Programming
    Replies: 4
    Last Post: 3rd December 2008, 18:25
  4. QMdiArea with designer
    By maximAL in forum Qt Tools
    Replies: 3
    Last Post: 7th September 2007, 13:58
  5. QMdiArea problem
    By walito in forum Newbie
    Replies: 3
    Last Post: 30th July 2007, 09:52

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.