Results 1 to 19 of 19

Thread: QMdiArea behaviour different between Qt4 and Qt5

  1. #1
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    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
    4,118
    Thanks
    235
    Thanked 656 Times in 646 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    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 17: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
    112
    Thanks
    8
    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 02:06.

  4. #4
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    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 05:11.

  5. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,118
    Thanks
    235
    Thanked 656 Times in 646 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    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 17: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.

  6. #6
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    Hi d_stranz,
    The screenshot attached to my previous post is referred to here:
    "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)."
    It was the result of creating mdiArea and the text window programmatically - the scrollbar was automatically generated, I didn't do anything to get it. This situation is an improvement but still no scrollbar on the text window. I need to emphasise that with Qt4 I get scrollbars on both windows - it all works perfectly even though I don't use a layout.

    I found that any attempts I made to fix the size of the text window made things worse, reverting to the situation shown in Capture-Qt5.jpg in my first post. This includes trying adding a QSplitter.

    It's useful to know that the layout is controlling the geometry - but then what controls the layout? For example, what is determining the relative sizes of the windows in Capture-program.jpg? I can live with the geometry that is automatically provided, but I do need a scrollbar on the text window, without that it is useless. I haven't yet found out how to add a scrollbar.

    I have to apologise for packing so much into my previous posts, and you may have missed my question about another widget, on page_FACS. Here I create everything programmatically, including the layout that contains it all. I found that the layout was effectively too big for the screen - the contained graphs extending off the bottom of the screen - and the only way I could get to see everything was by doing setGeometry on the layout. This is obviously unsatisfactory since the size specified for my screen may be wrong on another screen. I thought the layout should automatically size itself to fit the screen, but this is not happening. Since the problem here is similar to the page_output problem, I thought I should mention it at the same time.

    Thanks for your continued attention to this tedious topic.

    Gib


    Added after 1 16 minutes:


    I am increasingly suspecting that this is a Qt5 bug, related to tileSubWindows() (it works perfectly in Qt4). I have attached three screenshots, which I will explain.
    First, I am setting stretch factors, 4 for the MDI window, 1 for the text window.
    Qt Code:
    1. mdiArea = new QMdiArea;
    2. box_outputLog = new QTextBrowser;
    3. verticalLayout_3->addWidget(mdiArea,4);
    4. verticalLayout_3->addWidget(box_outputLog,1);
    To copy to clipboard, switch view to plain text mode 

    before-addSubWindow.jpg is what the screen looks like after the MDI and text windows have been created, but before the 20 subwindows have been added. This shows that the layout is as desired.

    without-tileSubWindows.jpg shows the screen while the program is executing, after adding the subwindows but with tileSubWindows() commented out. Note that the graphs are crammed into the MDI window, overlapping, and there is no scrollbar.

    with-tileSubWindows.jpg shows the screen while executing when the program is compiled with tileSubWindows(). Now the graphs fill the screen, with a non-functioning scrollbar - and an extra scrollbar to the right of it. There is no sign of the text window.

    I'm trying to come up with a small reproducer to make a bug report, but it is not simple. What a time-waster this is!
    Attached Images Attached Images
    Last edited by gib; 23rd August 2019 at 23:00.

  7. #7
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,118
    Thanks
    235
    Thanked 656 Times in 646 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    It's unlikely to be a Qt bug. (Sorry).

    Can you post the code where you create this widget? (i.e. the code that basically creates the whole layout, splitter, mdi, and text hierarchy and adds it as a stacked widget page) There is likely something very basic wrong that isn't being revealed by the verbal descriptions or screen shots.
    <=== 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.

  8. #8
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    I know that a bug in Qt is very unlikely, and problems like this always turn out to be my error. I'm just running out of ideas.
    Because most of the UI is created in Design mode, I can just show a screenshot when page_output is selected. The code part is very simple. The MDI and text windows, mainwindow.h variables, are created when mainwindow starts.
    Qt Code:
    1. mdiArea = new QMdiArea;
    2. box_outputLog = new QTextBrowser;
    To copy to clipboard, switch view to plain text mode 

    When I click a button to start the simulation, the initializeGraphs() function is executed.
    Qt Code:
    1. void MainWindow::initializeGraphs(RESULT_SET *R)
    2. {
    3. LOG_QMSG("initializeGraphs");
    4. mdiArea->closeAllSubWindows();
    5. mdiArea->show();
    6.  
    7. setGraphsActive();
    8. int non_ts = 0;
    9. grph->makeGraphList(non_ts);
    10. nGraphs = grph->nGraphs;
    11. if (nGraphCases > 0) {
    12. clearAllGraphs();
    13. }
    14. QString title = "title";
    15. QString tag = "tag";
    16. for (int i=0; i<nGraphs; i++) {
    17. if (!grph->isTimeseries(i) && !grph->isProfile(i) && !grph->isDistribution(i)) continue; // ???
    18. if (pGraph[i] != nullptr) {
    19. pGraph[i]->deleteLater();
    20. pGraph[i] = nullptr;
    21. }
    22. if (pGraph[i] == nullptr) {
    23. pGraph[i] = new Plot(tag,R->casename);
    24. pGraph[i]->setTitle(title);
    25. }
    26. }
    27.  
    28. for (int i=0; i<nGraphs; i++) {
    29. if (!grph->isTimeseries(i) && !grph->isProfile(i) && !grph->isDistribution(i)) continue;
    30. mdiArea->addSubWindow(pGraph[i]);
    31. pGraph[i]->show();
    32. }
    33.  
    34. verticalLayout_3->addWidget(mdiArea,2);
    35. verticalLayout_3->addWidget(box_outputLog,1);
    36.  
    37. mdiArea->tileSubWindows();
    38. }
    To copy to clipboard, switch view to plain text mode 

    I have experimented with the placement of the tileSubWindows line. If it is located after the addWidget, as shown here, the result is shown in after-addwidget.jpg, while if it is located before addWidget, I see before-addwidget.jpg.
    In the 'before' case, something strange has been done to the MDI window, but the text window is fine - the scrollbar allows all the text to be viewed. In the 'after' case, the MDI scrollbar works correctly, but although the text window has a scrollbar, part of the window is off the screen, and even when the scrollbar is scrolled all the way down a number of lines at the bottom are not visible. This is why it looks as if the layout has the wrong size.
    Attached Images Attached Images

  9. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,118
    Thanks
    235
    Thanked 656 Times in 646 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    are created when mainwindow starts
    What does "starts" mean? In the MainWindow constructor, after setupUi() is called? In the showEvent()? Somewhere else?

    mdiArea->show();
    This and any other calls which affect what is seen onscreen will probably not have any visible effect until after this method is exited because those things require the Qt event loop to run. Likewise, if MainWindow's showEvent() has not occurred prior to the call to initializeGraphs(), no methods that ask for geometry of MainWindow or any of its unshown child windows will return a valid result. Window sizes and geometries are not valid until the showEvent() is first entered. This includes within the MainWindow constructor and any methods called from it. Geometries are also not valid inside resizeEvent() unless a call to isVisible() returns true.

    verticalLayout_3->addWidget(mdiArea,2);
    verticalLayout_3->addWidget(box_outputLog,1);
    These calls should immediately follow the two lines where you create the widgets. And they especially should not be called from a method that could be executed more than once.

    But you still haven't shown the right thing. And from what I see in the code you did post, it doesn't correspond to what I thought you said you were doing.

    First, is "MainWindow" derived from QMainWindow?

    Second, what are you using as the "centralWidget()" for your QMainWindow-based widget? I had thought you said it was a QStackedWidget and that the MDI area and text browser were widgets added to a widget that was a page in this stacked widget?

    Third - if you aren't using a QStackedWidget as the central widget, are you setting a central widget at all (in code or in the UI file)?

    Fourth, on what widget are you installing verticalLayout_3?

    If these steps have been done using Qt Designer, then seeing the MainWindow.ui file would help.
    <=== 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.

  10. #10
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    Sorry for not answering your questions correctly. I'll try to be more complete, subject to my limited understanding. The code is rather extensive, and probably doesn't follow best practice.
    The MainWindow class declaration starts like this:

    Qt Code:
    1. class MainWindow : public QMainWindow, private Ui::MainWindow
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. MainWindow(QWidget *parent = nullptr);
    To copy to clipboard, switch view to plain text mode 

    and then in mainwindow.cpp (leaving out a lot of irrelavant code)

    Qt Code:
    1. MainWindow::MainWindow(QWidget *parent)
    2. : QMainWindow(parent)
    3. {
    4. setupUi(this);
    5. showMaximized();
    6. ...
    7. mdiArea = new QMdiArea;
    8. box_outputLog = new QTextBrowser;
    9. ...
    10. goToInputs();
    11. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. void MainWindow::goToInputs()
    2. {
    3. stackedWidget->setCurrentIndex(0);
    4. action_inputs->setEnabled(false);
    5. action_outputs->setEnabled(true);
    6. action_VTK->setEnabled(true);
    7. action_FACS->setEnabled(true);
    8. action_field->setEnabled(true);
    9. }
    To copy to clipboard, switch view to plain text mode 

    At this point the user can change input data, and when ready click a button that starts does several things, including initializeGraphs, then starts the simulation and enables the output screen (page_output) where status messages are written to the text window and graphs are updated in real time.
    These calls should immediately follow the two lines where you create the widgets. And they especially should not be called from a method that could be executed more than once.
    Effectively these calls do come immediately after creation of the widgets - initializeGraphs is called only once.

    Second, what are you using as the "centralWidget()" for your QMainWindow-based widget? I had thought you said it was a QStackedWidget and that the MDI area and text browser were widgets added to a widget that was a page in this stacked widget?

    Third - if you aren't using a QStackedWidget as the central widget, are you setting a central widget at all (in code or in the UI file)?
    The way the widgets are related is shown in UI.jpg (attached).
    MainWindow: QMainWindow
    centralwidget:QWidget
    stackedwidget:QStackedWidget
    page_output:QWidget
    verticalLayout_3:QVBoxLayout

    Fourth, on what widget are you installing verticalLayout_3?
    As you can see, verticalLayout_3 is installed on page_output, a QWidget.

    Everything was created in Design mode. It is rather complicated, but it all works with Qt4, except that the Qt4 code doesn't have the QVBoxLayout, and the QMdiArea and QTextBrowser widgets are added directly to page_output, in Design mode, while now I'm adding them to the layout in code.
    Unfortunately I can't attach the ui file, because it is 413 kB, exceeding the limit for such files. It comprises many input screens, each with a large number of widgets.
    This program (and the simulation engine - built as a DLL - that it provides the GUI for) has been developed over several years and has grown in complexity. Everything still works fine in the Qt4 version. The reason for moving to Qt5 is that I like the idea of using Qt3d for OpenGL graphics instead of VTK, which I'm currently using, and which can create problems as the VTK code and the way it works with Qt is changing.
    Attached Images Attached Images
    Last edited by gib; 24th August 2019 at 04:33.

  11. #11
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,118
    Thanks
    235
    Thanked 656 Times in 646 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    (leaving out a lot of irrelavant code)
    Arrgh. It is mostly like exactly the code that you label irrelevant that is the problem. Can you please simply post the entire MainWindow constructor code and the member variables section of MainWindow.h? It is impossible to tell from what you have posted and from your verbal descriptions how these various widgets are assembled into your main window hierarchy. Your screenshots are so small they are illegible so those are no help.

    I am using VTK for 3D scientific graphics precisely because Qt3D has no built-in support for it and because the Qt Visualization and Qt Charts frameworks are so rigidly designed they allow for absolutely no customization or extension. VTK has a steep learning curve, but once you start to understand it, it is way more flexible than anything in Qt. Not really sure what you mean by "the way it works with Qt is changing" - yes, there are some new classes for hosting OpenGL graphics in Qt widgets, but those have been around for a while.
    <=== 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.

  12. #12
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    I'm not sure exactly what constitutes the "entire MainWindow constructor code". Is that the whole code block starting 'MainWindow::MainWindow(QWidget *parent)'? The omitted code really is irrelevant. I have sent everything that relates to the creation of the UI, except of course the manual process of construction in Design mode. There is one more action before initializeGraphs():
    Qt Code:
    1. connect(sthread0, SIGNAL(sh_output(QString)), box_outputLog, SLOT(append(QString)));
    To copy to clipboard, switch view to plain text mode 
    this happens after the Run button is clicked, and after creation of the thread sthread0 (which handles asynchronous communications with the DLL engine). I don't think this is relevant to the behaviour I'm seeing.

    I had noticed that the .png files I attach are converted to .jpg, but I didn't know (until I read your comment) that the resolution is drastically reduced.

    I have been using QVTKWidget for 3D visualisation in several Qt projects for about 10 years. This was first deprecated, and in the latest VTK versions it has been dropped, replaced by some different classes, so my program doesn't build with the latest VTK. The Qt4 versions of my programs work fine, and I can continue with them as long as I stick to an old enough version of VTK. It occurred to me, since I have some spare time, to explore the possibility of doing everything within Qt, thus simplifying upgrading (I'm also trying to get a Linux version working, and I ran into some issues there that I can't recall right now.) It looked as if Qt3d might be able to do what I want in the current program, in which I need only display spheres, and my preliminary testing was positive. Using Qt5 t has turned out to be tricky for reasons unrelated to Qt3d (for testing I have removed VTK and not yet added in Qt3d functionality.)

    You have to bear in mind that I have a very limited grasp of C++, just enough to get things working without really understanding why they work. It's a matter of old dog, new tricks. You'd probably be horrified if you saw my code, which contains a lot of C-style programming. The only good thing about it is that it works (with Qt4). You have been very patient, but I sense that your patience may be wearing thin - quite understandably. What I'd like to be able to do is cut my code down to a small program that reproduces the problem, but that is easier said than done, since it has so many moving and interconnected parts.

  13. #13
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    I have created a simple reproducer. Actually I've left almost all the code unchanged except for a couple of functions and MainWindow::MainWindow, which is now a few lines:
    Qt Code:
    1. MainWindow::MainWindow(QWidget *parent)
    2. : QMainWindow(parent)
    3. {
    4. setupUi(this);
    5. showMaximized();
    6.  
    7. connect(action_run, SIGNAL(triggered()), SLOT(runServer()));
    8. goToInputs();
    9. }
    To copy to clipboard, switch view to plain text mode 

    After goToInputs() has executed, clicking the Run button executes runServer():
    Qt Code:
    1. void MainWindow::runServer()
    2. {
    3. initializer();
    4. goToOutputs();
    5. return;
    6. }
    7.  
    8. void MainWindow::initializer()
    9. {
    10. bool use_graphs = true;
    11. mdiArea = new QMdiArea;
    12. box_outputLog = new QTextBrowser;
    13.  
    14. for (int i = 0; i < 20; i++) {
    15. if (use_graphs) {
    16. pGraph[i] = new Plot("tag","title");
    17. mdiArea->addSubWindow(pGraph[i]);
    18. } else {
    19. editor[i] = new QTextEdit;
    20. editor[i]->setMinimumHeight(200);
    21. editor[i]->setMinimumWidth(80);
    22. mdiArea->addSubWindow(editor[i]);
    23. }
    24. }
    25. verticalLayout_3->addWidget(mdiArea,2);
    26. verticalLayout_3->addWidget(box_outputLog,1);
    27. mdiArea->tileSubWindows();
    28. for (int i = 0; i < 50; i++) {
    29. QString line = "line number: " + QString::number(i);
    30. box_outputLog->append(line);
    31. }
    32. }
    To copy to clipboard, switch view to plain text mode 

    With use_graphs = true or false, I get the attached with-QwtPlot.jpg or with-QTextEdit.jpg, attached.
    Here is class Plot:
    Qt Code:
    1. class Plot : public QwtPlot
    2. {
    3. public:
    4. Plot(QString, QString, QWidget *parent = 0);
    5. ~Plot();
    6.  
    7. void mousePressEvent (QMouseEvent *);
    8. void addCurve(QString);
    9. void removeCurve(QString);
    10. void removeAllCurves();
    11. void redraw(double *, double *, int, QString, QString, double, bool);
    12. void redraw2(double *, double *, double *, double *, int, int);
    13. void draw2(double *, double *, double *, double *, int, int);
    14. void setYScale(double);
    15. double calc_yscale(double);
    16.  
    17. QString name;
    18. static const int ncmax = 8;
    19. QwtPlotCurve *curve[ncmax];
    20. double xscale;
    21. double yscale;
    22. int ncurves;
    23. char msg[1024];
    24. };
    To copy to clipboard, switch view to plain text mode 

    (I am using qwt-6.1.3)

    mainwindow.h includes:
    Qt Code:
    1. QMdiArea *mdiArea;
    2. QTextBrowser *box_outputLog;
    3. QTextEdit *editor[20];
    4. Plot *pGraph[32];
    To copy to clipboard, switch view to plain text mode 

    page_output looks similar but not quite the same in the two cases. With use_graphs=false (with-QTextEdit.jpg) the scrollbar enables viewing of lines 1 to 35 - the last 14 lines are off the screen. With use_graphs=true (with-QwtPlot), there is a scrollbar on the text window, but the slider is not visible, and only lines 13 to 18 can be seen. In both cases the MDI window scrolls correctly, but the window sizing is different in the two cases, and in neither does it correspond to the 2:1 ratio specified by the stretch factors.
    I have made a closeup pic of the relevant section of the UI display (ui-closeup.jpg), showing where verticalLayout_3 is located.

    Edit: A small correction: the scrollbar slider for the use_graphs=true case can be raised by clicking in the bar, but only 6 lines can ever be viewed, e.g. lines 0-5. It's possible that, taking into account that part of the layout that is invisible (off-screen), the 2:1 ratio is in fact effective. The question is this: how to make the layout fit the screen?
    Attached Images Attached Images
    Last edited by gib; 25th August 2019 at 05:04.

  14. #14
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,118
    Thanks
    235
    Thanked 656 Times in 646 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    OK, first, you should be constructing and adding the MDI area and text browser in the MainWindow constructor, not through a slot that could be executed multiple times. As your code stands now, each time you click the run button, you will create another pair of MDI area and text browser instances. And because you use the same variables to store those new instances, the instances created on the previous run will become dangling and inaccessible. The new MDI area and text browser instances will be used for the subsequent lines, not the original ones. I am pretty sure that's not what you want.

    Likewise, your initializer() method also produces a whole new set of plots or text edits each time the run button is clicked, and these also hide the 20 original ones that were produced on the previous click.

    I hope that this isn't the case in your real program and that this is just a result of trying to create a demonstration too hastily.

    In any case, the point is: create any widgets you are going to use -once-, in the MainWindow constructor, and re-use those widgets instead of repeatedly destroying and re-creating them. The MDI area and text browser can be created and added to the vertical layout once. Likewise the plots and the text edits. To switch between plot mode and text mode, you simply make the other set of MDI sub windows invisible (setVislble( false ) or call hide()). Or add a second stacked widget in place of the current MDI area, and create two MDI area pages in that stack, one for plots and one for text edits. To switch modes, just display the appropriate page.

    I think that the majority of the problems you are having with this UI are a result of 1) the previous implementation doing everything in Qt Designer, 2) not using layouts, and 3) changes between Qt 4 and 5 which probably tightened up some of the UI and layout behavior and eliminated holes which allowed the previous UI to work.

    I would suggest you do the following to refactor your UI and make it more stable, predictable, and maintainable:

    - take one page from the stacked widget at a time and re-implement that page as a separate QWidget-based class (without a UI file)
    - make sure there is a top-level layout of some sort for that page
    - add any sub-components for that page to the proper locations in the layout in code, not UI
    - add the page to the stacked widget manually (in the MainWindow constructor)
    - eliminate the corresponding code for that page from the UI file

    Finally, eliminate the stacked widget itself from the UI file by creating it manually in the MainWindow constructor and adding it as the centralWidget. Something like this:

    Qt Code:
    1. MainWindow::MainWindow( QWidget * parent ) : QMainWindow( parent )
    2. {
    3. setupUi(); // Creates menu, tool, and status bars and other standard QMainWindow features
    4.  
    5. stackedWidget = new QStackedWidget( this );
    6. page_input = new PageInput();
    7. page_output = new PageOutput();
    8. page_3D = new Page3D();
    9. page_2D = new Page2D();
    10. page_FACS = new PageFACS();
    11.  
    12. stackedWidget->addPage( page_input );
    13. stackedWidget->addPage( page_output );
    14. stackedWidget->addPage( page_3D );
    15. stackedWidget->addPage( page_2D );
    16. stackedWidget->addPage( page_FACS );
    17.  
    18. setCentralWidget( stackedWidget );
    19.  
    20. // connect actions, etc.
    21. }
    To copy to clipboard, switch view to plain text mode 

    This refactoring accomplishes several things:

    First, it makes clear exactly how your UI hierarchy is being constructed. It doesn't hide half of it in the ui file.
    Second, your MainWindow.ui file no longer contains the entire user interface description for your program, and neither does MainWindow.[h,cpp]
    Third, each page in the stacked widget is implemented in it own class files, independent of all the others. You can replace or modify any page without affecting either MainWindow or the other pages.
    Fourth, this independence allows you to add new pages or remove pages at will, in code, without Qt Designer.

    I would also suggest that you replace the central QStackedWidget with QTabWidget. The programming API is nearly identical, but has the usability advantage of being able to simply click a tab to switch between pages.
    <=== 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.

  15. #15
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    Quote Originally Posted by d_stranz View Post
    OK, first, you should be constructing and adding the MDI area and text browser in the MainWindow constructor, not through a slot that could be executed multiple times. As your code stands now, each time you click the run button, you will create another pair of MDI area and text browser instances. And because you use the same variables to store those new instances, the instances created on the previous run will become dangling and inaccessible. The new MDI area and text browser instances will be used for the subsequent lines, not the original ones. I am pretty sure that's not what you want.

    Likewise, your initializer() method also produces a whole new set of plots or text edits each time the run button is clicked, and these also hide the 20 original ones that were produced on the previous click.

    I hope that this isn't the case in your real program and that this is just a result of trying to create a demonstration too hastily.

    In any case, the point is: create any widgets you are going to use -once-, in the MainWindow constructor, and re-use those widgets instead of repeatedly destroying and re-creating them.
    The example I showed was merely to illustrate the problem with the layout. The only connection with my actual code is that it uses almost the same Design-generated UI (apart from the addition of verticalLayout_3). Needless to say, in my code I don't do the things you warn about. The MDI and text windows, and the subwindows, are created once only. As I've mentioned repeatedly, I've been using this code in several projects for several years, with no problems (with Qt4). My hope in creating this extremely simple code was that somebody would see either that I was doing something wrong, or that Qt5 is behaving wrongly. The conclusion seems to be that the problem must lie in the UI separate from the code I showed, i.e. in the bulk of the UI that was created using the Design facility of Qt Creator. That suggests to me a Qt5 problem, since any UI that is created in that way, and doesn't generate an error, should work.

    I'm still considering submitting a bug report, if only to find out what's wrong with the UI. That would take quite a lot of work, however. I'd need to strip almost everything out of the program, and out of the UI, but leaving that multi-level structure leading to the final layout. Since I hate to leave mysteries unsolved, I might do it.

    Your suggestions about how to redo the UI are interesting, and no doubt well founded. If I feel inspired I might give it a shot.

    Meanwhile I want to correct one statement I made about VTK (a memory lapse.) QVTKWidget has not been removed, although it is deprecated and there are another couple of widgets to replace it (they are still being revised, according to advice from VTK.) What I know is that code that worked with Qt4 and VTK 5.10 now causes a crash on Ubuntu 16.04 with Qt5 and VTK 8.2 when qvtkWidget->GetRenderWindow() is executed. I'm seeking help about this on discourse.vtk.org.

  16. #16
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    I have found a solution, although it isn't very satisfactory. If I set the maximum height of page_output (which holds verticalLayout_3) to 1090, the two windows (with stretch factor ratio 4:1) just fit on my screen, which has resolution 1920x1200, and scrolling enables all the contents to be viewed. This works for the test cases, and for my real code. The question is: what happens when the program is run on a system with a different screen resolution? It is my understanding that when the maximum size is set to 16777215 x 16777215 the layout should be automatically fit to the available screen space. This is not happening for some reason.
    Last edited by gib; 26th August 2019 at 03:59.

  17. #17
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,118
    Thanks
    235
    Thanked 656 Times in 646 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    It is my understanding that when the maximum size is set to 16777215 x 16777215 the layout should be automatically fit to the available screen space.
    Not true. MainWindow::showMaximized() should fit the window to the actual screen size, but MainWindow::show() will size it to whatever was set programmatically (either a default size or based on a call to resize()). However, if your code has overridden Qt's normal behavior by explicitly setting geometries and not using layouts, then all bets are off because Qt will usually follow the maxim that the code is always right.
    <=== 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.

  18. #18
    Join Date
    Mar 2010
    Location
    Auckland, NZ
    Posts
    112
    Thanks
    8
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    I am using a layout: verticalLayout_3. The only reason I am now setting geometry for page_output is that otherwise the layout is not constrained to fit the screen. Have I not made this clear?

  19. #19
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,118
    Thanks
    235
    Thanked 656 Times in 646 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: QMdiArea behaviour different between Qt4 and Qt5

    The only reason I am now setting geometry for page_output is that otherwise the layout is not constrained to fit the screen.
    Then there is almost certainly something wrong with the way the UI is defined. It is the MainWindow that determines the overall size of the application on screen, not any child widget within it, unless that widget is being created without a parent and is never added to a layout (which has itself been added to a parent QWidget). Only in the case where a widget (or its layout) are top-level (ie. parentless) can a widget be larger than the app's main window. Widget geometry is always relative to its parent and only if there is no parent can geometry be set arbitrarily.
    <=== 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, 14:25
  2. Weird behaviour with QMdiSubWindows in a QMdiArea?
    By qt_noob in forum Qt Programming
    Replies: 2
    Last Post: 4th April 2009, 16:48
  3. QMdiArea and styleSheet
    By Raccoon29 in forum Qt Programming
    Replies: 4
    Last Post: 3rd December 2008, 17:25
  4. QMdiArea with designer
    By maximAL in forum Qt Tools
    Replies: 3
    Last Post: 7th September 2007, 12:58
  5. QMdiArea problem
    By walito in forum Newbie
    Replies: 3
    Last Post: 30th July 2007, 08: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.