Qt World Summit: Register Today!

Howto visualize a tree-based QAbstractItemModel with a QTableView

  • Hello Qt folks out there,

    I'd like to visualize a tree-based model as shown in the simple tree model example ("link":http://qt-project.org/doc/qt-4.8/itemviews-simpletreemodel.html) in a QTableView as follows:

    Given the following tree
    or or
    /\ /\
    / \ / \
    I1 I2 I3 I4 I5

    The table should look like this:

    | | | Item 1
    | |v|_______
    | | | Item 2
    | ||______
    |^| | Item 3
    | | |_______
    | |v| Item 4
    | | |_______
    | | | Item 5

    As you can see, the tree shall be displayed from left to right, each node having a row-span over all its children.

    I've already stumbled over the fact that the QTableView does not respect the QAbstractItemModel::span() method for all the cell-spans. I wrote a updateCellSpan() method for that, which is triggered whenever the underlying model changes (dataChanged()).

    What I do not understand, is how to realize the QAbstractItemModel::index() method for my situation.

    Do you think it's possible to realize the functionality within the QAbstractItemModel::index() method directly or will it be necessary to use a ProxyModel?

    Any kind of hint appreciated!

  • then use QTreeView. QTreeView give you a table view with a column defined has "parents" tree content.

    Also, use of QStandardItemModel would be easier... This is an implementation of QAbstractItemModel, because you can not use QAbstrcatItemModel directly, but you have to use it for implement your own model... but also, you can implement QStandardItemModel too...

    also, for index:
    QStandardItemModel::index(int row, int column, QModelIndex parent)
    give you back a QModelIndex object who define the index of your data stored in your model at: the row and column number of your index parent.

    and then, if you find this index, you can have is content data.
    you can have it from an event selection in your view or from a code search, etc...

    you have maybe to look at some model/view tutorials (from QT or other). There is also some codes exemples provide by Qt, then you can look inside.

    But sure, what you need to do for this is:

    a QTreeView for the view

    a QStandardItemModel for the model (and maybe implement from this class)

  • I disagree with suggestion 2 above. I find using QStandardItemModel almost never easier than using my own model.

    I think what you are looking for, is indeed a modification of QTreeView. Would it not be easier to subclass QTreeView, and reimplementing its protected rendering functions for the tree and branches?

  • Thank you Jerome and Andre!

    It sounds indeed easier to use a QTreeView and reimplement its drawing and rendering mechanisms! Maybe I could replace the node/branch indicators with different widgets like a PushButton (the spanning cells shall be clickable later).

    Since I already have 90% of QAbstractItemModel implemented, I think that I will keep it and implement the last 10% (index()).

    P.S.: I'm sorry for the crappy display of the ASCII style tree and table. I used the '@' around it and the preview showed monospaced preformatted text, but somehow they use another font/css in the final version...

  • Please don't use widgets for that. That is not going to help you in the long run, and will hurt performance. You're better off doing your own rendering, perhaps using QStyle to render something that looks like a push button if you really want.

    Implementing models, tree models especially, is tricky to get right. A tip is to use "model test":http://doc.qt.io/qt-5/modelview.html#3-5-debugging-with-modeltest to bang on it and see where it breaks and needs improvement.

  • So you're saying instead of changing certain widgets within the QTreeView, I should rather realize my own rendering (i.e. how the complete outer widget is drawn)?

    Are there any examples on how to do that? I've never altered the rendering of a widget before...

  • No, I am saying that you should not use widgets to represent items in an item view. You should indeed do your own rendering inside the view.

    To do that, start out simple. Just use QPainter to draw a rect with a symbol in the center for instance.

  • I understand. Sounds like a good plan.

    One thing I stumbled over is that in a QTreeView, each node gets its own row. In my case, only nodes with no children (leafs) should reserve a row. Nodes having children (operators and/or) should have their graphical representation on the left (using the reimplementation of QTreeView::drawXXX() methods) we talked about.

    Is it possible to rearrange items?

  • Hmmm... good point. That is not going to be easy to do at all. Perhaps you could use a custom delegate that results in a 0 height row?

  • QStyledItemDelegate::sizeHint is only called once (initially) and reimplementing QStyledItemDelegate for leaf nodes only results in this: !http://www.frankmeffert.de/wp-content/uploads/qtreeview.png(link)!

Log in to reply