Solved TableView with different delegates for its columns (QtQuick 2.15)
-
Hi,
I want to show a TableView that shows a few of its roles with CheckBoxes or Buttons, other roles as normal text delegates, other roles not at all.
I am using a c++ model derived from QAbstractTableModel (togethter with a QSortFilterProxyModel). Currently Qt 15.0.I am aware of the DelegateChooser , but the fact that it is in qt-labs lets me hesitate to use it.
I'd hate to lose TableView's goodies (e.g. resizing columns) by using a ListView and I should avoid QtQuick 1 for performance reasons (and being deprecated in the first place).
I have also contemplated just using a bunch of delegates inside an Item of which only one is visible at a time, depending on the role. But that'd be ugly and very memory-consuming.
What is a proper way to go? Is it safe to go for a "labs" feature?
BR
Sebastian -
@SeDi the 'classic' way to do this is to use a
Loader
in your delegate and use a switch or if-else if-... construct to instantiate the appropriate component. This is what I do in a similar situation involving aListView
- but I am stuck on 5.9.6 at the moment. I would useDelegateChooser
if I had the option, even if it is a labs component, as I could always switch back to my current approach if it stopped being supported or whatever. -
@Bob64 That sounds convincing - thank you!
-
@SeDi For posterity, here's my working solution:
delegate: Rectangle { width: childrenRect.width height: childrenRect.height Loader { sourceComponent: { switch(columnNo) { case 0: return firstDelegate; case 1: return secondDelegate; // ... default: return etcDelegate; } } } Component { id: firstDelegate Rectangle { width: childrenRect.width height: childrenRect.height color: "lightgray" Text { width: contentWidth + contentHeight height: contentHeight * 1.1 text: "first" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } } Component { id: secondDelegate Rectangle { width: childrenRect.width height: childrenRect.height color: "yellow" Text { width: contentWidth + contentHeight height: contentHeight * 1.1 text: "second" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } } Component { id: etcDelegate Rectangle { width: childrenRect.width height: childrenRect.height color: "lightgreen" Text { width: contentWidth + contentHeight height: contentHeight * 1.1 text: foodName verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } } }
To provide the columnNo role I had to do some work in my QAbstractTableModel.
The roles enum in the header:class LogTableModel : public QAbstractTableModel { enum Role { DisplayRole = Qt::DisplayRole, DecorationRole = Qt::DecorationRole, StatusTipRole = Qt::StatusTipRole, //whatever... ColumnNoRole = Qt::UserRole+5 // or wherever it suits ...
In data(...) I have implemented:
QVariant LogTableModel::data(const QModelIndex &index, int role) const { if (index.isValid()) { switch(role) { case DisplayRole: return QVariant::fromValue(m_columns.at(index.column())->at(index.row())); case ColumnNoRole: return QVariant::fromValue(index.column()); ...
roleNames() must also know it:
QHash<int, QByteArray> LogTableModel::roleNames() const { QHash<int, QByteArray> roles; roles[DisplayRole] = "display"; roles[ColumnNoRole] = "columnNo"; ...