Moving QWidget to QDialog does not display widget content
-
Hi
I have a code, where I use a QTabBar and using Drag and Drop I can move a tab into a separate window. Using the same code in Qt6 Python works fine, but for whatever reason with C++ it does not.
The main issue is the following code:
ToolDialog::ToolDialog(QWidget *contentWidget, QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { _contentWidget = contentWidget; QVBoxLayout * layout = new QVBoxLayout(this); layout->addWidget(_contentWidget); this->setLayout(layout); }
The resulting QDialog is just empty. If I add another QWidget to the layout above, that element is getting displayed (also it is getting displayed, as if it is the only one present aka aligned in the middle of the resulting dialog). The _contentWidget is the correct one and containing all the information expected. Just the paint does not seem to happen.
The code, which calls the ToolDialog is a Slot with the following content:
void DetachableTabWidget::detachTab(int index, QPoint pos) { QString name = tabText(index); QWidget * contentWidget = widget(index); QRect contentWidgetRect = contentWidget->frameGeometry(); ToolDialog * detachedTab = new ToolDialog(contentWidget, parentWidget()); detachedTab->setWindowModality(Qt::NonModal); detachedTab->setWindowTitle("Conversation: " + name); detachedTab->setObjectName(name); detachedTab->setGeometry(contentWidgetRect); connect(detachedTab, &ToolDialog::onCloseSignal, this, &DetachableTabWidget::attachTab); detachedTab->move(pos); detachedTab->show(); }
I have no idea what is going on here, but maybe one of you can help me out, why the resulting QDialog does not seem to paint the given QWidget. Explicitly setting the parent to the dialog did not help also, btw.
-
Hi
I have a code, where I use a QTabBar and using Drag and Drop I can move a tab into a separate window. Using the same code in Qt6 Python works fine, but for whatever reason with C++ it does not.
The main issue is the following code:
ToolDialog::ToolDialog(QWidget *contentWidget, QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { _contentWidget = contentWidget; QVBoxLayout * layout = new QVBoxLayout(this); layout->addWidget(_contentWidget); this->setLayout(layout); }
The resulting QDialog is just empty. If I add another QWidget to the layout above, that element is getting displayed (also it is getting displayed, as if it is the only one present aka aligned in the middle of the resulting dialog). The _contentWidget is the correct one and containing all the information expected. Just the paint does not seem to happen.
The code, which calls the ToolDialog is a Slot with the following content:
void DetachableTabWidget::detachTab(int index, QPoint pos) { QString name = tabText(index); QWidget * contentWidget = widget(index); QRect contentWidgetRect = contentWidget->frameGeometry(); ToolDialog * detachedTab = new ToolDialog(contentWidget, parentWidget()); detachedTab->setWindowModality(Qt::NonModal); detachedTab->setWindowTitle("Conversation: " + name); detachedTab->setObjectName(name); detachedTab->setGeometry(contentWidgetRect); connect(detachedTab, &ToolDialog::onCloseSignal, this, &DetachableTabWidget::attachTab); detachedTab->move(pos); detachedTab->show(); }
I have no idea what is going on here, but maybe one of you can help me out, why the resulting QDialog does not seem to paint the given QWidget. Explicitly setting the parent to the dialog did not help also, btw.
@rknall
In some shape or form, you are trying to take aQWidget
which currently belongs as a tab page in aQTabWidget
and put it onto aQDialog
to display it, is that right? A widget cannot be in two places at the same time! :) I don't know what your Python code might do if that works, but you should remove the widget from the tab before you can put it onto another widget like a dialog. -
This is what I thought. But neither calling removeTab(index) after I got the widget, nor explicitly setting the parent to null will change the fact, that no content is being shown.
I also checked the underlying QStackedWidget if it still contained the widget and no, after adding a call of removeTab(index) after getting the widget itself, did not make a difference.
The Python code works fine btw, it displays the expected content.
-
This is what I thought. But neither calling removeTab(index) after I got the widget, nor explicitly setting the parent to null will change the fact, that no content is being shown.
I also checked the underlying QStackedWidget if it still contained the widget and no, after adding a call of removeTab(index) after getting the widget itself, did not make a difference.
The Python code works fine btw, it displays the expected content.
@rknall
Then show the new code which you are using. I can only guess that something in the Python does something like this for you, which you need to be explicit about in C++.One possible thought: if you remove a tab widget while it is not being shown, I assume it will have its
visible
property currently set tofalse
. You will need toshow()
it --- and possibly its descendants, check them forvisible
to be sure --- make sure you do that correctly. -
Unbelievable .. I was searching for 2 days for this. You are absolutely right. QStackedWidget - for whatever reason - sets the element to hidden after it is removed. Apparently this does not happen in the Python code. Simply setting the widget to not hidden after removing it from the QTabWidget solved it!
Thanks!
Oh, btw - no the python code did nothing special. It is just a hidden thing QStackedWidget does, which apparently is not present in the python version for the tab widget.
-
To extend, just un-hiding the widget is not enough, the widget has also to be removed from the QStackedWidget itself. The following excerpt is what works for me now:
void DetachableTabWidget::detachTab(int index, QPoint pos) { QString name = tabText(index); QWidget * contentWidget = widget(index); QRect contentWidgetRect = contentWidget->frameGeometry(); QStackedWidget * par = qobject_cast<QStackedWidget *>(contentWidget->parent()); if (!par) return; par->removeWidget(contentWidget); contentWidget->setHidden(false); ToolDialog * detachedTab = new ToolDialog(contentWidget, parentWidget()); detachedTab->setWindowModality(Qt::NonModal); detachedTab->setWindowTitle("Conversation: " + name); detachedTab->setObjectName(name); detachedTab->setGeometry(contentWidgetRect); connect(detachedTab, &ToolDialog::onCloseSignal, this, &DetachableTabWidget::attachTab); detachedTab->move(pos); detachedTab->show(); }
-
Unbelievable .. I was searching for 2 days for this. You are absolutely right. QStackedWidget - for whatever reason - sets the element to hidden after it is removed. Apparently this does not happen in the Python code. Simply setting the widget to not hidden after removing it from the QTabWidget solved it!
Thanks!
Oh, btw - no the python code did nothing special. It is just a hidden thing QStackedWidget does, which apparently is not present in the python version for the tab widget.
@rknall
I can only say that Python (PyQt, PySide) really should only be "thin" wrappers around the Qt C++ library calls. I do not know what could be happening to change their behaviour in this respect, but it's moot now as I am glad to see you have it working from C++ :) -
To extend, just un-hiding the widget is not enough, the widget has also to be removed from the QStackedWidget itself. The following excerpt is what works for me now:
void DetachableTabWidget::detachTab(int index, QPoint pos) { QString name = tabText(index); QWidget * contentWidget = widget(index); QRect contentWidgetRect = contentWidget->frameGeometry(); QStackedWidget * par = qobject_cast<QStackedWidget *>(contentWidget->parent()); if (!par) return; par->removeWidget(contentWidget); contentWidget->setHidden(false); ToolDialog * detachedTab = new ToolDialog(contentWidget, parentWidget()); detachedTab->setWindowModality(Qt::NonModal); detachedTab->setWindowTitle("Conversation: " + name); detachedTab->setObjectName(name); detachedTab->setGeometry(contentWidgetRect); connect(detachedTab, &ToolDialog::onCloseSignal, this, &DetachableTabWidget::attachTab); detachedTab->move(pos); detachedTab->show(); }
@rknall said in Moving QWidget to QDialog does not display widget content:
the widget has also to be removed from the QStackedWidget itself.
Of course it does! A given widget must only be in one place. Whether it was in the
QTabWidget
or theQStackedWidget
or both or whatever, it must be completely removed in order to put it into, say, aQDialog
. Maybe this was what was somehow happening for you in your Python (if you can be bothered you could check how it ends up in the working Python code).... -
I can be bothered ;-)
As you can see below, neither is the widget removed, nor unhidden. I checked and it seems, that the wrapper does indeed remove the widget in Python, but the same method
QWidget * widget(int tabIndex) const;
does not do it. I get that there are some differences between those two.
def detachTab(self, index, point): # Get the tab content name = self.tabText(index) icon = self.tabIcon(index) if icon.isNull(): icon = self.window().windowIcon() contentWidget = self.widget(index) contentWidgetRect = contentWidget.frameGeometry() # Create a new detached tab window detachedTab = self.DetachedTab(contentWidget, self.parentWidget()) detachedTab.setWindowModality(Qt.NonModal) detachedTab.setWindowTitle(name) detachedTab.setWindowIcon(icon) detachedTab.setObjectName(name) detachedTab.setGeometry(contentWidgetRect) detachedTab.onCloseSignal.connect(self.attachTab) detachedTab.move(point) detachedTab.show()
Just as a side-note, Qt version was in both cases Qt 6.3, PySide6 respectively.