Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Presetting a combobox to one of its tree view popup entry



  • Hi,
    I have a combobox with a popup treeview as shown below.
    b289155e-d0ce-4f3c-a718-c96b49586a52-image.png
    I would like to set the combobox current item programmaticaly to one of the child items.

    How can I achieve that ?



  • Finally I found a way to make it work.
    First I have created a subclass for QCombobox called TreeBox.

    TreeBox::TreeBox(QWidget *parent) : QComboBox(parent)
    {
        m_tree = new QTreeView;
        this->setView(m_tree);
    
        m_tree->setHeaderHidden(true);
        m_tree->viewport()->installEventFilter(this);
    }
    

    Then in the class which is using the TreeBox I have declared a private property to keep track of the items added to the list view.

    QVector<QStandardItem*> m_itemList;
    QStandardItemModel m_modelForTree;
    

    In the ui I have added a ComboBox and promoted it to TreeBox.
    Then I populate the tree model as follows and set the model to the ComboBox.

    QStandardItem *root = m_modelForTree.invisibleRootItem();
        QStandardItem *item;
        for (int i=0; i<10; i++){
            item = new QStandardItem(QString("item %0").arg(i));
            m_itemList.append(item);
            root->appendRow(item);
            for(int j=0; j<5; j++){
                item->setChild(j, 0, new QStandardItem(QString("item %0%1").arg(i).arg(j)));
            }
        }
    
        ui->comboBox->setModel(&m_modelForTree);
    

    As an example I choose "item 43" to be set at the startup of this test program.

    QString text = "item 43";
    

    Then I loop through the QStandardListItems in m_itemList to find the QModelIndex of the item I want to preset.

    bool textFound=false;
        QModelIndex modelIndex;
        for (int i=0; i<m_itemList.count(); i++){
            for (int j=0; j<m_itemList[i]->rowCount(); j++){
                modelIndex = m_modelForTree.indexFromItem(m_itemList[i]->child(j));
                if (modelIndex.data(Qt::DisplayRole).toString()==text){
                    textFound = true;
                    break;
                }
            }
            if (textFound)
                break;
        }
    

    Now I can set the item as follows

    ui->comboBox->setRootModelIndex(modelIndex.parent());
    ui->comboBox->setCurrentIndex(modelIndex.row());
    

    Unfortunately this restricts also the items displayed in the popup of the combobox to those of the current parent item.
    9807f986-bb64-4ecd-87ad-c875361c6d58-image.png

    To avoid this behavior I have to reset to the first QStandardItem in the list

        modelIndex = m_modelForTree.indexFromItem(m_itemList[0]);
        ui->comboBox->setRootModelIndex(modelIndex.parent());
    

    Now I get the behaviour I was looking for
    8e08d83e-4626-467b-9119-a6da38c7b365-image.png

    Maybe there are simpler ways to do it and I would be glad if someone could come up with one.
    But for the time being I just wanted to share this solution.



  • @Bert59

    Check what index they have and then just setCurrentIndex(idx).



  • But how do I get the index of an item? If I just now the name, for example "item 24", how can I get the index for it?



  • @Bert59
    You must search the tree view items for the one matching item 24. You could try QComboBox::findText() to do that, I don't know if it works for you but worth a try.

    If you say all you want to do is set the current item, have you tried simply yourComboBox->setCurrentText("item 24")? I don't know whether that will work with a tree view, and selecting a sub-item, but again worth a try?



  • Thank you for the feedback.
    Unfortunately both methods only work for the root items (item 2 for example) but not for the child items like "item 24".



  • @Bert59
    Yes I did wonder if that might be the case.

    That only means you cannot use the two quick ...text() methods. Revert to what I said first (which is what ...text() methods would have to do internally anyway): search the tree view/model for the item you want. I assume you have tested that setCurrentIndex(7) does indeed select item 24 correctly, so you know all you have to do is correctly find that item 24 is at item #7 and it will then select correctly? (If it does not do that, and actually selects item 7 which is presumably scrolled down at the bottom, then you have a problem....)



  • setCurrentIndex(7) selects in fact "item 7".

    I think I should use ui->comboBox->view()->setCurrentIndex(index);

    But in this method index is a QModelIndex and so far I couldn't find a way to get the QModelIndex from the items name.



  • @Bert59 said in Presetting a combobox to one of its tree view popup entry:

    setCurrentIndex(7) selects in fact "item 7".

    Then you should stop and realise this is telling you your whole idea is flawed/does not work.

    A QComboBox works from a single, integer index, not a QModelIndex. Your finding shows that no value for QComboBox::setCurrentIndex() is going to select a non-top-level item/node such as item 24. Rather, it only works on the top-level items, and that's all it will allow you to select/return as selected. Even if you find item 24's QModelIndex in the model, how will that help you select/return it in a combo box?

    QCombBox only works for a "flat" list of items. Not some tree view hierarchy. Where did you get the idea from that you could make it work with a tree view? Have you found any code example anywhere which says that can be done?



  • Finally I found a way to make it work.
    First I have created a subclass for QCombobox called TreeBox.

    TreeBox::TreeBox(QWidget *parent) : QComboBox(parent)
    {
        m_tree = new QTreeView;
        this->setView(m_tree);
    
        m_tree->setHeaderHidden(true);
        m_tree->viewport()->installEventFilter(this);
    }
    

    Then in the class which is using the TreeBox I have declared a private property to keep track of the items added to the list view.

    QVector<QStandardItem*> m_itemList;
    QStandardItemModel m_modelForTree;
    

    In the ui I have added a ComboBox and promoted it to TreeBox.
    Then I populate the tree model as follows and set the model to the ComboBox.

    QStandardItem *root = m_modelForTree.invisibleRootItem();
        QStandardItem *item;
        for (int i=0; i<10; i++){
            item = new QStandardItem(QString("item %0").arg(i));
            m_itemList.append(item);
            root->appendRow(item);
            for(int j=0; j<5; j++){
                item->setChild(j, 0, new QStandardItem(QString("item %0%1").arg(i).arg(j)));
            }
        }
    
        ui->comboBox->setModel(&m_modelForTree);
    

    As an example I choose "item 43" to be set at the startup of this test program.

    QString text = "item 43";
    

    Then I loop through the QStandardListItems in m_itemList to find the QModelIndex of the item I want to preset.

    bool textFound=false;
        QModelIndex modelIndex;
        for (int i=0; i<m_itemList.count(); i++){
            for (int j=0; j<m_itemList[i]->rowCount(); j++){
                modelIndex = m_modelForTree.indexFromItem(m_itemList[i]->child(j));
                if (modelIndex.data(Qt::DisplayRole).toString()==text){
                    textFound = true;
                    break;
                }
            }
            if (textFound)
                break;
        }
    

    Now I can set the item as follows

    ui->comboBox->setRootModelIndex(modelIndex.parent());
    ui->comboBox->setCurrentIndex(modelIndex.row());
    

    Unfortunately this restricts also the items displayed in the popup of the combobox to those of the current parent item.
    9807f986-bb64-4ecd-87ad-c875361c6d58-image.png

    To avoid this behavior I have to reset to the first QStandardItem in the list

        modelIndex = m_modelForTree.indexFromItem(m_itemList[0]);
        ui->comboBox->setRootModelIndex(modelIndex.parent());
    

    Now I get the behaviour I was looking for
    8e08d83e-4626-467b-9119-a6da38c7b365-image.png

    Maybe there are simpler ways to do it and I would be glad if someone could come up with one.
    But for the time being I just wanted to share this solution.


Log in to reply