PDA

View Full Version : QComboBox setCurrentIndex doesn't work



trallallero
7th November 2011, 11:53
In the constructor of the QMainWindow I do the following:



int index;
m_Workspace.getValue<int>("workspace.mainWindow.projectsSort", index, 0);
ui->cmbProjectSort->setCurrentIndex(index);


When I start the program I can see for a second that the index is correct (actually 2), but then it's replaced with index 0 even though, in the designer, I set the current index to -1.

The problem is that I cannot find a signal that is thrown after the constructor in order to properly initialize the main window.

How can I solve the problem ?
I could put a button "Initialize" but the window is designed to be "ready to go" when started.

In the constructor of the QMainWindow I do the following:



int index;
m_Workspace.getValue<int>("workspace.mainWindow.projectsSort", index, 0);
ui->cmbProjectSort->setCurrentIndex(index);


When I start the program I can see for a second that the index is correct (actually 2), but then it's replaced with index 0 even though, in the designer, I set the current index to -1.

The problem is that I cannot find a signal that is thrown after the constructor in order to properly initialize the main window.

How can I solve the problem ?
I could put a button "Initialize" but the window is designed to be "ready to go" when started.

Added after 36 minutes:

I've found the problem.

The combo box items are not set in the "setupUi" function but in the "retranslateUi" one.


void retranslateUi(QMainWindow *MainWindow)
{
...
cmbProjectSort->clear();
cmbProjectSort->insertItems(0, QStringList()
<< QApplication::translate("MainWindow", "Hostname", 0, QApplication::UnicodeUTF8)
<< QApplication::translate("MainWindow", "Name", 0, QApplication::UnicodeUTF8)
<< QApplication::translate("MainWindow", "Description", 0, QApplication::UnicodeUTF8)
<< QApplication::translate("MainWindow", "Id", 0, QApplication::UnicodeUTF8)
);
...
}


But even if I set the index after the call to ui->retranslateUi(this) in the changeEvent, it doesn't work.

ChrisW67
8th November 2011, 02:07
You cannot set the index of the combo box until after it is populated, which occurs in the setupUi() function call that should be near the top of your constructor.

We have no idea what your getValue() template function does with index but clearly it is not what you are expecting. Where are you seeing an index value of 2? From the code we can see index is not initialised, and possibly not set. Is index passed by non-const reference? Is the 0 parameter a default value?

trallallero
8th November 2011, 07:32
Ok, I've put some log to show what happens:


int index;
m_Workspace.getValue<int>("workspace.mainWindow.projectsSort", index, 0);
ui->cmbProjectSort->setCurrentIndex(index);
std::cout << "project index: " << ui->cmbProjectSort->currentIndex() << std::endl;

m_Workspace.getValue<int>("workspace.mainWindow.clientsSort", index, 0);
ui->cmbClientsSort->setCurrentIndex(index);
std::cout << "client index: " << ui->cmbClientsSort->currentIndex() << std::endl;

The combo box items are fixed so inserted with the designer.
The code is inside the constructor and when I start the program I see the log:


project index: 2
client index: 3


But, after the constructor, the combo indexes are not 2 and 3. As I wrote, they are 0 and 0.

I've solved the problem putting the same code in the changeEvent function as the combo boxes are filled in the retranslateUi function.
What I was doing wrong, was saving the index of the combo boxes in the currentIndexChanged function so, when qt changed to index to 0, I was saving it to the property tree. Now I save it only when the user presses "Save workspace".

So, from my side it's fixed, everything works now. The only "bad" thing is that this stuff doesn't seem to be documented. I also thought that the combos were filled in setupUi but, in this case, it's not true.

Thanks.


PS:
getValue is just a template function that uses boost property tree:


template<class T>
bool getValue(const std::string key, T& value, const T& defaultValue)
{
try
{
value = mPropertyTree.get<T>(key);
return true;
}
catch(...)
{
std::cout << "getting value of key <" << key << "> failed! Will use default value <" << defaultValue << ">" << std::endl;
value = defaultValue;
return false;
}
};

ChrisW67
8th November 2011, 08:51
OK, in your constructor you set valid indexes on the populated combo boxes and the values are set correctly.


But, after the constructor, the combo indexes are not 2 and 3. As I wrote, they are 0 and 0.

At some indeterminate point in time later they have changed. You still haven't identified what is changing them.



I've solved the problem putting the same code in the changeEvent function as the combo boxes are filled in the retranslateUi function.
What I was doing wrong, was saving the index of the combo boxes in the currentIndexChanged function so, when qt changed to index to 0, I was saving it to the property tree. Now I save it only when the user presses "Save workspace".

So, from my side it's fixed, everything works now. The only "bad" thing is that this stuff doesn't seem to be documented.
You are correct that the generated retranslateUi() function populates the combo boxes. The retranslateUi() function is called by the setupUi() function that your constructor calls. It must have been called before you set the indexes in your constructor or the currentIndex() values would have been -1. The current index of the combo box is set in setupUi() to the value in the Designer properties for the combo box (zero is the default). This all happens before any automatic connection to signals from the widgets are made so currentIndexChanged() may be emitted but is not connected to anything.

Edit: Oddly, manually connected signals from Designer are connected before the index is set, so you could get into strife. Solutions: do these connections manually in the constructor after setupUi(), or use the automatic connection by name.


AFAICT you still have not identified what reset your index to zero after you currentIndexChanged() handler was connected.
What "this stuff" are you referring to?


I also thought that the combos were filled in setupUi but, in this case, it's not true.
I don't know where you get that idea from, but you are wrong. Here is the generated code from a simple main window with a combo box (emphasis mine):



QT_BEGIN_NAMESPACE

class Ui_MainWindow
{
public:
QWidget *centralWidget;
QVBoxLayout *verticalLayout;
QComboBox *comboBox;
QMenuBar *menuBar;
QToolBar *mainToolBar;
QStatusBar *statusBar;

void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(400, 300);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
verticalLayout = new QVBoxLayout(centralWidget);
verticalLayout->setSpacing(6);
verticalLayout->setContentsMargins(11, 11, 11, 11);
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
comboBox = new QComboBox(centralWidget);
comboBox->setObjectName(QString::fromUtf8("comboBox"));

verticalLayout->addWidget(comboBox);

MainWindow->setCentralWidget(centralWidget);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
menuBar->setGeometry(QRect(0, 0, 400, 20));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
MainWindow->setStatusBar(statusBar);

retranslateUi(MainWindow); // <<<<<<<<<<<<<<<<<<<<<<<<< setupUi() calls retranslateUi();

comboBox->setCurrentIndex(0); // <<<<<<<<<<<<<<<<<<<<<<< then sets the starting index value you specified in Designer


QMetaObject::connectSlotsByName(MainWindow); // <<<<<< connections made now
} // setupUi

void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0, QApplication::UnicodeUTF8));
comboBox->clear();
comboBox->insertItems(0, QStringList()
<< QApplication::translate("MainWindow", "A", 0, QApplication::UnicodeUTF8)
<< QApplication::translate("MainWindow", "B", 0, QApplication::UnicodeUTF8)
<< QApplication::translate("MainWindow", "C", 0, QApplication::UnicodeUTF8)
<< QApplication::translate("MainWindow", "D", 0, QApplication::UnicodeUTF8)
);
} // retranslateUi

};

trallallero
8th November 2011, 09:37
OK, you're right. I've seen the ui_MainWindow.h file and it's exactly as you wrote.

What I've also seen is that the currentIndex is set to 0 when insertItems is called (this is part of "the stuff" that is not documented).
So what I think is that the changeEvent function with event->type() == QEvent::LanguageChange is executed after the constructor and the ui->retranslateUi(this), inserting the items in the combo boxes, sets the currentIndex to 0.

I call m_Translator.load(...) in the constructor to load the language got from the xml file, that's why the changeEvent function is executed.

Well thanks, now everything is clear.