[SOLVED] [QComboBox and Model/View] Associate PK and data in ComboBox



  • Hello Qt devs!

    This is a question related to my other post, found here. I now can show data in a categoryComboBox that depends on what is in groupComboBox. However, in the implementation, I have to add a +1. Let me show you:

    @ // Populate the group ComboBox
    groupModel = new QSqlRelationalTableModel(this, QSqlDatabase::database("*****"));
    groupModel->setTable(""TB_Groupe"");
    groupModel->setSort(groupModel->fieldIndex("GR_Nom"), Qt::AscendingOrder);
    groupModel->select();

    ui->MW_groupComboBox->setModel(groupModel);
    ui->MW_groupComboBox->setModelColumn(groupModel->fieldIndex("GR_Nom")); 
    

    // Populate category ComboBox according to Group ComboBox
    catModel = new QSqlRelationalTableModel(this, QSqlDatabase::database("*****"));
    catModel->setTable(""TB_Categorie"");
    catModel->setFilter(""CAT_IndexGroupe" = " % QString::number(ui->MW_groupComboBox->currentIndex()+1));
    catModel->setSort(catModel->fieldIndex("CAT_Nom"), Qt::AscendingOrder);
    catModel->select();

    ui->MW_catComboBox->setModel(catModel);
    ui->MW_catComboBox->setModelColumn(catModel->fieldIndex("CAT_Nom"));
    
    // Connects GroupComboBox and catComboBox to display appropriate categories
    connect(ui->MW_groupComboBox, SIGNAL(currentIndexChanged(int)),this, SLOT(RefreshCategory(int)));
    

    }

    /*********************************************
    Refreshes items in catComboBox according
    to what is in groupComboBox
    ********************************************/

    void MainWindow::RefreshCategory(int choice)
    {
    catModel->setFilter(""CAT_IndexGroupe" = " % QString::number(choice+1));
    catModel->select();

    ui->MW_catComboBox->setModel(catModel);
    ui->MW_catComboBox->setModelColumn(catModel->fieldIndex("CAT_Nom"));@
    

    Is there a way, in the backend, to associate the index of the groupComboBox to its PK in the DB? Thanks in advance! The choice+1 is an ugly, ad-hoc solution.



  • No problem
    @
    groupModel->data(groupModel->index(choice, groupModel->fieldIndex("YOUR_PK_FIELD")));
    @



  • Unfortunately, this does not work. The variable choice is defined only in the function RefreshCategory(int). I tried it, and I still need the choice+1 so that the data displays correctly.

    Is there a way to do this during the initialization of MW_groupComboBox? I mean, I thought it would automatic, since it is another column in the same model.



  • "QComboBox::currentIndex() ":http://doc.qt.nokia.com/4.7/qcombobox.html#currentIndex-prop should give you the row, fieldIndex the column. With those, you can create a QModelIndex and retrieve the data.

    The code should look someting like this:

    @
    int row = comboBox->currentIndex();
    int col = groupModel->fieldIndex("YOUR_PK_FIELD");
    QModelIndex index = groupModel->index(row, col);
    QVariant PKvalue = groupModel->data(index);
    @



  • Okay. With the created QModelIndex, could I use setRootModelIndex(QModelIndex) to set the index of the ComboBox arbitrarily?

    If I understood your code, it simply maps the ComboBox index to the PKs in the appropriate DB table?

    In short, with setRootModelIndex, I should be able to replicate something like this in my ComboBox

    @ Index Data
    20 Ent
    21 Rad
    22 CQq
    @

    if I have something like that in my DB, right?



  • An abstract item model can contain an tree of arbitrary level. setRootModelIndex just tells the list view in the combox which of the possible subtrees it should use, it is relevant for your actual problem for getting the right index (you must set the root index as third parameter for the groupModel->index() call).



  • This still doesn't work. I thought this was supposed to be easy.

    All I want is that the values

    @MW_groupComboBox->currentIndex();@

    reflect the PKs of the data in the DB. I have tried this:

    @ QModelIndex index = groupModel->createIndex(ui->MW_groupComboBox->currentIndex(),
    groupModel->fieldIndex("IndexGroupe"));

    ui->MW_groupComboBox->setRootModelIndex(index);@
    

    which doesn't work because ::createIndex(int, int, void *ptr =0) is protected.

    Volker, I have also tried your solution, but it does nothing. @MW_groupComboBox->currentIndex();@ still returns 0 through 2, when I want it to return 1 through 3 (well, that's in the DB, I don't want to specify this literally in the code).

    I feel like this shouldn't be so complicated...



  • Use
    @
    QModelIndex index = groupModel->index(ui->MW_groupComboBox->currentIndex(),
    groupModel->fieldIndex("IndexGroupe"));

    ui->MW_groupComboBox->setRootModelIndex(index);
    @



  • The combo box index is set internally. You cannot set it externally to an arbitrary value.

    If you populate the combo box with "QComboBox::addItem () ":http://doc.qt.nokia.com/4.7/qcombobox.html#addItem, you can add an arbitrary value as a "data role" for the respective item. You will have to iterate through your values manually then, you can not just set a model for the view.



  • Tried this. Now my ComboBox has only a single item. Can't I designate a column of my model to be the index of the ComboBox, or something similar?



  • [quote author="Joey Dumont" date="1309265662"]Tried this. Now my ComboBox has only a single item. Can't I designate a column of my model to be the index of the ComboBox, or something similar?[/quote]

    NO



  • [quote author="Joey Dumont" date="1309265662"]Tried this. Now my ComboBox has only a single item. Can't I designate a column of my model to be the index of the ComboBox, or something similar?[/quote]

    You can always do what Volker suggested above (That accesses another column with the current index). If you think that's too much code everytime you want to access the index, I'm afraid you'll have to subclass QComboBox

    [quote]
    @
    int row = comboBox->currentIndex();
    int col = groupModel->fieldIndex("YOUR_PK_FIELD");
    QModelIndex index = groupModel->index(row, col);
    QVariant PKvalue = groupModel->data(index);
    @
    [/quote]



  • [quote author="loladiro" date="1309266013"]
    You can always do what Volker suggested above (That accesses another column with the current index). If you think that's too much code everytime you want to access the index, I'm afraid you'll have to subclass QComboBox
    [/quote]

    That would just move that code into the subclass...



  • Very true, I only suggested it, because he didn't seem to want to go through the entire process every time he access the index.



  • Thanks, Volker. Now, that brings another question. I'm using something like that to fetch data from a DB.
    !https://lh6.googleusercontent.com/-Eyg_apku1S8/TgnRSDAAVnI/AAAAAAAAB34/YKLXdQehE84/s800/Screenshot-Contr%C3%B4les%20de%20qualit%C3%A9-1.jpg!

    The Category CC changes according to the Index of the GroupCC, as said earlier. Now, since I cannot set the Index of the ComboBox, the complexity of the query seems to increase rapidly (I need to account for the index of the group when binding a value to the category, etc...)

    By subclassing QComboBox, could I set the index myself, or is this really impossible? Thanks!



  • You get a signal when the group combo box changes. Get the data out of the group combo box' model (you have at least two choices pointed out here in the thread) and fill the model for the category's model accordingly. You'll have to re-select from the SQL anyways or put all the data in cache or the like which you access with the selected group's data.



  • Oh, the category CC already changes according to the index of the group CC (see the code I first posted).

    However, the five ComboBox uniquely identifies a set of data in the DB. Hence, I thought that if I could change the index of the ComboBox that I could directly use

    @query.prepare("...WHERE IndexAcc = :acc");
    query.bindValue(":acc", accComboBox->currentIndex();@

    because I thought that using something like

    @
    query.prepare("...WHERE name_acc = :acc");
    query.bindValue(":acc", accComboBox->currentText().toString());@

    was error-prone. Ain't it?



  • [quote author="loladiro" date="1309266013"]
    You can always do what Volker suggested above (That accesses another column with the current index). If you think that's too much code everytime you want to access the index, I'm afraid you'll have to subclass QComboBox
    [/quote]

    Okay, now I understand this part better. However, what I need is relational table, because for one value of the GroupComboBox index, I have several possible values for the Category ComboBox index.



  • A primary key is a primary key - a string value need not be unique.

    So you're doing it the wrong way anyways.

    query.bindValue() sets the value to the current value of that variable. It is not updated once the value changes! No matter how often you run the query, it always yields the same results!

    You must call bindValue again after the value has changed (i.e. after the combo box has a new current item) and re-run the query!



  • [quote author="Volker" date="1309267439"]A primary key is a primary key - a string value need not be unique.

    So you're doing it the wrong way anyways.

    query.bindValue() sets the value to the current value of that variable. It is not updated once the value changes! No matter how often you run the query, it always yields the same results!

    You must call bindValue again after the value has changed (i.e. after the combo box has a new current item) and re-run the query![/quote]

    Yes, I know all that. This sort of query will be connected to a button (now yet implemented) that will bind the values of whatever is in the ComboBoxes to a prepared SQL query and update the UI accordingly. However, from what you're telling me, I can access the PK associated with a certain item in the groupComboBox by using the currentIndex() of the groupComboBox and externally mapping it to its PK. That's fine.

    However, for each item in the groupComboBox, there are several items in the categoryComboBox. Now, since each time I change the index of groupComboBox, the contents of the categoryComboBox are changed, I cannot map the PK of the categoryComboBox to its index. Do you understand my problem?

    Because of this one-to-many relationship, it is somewhat difficult to implement something that would bind the right value in the SQL query. Now, and I want this to be the final question in this grudgingly long thread, can I set the indices of ComboBoxes if I subclass them?

    (To me, it seems like the most robust solution to fetch data from the DB.)

    Thanks, y'all!



  • Sorry, I don't understand where your mapping breaks. And I don't see a potential problem either.



  • Okay. I'll work a little bit more on this and come back later.

    Thanks for your tips!



  • It was easier that I thought. I wanted to filter data according to a foreign key. I had to fetch the PK of a table according to the value of the ComboBox.

    Here's how I did it:

    @
    catModel->setFilter(""CAT_IndexGroupe" = " % QString::number(
    groupModel->data(groupModel->index(ui->MW_groupComboBox->currentIndex(), groupModel->fieldIndex("IndexGroupe")), Qt::DisplayRole).toInt()));@

    Thanks everyone for your tips!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.