Setting position of individual tabs in a QTabWidget
-
Hello All.
I have inherited a huge QT GUI (well, I say huge; looks big to me, but I've no idea what counts as "big" in QT circles) and a list of bugs/features to deal with.
One such involves a tabbed window (handled by a QTabWidget object; it looks like tab objects are created and then passed to the QTabWidget via the addTab fuction - looks pretty standard from my reading so far).
There is a request to privilege one particular tab; at the moment, every tab added appears on screen with the other tabs, added to the leftmost available position (i.e. the first tab goes on the left, and the next tab goes next to it, and so on, filling the QTabWidget space towards the right). The request is to have this one particular tab appear at the other end (i.e. on the right).
I see the QTabWidget::TabPosition variable in QTabWidget that dictates where all the tabs go; is there a way to privilege one particular tab and, as described above, put it at the other end?
I have had a root through the forum and the documentation; I'm so new to this it's difficult even to find the right search terms and I'm still learning the art of the possible in QT.
-
Hi Moschops,
This can be achieved by taking the actual tab page, and inserting it elsewhere in the tab widget.
Here is an example:
@
QWidget* pPrivilegedTabWidget = ui.tabWidget->widget(nPrivilegedTabIndex);
QString sTabText = ui.tabWidget->tabText(nPrivilegedTabIndex);// Will not destroy the actual widget, as stated in the documentation
ui.tabWidget->removeTab(nPrivilegedTabIndex);// Not sure this one works with an index == tabsCount
ui.tabWidget->insertTab(ui.tabWidget->count(), pPrivilegedTabWidget, sTabLabel);
// Else this one will do
ui.tabWidget->addTab(pPrivilegedTabWidget, sTabText);
@There may exist a more optimal solution to move tabs around I'm not aware of.
And if you need tabs to be added at the end, before the privileged tab, simply use "insertTab" instead of "addTab".Regards
-
Hi hi,
Thanks for replying. I think what you describe will add the tab to the end of the existing tabs, but next to them; my feature request wants this one tab to be on its own at the other end. Such that if I had one tab open already (at the left), and then opened this privileged tab, it would appear way over on the right, not touching the exisiting tab, and any other tabs I added would still go next to the one on the left. If I could add a picture here I'd show a diagram :p
If I've misunderstood what your code does and it does actually do what I'm looking for, I do apologise. I'm feeling my way in QT and I must confess that sometimes I read the documentation for a class but still don't quite understand what it does until I try it out.
I have also come up with an alternative that I think my feature requester would accept, that seems to work, but it scares me a little :p
I might be able to get the feature requester to accept, instead of having the tab over the other side of the tabbar, having it pop up in its own separate window. "How much more privileged can it get?" is how I'll sell it :p
I replaced code that looked like this:
@ tabWidget->addTab(helpWidget, QIcon(":/workplace/Help"), HelpStrings::HelpTabName);@
with code that looked like this:
@ helpWidget->setParent(NULL,Qt::Tool);
helpWidget->show();@
where helpWidget is a subclass of QWidget.Rebuild and run, and select Help, and the help pops up in its own separate, detached window. However, I now think to myself what about parents and memory and all that sort of thing? I am sure I have read that some classes, when handed an object, take responsibility for looking after it in some way - they handle its destruction or some such.
Now, I read the addtab function documentation, and it doesn't say anything about this; this makes me think that "all" the addtab function does is use the QWidget* parameter as one more thing to show, and it remains up to whoever created that QWidget to still handle destruction, management etc. If this is the case, then what I've done above should be safe?
I am still gettnig into the "mindset" of QT; still trying to understand the philosophy of object management that it uses, hence my uncertainty here. I certainly don't want to start losing objects and having memory leaks and all that sort of thing.
-
More addendum from OP:
Gargh! That's not quite so good as I'd hoped. If I make the helpWidget appear in its own separate window, everything is great until I close it - I can never get it back. I can only guess that the object still exists, and just isn't being shown, and because the rest of the application expdects it to be in the tabbar, nothing else ever calls the show function. My software archaeology continues :p
-
You're correct, I misunderstood what you wanted to do.
First, regarding your questions about memory management: Qt classes (QObject inherited classes) have a memory management mechanism, which deletes objects for you, but here is the principle:
- Most Qt class inherit QObject (QObject means signals and slots, parent/children, QProperties, etc.). Exceptions are data containers and small graphical objects (QGraphicsItem's)
- QObject have can have children, and a parent
- The more common way to set the parent of a QObject is to pass it to the constructor of your class
@m_pWidget = new QWidget(pParentWidget);
or
QObject* myObject = new QObject(pParentObject);
@
For a widget, this will make it a child widget (same window) of its parent. - When destroying a QObject, it automatically destroyes all its children, which in turn destroy their children, etc.
In your case, all widgets attached to tabs will be destroyed when your tab widget is destroyed. Because to be visible(or not) in your tab widget, this widget has to be a child of the tab widget.
What is done with "removeTab", is that the widget is taken from the tab widget by "unparenting" it. And once done, as not anymore a child of the tab widget, it will not be destroyed when destroying the tab widget.
There is some good reading about QObject and memory management here on QtProject documentation, I just can't find the page.
Then concerning your first question, the easier/quicker is to add a button on top of your tab widget to me. Else you'd need to override the painting of the tab widget, I think, which will not be trivial, and maybe needs to touch private information of that class (not recommanded).
An other solution is to use a QStackedWidget (the base class of QTabWidget), and add your own "tabs system". This one is more feasable, as you just ( :) ) have to dynamically create buttons and set their position/size, and handle their "clicked" signal. -
Thanks for the words; all much appreciated - I will read them all again and see what i can come up with. In an ideal world I'd start at page one of Blanchette & Summerfield, but life is what it is :)
bq. And once done, as not anymore a child of the tab widget, it will not be destroyed when destroying the tab widget.
Aha. That does make sense. So when I do this:
@ helpWidget->setParent(NULL,Qt::Tool);@
I am removing any and all parentage from my helpWidget, so it will not be destroyed as a side-effect of anything else (i.e. a parent) being destroyed. It is up to me to destroy it, so I'd better not lose the pointer to it.Previously, because I had this:
@ tabWidget->addTab(helpWidget, QIcon(":/workplace/Help"), HelpStrings::HelpTabName);@
the helpWidget destruction was being taken care of for me by tabWidget.Conceptually, I want helpWidget to be destroyed when the user closes the pop-up window (using my new system of having helpWidget show in its own completely separate window), so I should be able to tie the destruction of helpWidget to the destruction of that window. I think what I might be looking for is the Qt::WA_DeleteOnClose flag which should, hopefully, cause helpWidget to be deleted just as if I'd typed @delete helpWidget;@ somewhere.
Tinkering with established code is rather nerve-wracking :p
-
Yes that's it.
But you can also create it only once, and hide/show it. This is usually prefered when you want to save CPU (though if on desktop PC that doesn't matter at all), or simply preserve some user state, like scrolling position etc.
You can destroy it in your main window destructor then.