Create QTableView within a parent QTableView row
-
I have tabular data which I would like to display as a nested QTableView below a row in a parent QTableView
Something similar to this:
Does an open source widget already exist which can do this, or can someone point me in the direction of how best to implement this?
-
I think you can use combination of span and setIndexWidget/ indexWidget(const QModelIndex & index)
to achieve what you want.
You could also try QicsTable (google it ). I think it went free and LGPL a few years ago.
I've seen it before it happened and it was very customizable and powerful control. -
use combination of span and setIndexWidget/ indexWidget(const QModelIndex & index)
I don't think this will work, as according to the documentation
This function should only be used to display static content within the visible area corresponding to an item of data. If you want to display custom dynamic content or implement a custom editor widget, subclass QItemDelegate instead.
I want to display a table which should be scrollable, editable, etc, which I take to be dynamic content not static content (unless my understanding of what this means is incorrect?)
try QicsTable
I have looked at this before, but I was put off by the fact that they created their own custom classes for pretty much the whole model/view architecture (eg: you have to use their own
QicsDataModel
rather than aQAbstractItemModel
etc.).I guess I thought it would be better to find something which fits into the Qt ecosystem a bit more harmoniously.
Maybe I was unfair and didn't give it enough of a chance?
TIA
-
In case of you have to decide to write it yourself: The proper way of doing this is to subclass
QItemDelegate
and override thecreateEditor()
method to use aQTableView
inside the row.
I have never done this with another table, just with comboboxes and spinboxes but with those it works quite well. There's an official example: https://doc.qt.io/qt-4.8/qt-itemviews-spinboxdelegate-example.html -
Display static content just means that you have to handle this widget update yourself because view is not going to do it.
It really does not matter if you use QItemDelegate or setIndexWidget
unless you can implement a nested item model when data of specific model index for 'parent' model comes from 'child' item model.
If you do not do data update this way we are talking about completely unrelated widgets with their own data management and have to handle them separately.QItemDelegate will do display it for you - it will create a widget for a single cell, resize it to proper size, place it at proper location.
But your "cell table view" will not be storing data in the parent table view model.
If you can make it to do so, then sure it is better to use delegate. But I doubt efficient implementation exist.
Assuming 'parent' item model will not be used to store data as a cell data at specific index, you do have completely unrelated widgets.It just happens that one of the widget is displayed in the certain area over another.
Simplest way to achieve this would be setIndexWidget. QItemDelegate can also be used. Who says it can't?Imagine you want to drink tea. I would rather take the cup. You take the towel, put it around cup, than take the towel.
Does it work? Yes
Is it required to drink from cup? No -
I have tabular data which I would like to display as a nested QTableView below a row in a parent QTableView
Judging from your screenshot you don't have tabular data at all, but rather a hierarchical model (such as used with QTreeView), so I suggest following that model and implementing a view (you can reuse the table or tree view with some tweaks) to show exactly what you want.
-
@kshegunov - that's just a screenshot I found online, in an attempt to illustrate what I'm looking for.
The idea would be to have a ▶ drop down indicator on the side, which when clicked on, would transition open to reveal the nested table beneath.
Just as you mentioned, I have created a
QTreeView
where I insert a fake row which serves as labels for each level in the hierarchy.There are several downsides to this approach:
- Each row is forced to be vertically aligned
- The standard column headers of the
QTreeView
are left blank, but visible, to allow column resizing and dragging to reposition. - You cannot resize a column by resizing its label, you have to resize the blank column headers at the top
- You cannot resize the column for level 1 of the tree without resizing the column for level 2, etc.
- You cannot reposition a column by dragging its label, you have to drag the blank column headers at the top
- You cannot drag a column to re-order it in one level of the tree without moving the lower-level columns.
Here you can see I've dragged the
"enabled"
column to the right, and it's pulled the 3rd level"size"
along with it, leaving a bunch of "blank" columns between"route"
and"size"
:Here you can see resizing the first column has completely hidden the
"side"
column in level 3:All of these issues I've mentioned would be solved by having each level in the tree represented as a separate table.
I would be happy to have to model my hierarchical data as several
QAbstractTableModels
if need be, but in my mind I believe it should be possible to have model data in a tree-like structure (alaQAbstractItemModel
), and present the data in the view as several nested tables. -
@skebanga
Hello,
I see. Your case is a bit involved it seems.I would be happy to have to model my hierarchical data as several QAbstractTableModels if need be, but in my mind I believe it should be possible to have model data in a tree-like structure (ala QAbstractItemModel), and present the data in the view as several nested tables.
You can use a proxy model to split your hierarchical model to as many table-like data layouts as you wish. However, displaying the data in a single view is the issue here.
Honestly, I can't think of any "good" way of achieving what you want without some heavy coding of the view (basically implementing your own tree view). One thing you could try is to put a delegate to show your model's leaf tabular data, but if you want the columns to be interactive (sortable, movable) this wouldn't provide a real solution.
-
@skebanga
Did you ever find a satisfactory solution to your problem? I recently solved a similar problem: Inserting a table into a tree view's cell. The approach I took should work for any complex widget. My approach was as follows:QStyledItemDelegate
.createEditor
returns a table view.setEditorData
populates / updates the table from model data, then calls.sizeHintChanged.emit(index)
, which should call.sizeHint
and.updateGeometry
(this part was really key for me)..setModelData
can be implemented if needed.sizeHint
must return the exact size required by the editor. This can be done in one of two methods:- use
QStyle.sizeFromContents
andoption.fontMetrics
. This is tedious, but works with enough patience. - save a reference of the editor to the internal pointer during
createEditor
, then useindex.internalPointer().editor.sizeHint()
- use
QAbstractItemVeiw
.openPersistentEditor(index)
will need to be called for any cell which you would like to display the delegate for.setDelegate()
(or similar) will need to be called to set the delegate
Some notes:
- Events specific to the delegate will need to be handled to provide the user with the ability to resize, etc.
- Setting many cells to have delegates can be expensive.
Some thoughts:
- To me, Qt falls short here... Not being able to use the widget framework to easily expand the capability of
QAbstractItemView
is disappointing, but this is probably a side effect of trying to keep views fast. QAbstractItemView.openPersistentEditor(index)
seems like a hack... but implementingQStyledItemDelegate.paint()
seems to defeat the purpose of using Qt in the first place when you need to do something as complex as rendering a table or tree view within tree or table view.- I'd like the Qt docs to include a comment about
openPersistentEditor
on theQStyledItemDelegate
page, that would have saved me a lot of time.
Hope this helps someone in the future.
-
Hi @publicname , thank you for the suggestions.
Can you post an example code to achive this?@skebanga did you resolve the problem... in which way?
Can you post some example too?Thank you.