PDA

View Full Version : Calling QMainWindow::show() breaks QMenuBar::cornerWidget()



jacobP
12th October 2016, 22:36
I have an issue that I have been able to recreate in QtCreator :

Here is my QtCreator .ui file below. It is a empty basic QMainWindow with a QMenuBar containing 5 actions.


<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1085</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget"/>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1085</width>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
<string>Edit</string>
</property>
</widget>
<widget class="QMenu" name="menuCreate">
<property name="title">
<string>Create</string>
</property>
</widget>
<widget class="QMenu" name="menuWindow">
<property name="title">
<string>Window</string>
</property>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
<addaction name="menuCreate"/>
<addaction name="menuWindow"/>
<addaction name="menuHelp"/>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

Here is my mainwindow.cpp, my only source file in my project (except the main.cpp which I did not modify).

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QHBoxLayout>
#include <QMenuBar>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setGeometry(100,100,1306,722);
QMenuBar* menuBar = this->menuBar();

//creating a QFrame cornerwidget containing a HBoxLayout
QFrame* corner_widget_frame = new QFrame(menuBar);
QHBoxLayout* corner_widget_layout = new QHBoxLayout();
corner_widget_layout->setMargin(4);
corner_widget_layout->setSpacing(0);
corner_widget_frame->setLayout(corner_widget_layout);
corner_widget_frame->setAutoFillBackground(false);
corner_widget_frame->setStyleSheet("background-color: #FF0000;");
menuBar->setCornerWidget(corner_widget_frame);

//bring to front
setWindowState( (windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
show();
activateWindow();
//bring to front END

//create test widget
QWidget* blue_widget = new QWidget(); //no parent
blue_widget->setFixedSize(40,5);
blue_widget->setStyleSheet("background-color:blue;");
//create test widget END

//adding my widget to the corner_widget_frame
this->menuBar()->cornerWidget()->layout()->addWidget(blue_widget);
}

MainWindow::~MainWindow()
{
delete ui;
}

If you run this code in the QtCreator, you will see that the blue_widget is barely visible up in the top right corner. The majority of the widget is cut off from the main window. If I resize the main window horizontally the corner widget will appear correctly permanently.

12161

However, if you put the bring to front code at the end of the file, after the blue_widget is added, the widget is correctly displayed. I saw that if I comment out the QMainWindow::show() call in the code I posted above, I do not have my problem and the window is correctly displayed (not hidden), giving me the impression that in my current case the call to QMainWindow::show() is not only causing the problem but is also useless.
12162

I am working on an already existing application, I created this QtCreator project to isolate and replicate the issue. I did not add the QMainWindow::show() call myself in the application. Removing the QMainWindow::show() call in my application fixes my problem and doesn't seem to cause any issue, but I am afraid to remove it since I think it could cause other issues I don't see in my preliminary tests. Also in the application there is a certain period of time and several things happening between the time the bring to front code is executed and the widget is added to the corner widget(if it is added at all), meaning I cannot add my widget when my QMenubar is having it's corner widget created or before the QMainWindow::show() call.

According to documentation, all QWidget::show() does is litteraly show the widget and its parents. I have tried (in my QtCreator project and the application) to call QWidget::update(), QWidget::updateGeometry() and QWidget::show() on the QMainWindow, the QMenubar, the corner widget and the (blue)test_widget after adding my (blue)test_widget, to no avail. I also tried calling menuBar->adjustSize() but I did not see any changes.

I have also noticed that if I completely remove the QMenubar (meaning the 5 actions are gone) from my QMainWindow (with the QtCreator ui editor), the QMainWindow::show() call will not cause the issue and my corner widget will display properly.

So what does QMainWindow::show() do under the hood exactly ? Why is it causing this issue ? Is the QMainWindow::show() necessary ?

Thanks for the help.

anda_skoa
13th October 2016, 10:48
This is interesting, the blue widget should not show at all.

It is created after its parent is shown, so it should require an explicit show.

In any case the code to show the main window would usually be where the main window is being used, not inside its constructor, but of course that doesn't explain why the blue widget shows (as it shouldn't).

Cheers,
_

jacobP
13th October 2016, 16:34
Hi anda,

I made the simplest project possible, so you can copy all of it and paste it in QtCreator to see the results.

You say that the blue widget should not show at all, does that mean that a QWidget should always call QWidget::show on himself after he is added to a QLayout ?

For the code being in the constructor, I only did it that way to have the simplest code possible to show my issue. I understand and agree with your point.

With all that said, you made me realize a very important discovery: calling blue_widget->show() at the end of my code in my QtCreator project does fixe the problem, but doing the same in my application does not fix the issue. This is the 1st time I see a different behavior, I thought I had manage to have the same 1:1 behavior between the QtCreator project and my application.

Thanks for the help, I will keep looking.

anda_skoa
14th October 2016, 11:13
You say that the blue widget should not show at all, does that mean that a QWidget should always call QWidget::show on himself after he is added to a QLayout ?

No, it depends on the state of the parent when the child is created/added.

Basically a widget shows all its children when it is shown for the first time, but if you show a widget and then add children, they remain hidden until they are shown explicitly.
So what you are seeing is some kind of weird hybrid behavior, quite likely a bug.



For the code being in the constructor, I only did it that way to have the simplest code possible to show my issue. I understand and agree with your point.

I was mostly pointing this out as it would then not trigger your problem.
I.e. the weird behavior would normally not be observable.

Cheers,
_