Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Presenting a tree model with a hierarchical set of comboboxes

Presenting a tree model with a hierarchical set of comboboxes

Scheduled Pinned Locked Moved General and Desktop
1 Posts 1 Posters 1.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    pbUser
    wrote on last edited by
    #1

    Task is to provide a view for a simple read-only tree model with the help of *QComboboxes *to let the user choose a specific sub item. As questions about this topic are poping up very often, but rarely being answered, here an simple example. It is open for discussion on how to improve it.

    It was a quite tedious task after having started with QDataWidgetMapper, trying to use QStyledItemDelegate and other possible implementations. If you know it, it is basically rather simple and even well documented in the section "Parents of items" in the help file qthelp://org.qt-project.qtwidgets.540/qtwidgets/model-view-programming.html. The trick is to use hierarchicalIndex = treeModel->index(lower, 0, hierarchicalIndex) for each level of hierachy.

    An alternative solution is described at "Implementing_QTreeView_in_QComboBox_using_Qt":http://developer.nokia.com/community/wiki/Implementing_QTreeView_in_QComboBox_using_Qt-_Part_2
    unfortunately having several drawbacks as for example not working on Mac and not resizing well.

    Here is the complete code for main.cpp:
    @
    #include <QObject>
    #include <QApplication>
    #include <QMainWindow>
    #include <QVBoxLayout>
    #include <QComboBox>
    #include <QStandardItemModel>
    #include <QTreeView>

    // macro to overcome overloading issue - I like it cryptic ;-)
    #define SIGTYPE(t, c, f) static_cast<void (c:: *)(t)>(&c::f)

    // some model parameters
    enum {
    Trees = 5,
    Branches = 4,
    Leaves = 3
    };

    // our widget main window
    class MainWindow : public QWidget {
    Q_OBJECT

    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private slots:
        void on_comboBox_1_currentIndexChanged(int arg1);       // select the tree
        void on_comboBox_2_currentIndexChanged(int arg1);       // select the branch
        void on_comboBox_3_currentIndexChanged(int);            // select the leaf
    
    private:
        QStandardItem *addItemAt(QStandardItem *parentItem, QString itemString);
        QModelIndex hierarchicalIndex(int highest, ...);
    private:
        QVBoxLayout *verticalLayout;
        QComboBox *comboBox_1;
        QComboBox *comboBox_2;
        QComboBox *comboBox_3;
        QTreeView *treeView;
    
        QStandardItemModel *treeModel;
        int tree, branch;
    

    };

    MainWindow::MainWindow(QWidget *parent): QWidget(parent) {
    tree = 0;
    branch = 0;
    // compose a simple layout using 3 QComboBoxes and a QTreeView vertically aligned
    verticalLayout= new QVBoxLayout(this);

    comboBox_1 = new QComboBox(this);
    comboBox_2 = new QComboBox(this);
    comboBox_3 = new QComboBox(this);
    treeView = new QTreeView(this);
    
    verticalLayout->addWidget(comboBox_1);
    verticalLayout->addWidget(comboBox_2);
    verticalLayout->addWidget(comboBox_3);
    verticalLayout->addWidget(treeView);
    
    setLayout(verticalLayout);
    
    treeModel = new QStandardItemModel(this);
    QList<QStandardItem*> itemlist;
    itemlist.append(treeModel->invisibleRootItem());
    itemlist.append(NULL);
    for (int tree = 0; tree < Trees; tree ++ ) {
        itemlist[1] = addItemAt(itemlist.at(0), QString("Tree %1").arg(tree));
        itemlist.append(NULL);
        for (int branch = 0; branch < Branches; branch++) {
            itemlist[2] = addItemAt(itemlist.at(1),
                QString("Branch %2 of tree %1").arg(tree).arg(branch)
            );
            itemlist.append(NULL);
            for (int leaf = 0; leaf < Leaves; leaf ++) {
                itemlist[3] = addItemAt(itemlist.at(2),
                    QString("Leaf %3 of tree %1 (%2)")
                        .arg(tree).arg(branch).arg(leaf)
                );
            }
        }
    }
    treeView->setModel(treeModel);
    
    connect(comboBox_1, SIGTYPE(int, QComboBox, currentIndexChanged),
            this, &MainWindow::on_comboBox_1_currentIndexChanged
    );
    connect(comboBox_2, SIGTYPE(int, QComboBox, currentIndexChanged),
            this, &MainWindow::on_comboBox_2_currentIndexChanged
    );
    connect(comboBox_3, SIGTYPE(int, QComboBox, currentIndexChanged),
            this, &MainWindow::on_comboBox_3_currentIndexChanged
    );
    
    // reverse order to avoid runtime errors
    comboBox_3->setModel(treeModel);
    comboBox_2->setModel(treeModel);
    comboBox_1->setModel(treeModel);
    

    }

    MainWindow::~MainWindow() {
    }

    QStandardItem *MainWindow::addItemAt(QStandardItem *parentItem, QString itemString) {
    QStandardItem *item = new QStandardItem(itemString);
    parentItem->appendRow(item);
    return item;
    }

    // scans indices of a tree model (highestLevel, nextLevel, ...-1)
    // a negative int signals end of the variadic list
    QModelIndex MainWindow::hierarchicalIndex(int highest, ...) {
    va_list arguments;
    va_start(arguments, highest);
    QModelIndex hierarchicalIndex = treeModel->index(highest, 0);
    for (;;) {
    int lower = va_arg(arguments, int);
    if (lower < 0) break;
    hierarchicalIndex = treeModel->index(lower, 0, hierarchicalIndex);
    }
    va_end(arguments);
    return hierarchicalIndex;
    }

    void MainWindow::on_comboBox_1_currentIndexChanged(int arg1) {
    tree = arg1;
    comboBox_2->setRootModelIndex(hierarchicalIndex(tree, -1));
    comboBox_2->setCurrentIndex(0); // strangely enough we need to update manually here
    }

    void MainWindow::on_comboBox_2_currentIndexChanged(int arg1) {
    branch = arg1;
    comboBox_3->setRootModelIndex(hierarchicalIndex(tree, branch, -1));
    comboBox_3->setCurrentIndex(0);
    }

    void MainWindow::on_comboBox_3_currentIndexChanged(int /arg1/) {
    // here very likely we do our job
    }

    int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
    }

    #include "main.moc"
    @

    and the corresponding qmake file HierarchicalComboBox.pro:
    @
    lessThan(QT_MAJOR_VERSION, 5): message("Requires Qt5")

    QT += core gui widgets

    TARGET = HierarchicalComboBox
    TEMPLATE = app

    SOURCES += main.cpp
    @

    1 Reply Last reply
    0

    • Login

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Get Qt Extensions
    • Unsolved