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

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 a ListView - but I am stuck on 5.9.6 at the moment. I would use DelegateChooser 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";
    ...
    

Log in to reply