QComboBox Show/Hide Problem
-
Edit, using with Qt Version 4.6.3
Greetings qt community!I am working on an application in Qt in which I am creating a dynamic QWizardPage in which selecting an option from a QComboBox will make other options appear on the page for the user to select. I know there are several ways to do this such as QStackedWidget, but I would like to simply show/hide different components manually.
I have hand coded a custom QWizard and each QWizardPage. On this particular QWizardPage, there is initially a QLineEdit and a QCombo box. When I select an option, I show the other form components and everything works as expected. However, if I navigate to a different QWizardPage and then back to this one, the items are redrawn, but the QComboBox will show the options as a gray box (It still has the options as pressing up/down on the keyboard changes the value in the top of the box, but you can't read any of the options because of the gray box).
This is the way I have it setup:
The form components are all created in a .ui using the form designer. A QFrame is then set up using this ui and added to a QGridLayout which is then set as the main layout for the QWizardPage.I have overrided the initializePage() function:
@QList<QWidget*> lWidgets = m_fDetailsFrame->findChildren<QWidget*>();
for (int i = 0; i < lWidgets.size(); i++)
{
lWidgets[i]->hide();
}
m_fDetailsFrame->findChild<QWidget*>("m_cbConnectionTypes")->show();
m_fDetailsFrame->findChild<QWidget*>("m_lConnectionTypes")->show();@That is, I hide all the widgets in the frame, then I specifically show two of them, a QLabel and a QComboBox. Now, the weird thing is, this is the code that executes the first time and it works correctly and I can see the options. Also weird, is that if I explicitly hide the item with:
@m_fDetailsFrame->findChild<QWidget*>("m_cbConnectionTypes")->hide();@
It is redrawn correctly every time! However, I do not want to hard-code in a hide for every individual component. Also peculiar, if I add another QComboBox to the frame, it is only the last QComboBox that has this problem. I have tried several different options such as use setvisible vs hide and trying to retrieve the widgets from the frame from the ui but it always has the same result. What am I missing here that could be causing this problem? -
@mohsen: "update()":http://doc.qt.nokia.com/4.7/qwidget.html#update is preferred instead of "repaint()":http://doc.qt.nokia.com/4.7/qwidget.html#repaint
-
[quote author="mohsen" date="1294512238"]Use below code after "for" syntax.
@this->repaint();@ [/quote]Previously I tried repainting the components, but I had not thought to try repainting the entire QWizardPage. However, even with that code inserted, it still exhibits the same problem. Just to expand on this idea, I tried explicitly telling everything to repaint--even the whole QWizard, but it did not make any difference. It still looks like this:
!http://lakescientist.com/tmp/combobox.JPG(The problem)!
Also I tried using update and had similar result.
-
To me, it sounds like you're abusing initializePage. What you are doing, can best be done from the constructor. You don't need data from the previous pages anyway.
Still, I find your way of working a bit strange. Why not make everything in the .ui file hidden to begin with?
If the above does not help, please provide a small, self-contained, compilable example so we can play around with it.
-
There are alternate ways I have implemented from utilzing initializePage (my initial post was based off my initial discovery of this problem).
So you may wonder why I posted at all if that is the case. Well, this problem does not only happen when I "abuse" initializePage-it happens whenever I hide all widgets using the above for loop code instead of explicitly hiding each individual element. In my case-if the user changes the initial option pull down, I hide everything on the form and then display the relevant form components. Even when doing this, the original drop down box will be drawn as in the screen shot.
I will try to put together a small code example to exhibit this same behavior.
-
Here is a small project I put together showing the problem. Select something in the combo box and you will see the issue: "Download Project in zip form":http://lakescientist.com/tmp/comboprob.zip
Interestingly enough, I ran into another problem while trying to put together this quick little sample. I tried setting up a QFrame with the .ui class. Next, I created a QGridLayout and added the QFrame to it and then set this as they QWizardPages's layout. When I do this, nothing gets shown on the wizard page. However, if I set the parent of the QFrame to the QWizardPage (and us NO layout), it does show the form, but the layout is spaced poorly. I included in the code the comments related to these problems-is there another way to go about this?
[EDIT: fixe download link, Volker]
-
The problem is with you hideEverything() method. It explicitly hides more than you want and afterwards too less widgets are shown again.
Try
@
void TestPage::hideEverything()
{
foreach(QWidget w, m_fDetailsFrame->findChildren<QWidget>()) {
qDebug() << "Hiding" << w;
w->hide();
}
}
@This are all the widgets hidden:
@
QComboBox(0xf5b700, name = "comboBox")
QComboBoxPrivateContainer(0x127df8e0)
QComboBoxListView(0x127dcba0)
QWidget(0x127dd6d0, name = "qt_scrollarea_viewport")
QWidget(0x127dc250, name = "qt_scrollarea_hcontainer")
QScrollBar(0x127b9f00)
QWidget(0x127dec90, name = "qt_scrollarea_vcontainer")
QScrollBar(0x127def70)
QComboBoxPrivateScroller(0x127e0190)
QComboBoxPrivateScroller(0x127e0320)
QLabel(0xf45330, name = "label")
@You re-show only two of them. The private sub widgets of the combo boxes are not shown again and thus remain hidden or in a weird state.
Additionally:
Your program crashes in the the destructors:
@
TestPage::~TestPage()
{
// ERROR: double delete
delete m_fDetailsFrame;
delete m_gLayout;
}// and
TestWizard::~TestWizard()
{
// ERROR: double delete
delete m_tp;
}
@You delete the members although they are automatically deleted via Qt's parent-child relationship of QObjects.
Additonally 2:
You have weird system to access the members of your UI. Finding them via findChild() is expensive and error prone. You can access them directly via the ui member object:@
m_fDetailsFrame->findChild<QWidget*>("comboBox")->show();
// is the same as
ui.comboBox->show();
@As an additional goodie you get the pointer to the right class (QComboBox) and call QComboBox' methods. With your method you only get the QWidget pointer and only access to QWidget's methods.
Additionally 3:
You create Widgets but do not put them into layouts. Your UI will look ugly at best and be (partly) inaccessible by the user at worst.