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. Choose how to implement rows hiding in QAbstractItemModel based model

Choose how to implement rows hiding in QAbstractItemModel based model

Scheduled Pinned Locked Moved Solved General and Desktop
modelview
3 Posts 2 Posters 5.7k 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.
  • Y Offline
    Y Offline
    YuriQ
    wrote on last edited by
    #1

    I want to create data model (based on QAbstractItemModel) with ability to hide certain items (actually to hide whole rows). I found two ways to implement it but can't choose which one is better.
    You can find sample code which illustrates this issue on the bottom of this post. You can just copy and paste it into empty widgets project's main.cpp file, run qmake then compile and it should work. You can choose implementation method using macrodefinition "HIDE_IMPLEMENTATION".

    • 1st method of implementation: use layoutAboutToBeChanged and layoutChanged signals to (not sure about it) repaint whole view
    • 2nd method of implementation: use beginInsertRows/endInsertRows to make rows appear and beginRemoveRows/endRemoveRows to hide rows

    Both methods seems to work fine but 1st method causes view (QTreeView) to work with bug. After hiding row QTreeView can return wrong current index (index of hidden item). You can use "Check current index" button (see sample code) to see this. 2nd method of implementation doesn't have this bug.

    So actually I have three questions:

    1. Did I implement 1st method right or wrong? I suspect I did it wrong because of error mentioned above.
    2. Which method is right? First or second? Both of them? Other method?
    3. Which method is better?

    Thanks in advance.

    Sample code (tested with Qt 5.6.1):

    #include <QApplication>
    #include <QWidget>
    #include <QVBoxLayout>
    #include <QToolBar>
    #include <QTreeView>
    #include <QHeaderView>
    #include <QLineEdit>
    
    
    
    // --------------------
    //
    // CHOOSE IMPLEMENTATION: 1 or 2
    // Implementation 1: emit layoutChanged
    // Implementation 2: insert/delete row
    #define HIDE_IMPLEMENTATION 1
    //
    // --------------------
    
    
    
    // Model contains only 3 items. 3rd item can be hidden.
    class SimpleModel: public QAbstractItemModel
    {
        Q_OBJECT
    public:
        SimpleModel(): QAbstractItemModel(Q_NULLPTR)
        {
            hide = false;
        }
        void toggleHide()
        {
    #if   HIDE_IMPLEMENTATION == 1
            emit layoutAboutToBeChanged();
            hide = !hide;
            emit layoutChanged();
    #elif HIDE_IMPLEMENTATION == 2
            hide = !hide;
            if (!hide)
            {
                beginInsertRows(QModelIndex(), 2, 2);
                endInsertRows();
            }
            else
            {
                beginRemoveRows(QModelIndex(), 2, 2);
                endRemoveRows();
            }
    #endif
        }
    protected:
        Q_INVOKABLE virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
        {
            if (!parent.isValid())
                return createIndex(row, column, Q_NULLPTR);
            else
                return QModelIndex();
        }
        Q_INVOKABLE virtual QModelIndex parent(const QModelIndex &child) const
        {
            Q_UNUSED(child);
            return QModelIndex();
        }
        Q_INVOKABLE virtual int rowCount(const QModelIndex &parent = QModelIndex()) const
        {
            if (!parent.isValid())
                return hide ? 2: 3;
            else
                return 0;
        }
        Q_INVOKABLE virtual int columnCount(const QModelIndex &parent = QModelIndex()) const
        {
            Q_UNUSED(parent);
            return 1;
        }
        Q_INVOKABLE virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
        {
            if (!index.isValid() || role != Qt::DisplayRole)
                return QVariant();
            if (!index.parent().isValid())
            {
                switch(index.row())
                {
                case 0:            return QString::number(1);
                case 1:            return QString::number(2);
                case 2: if (!hide) return QString::number(3);
                }
            }
            return QVariant();
        }
    private:
        bool hide;
    };
    
    class Widget: public QWidget
    {
        Q_OBJECT
    public:
        Widget(): QWidget(Q_NULLPTR)
        {
            QVBoxLayout* layout = new QVBoxLayout;
            setLayout(layout);
    
            QToolBar* toolbar = new QToolBar;
            layout->addWidget(toolbar);
            QAction* actionHide = toolbar->addAction("Toggle hide");
            connect(actionHide, &QAction::triggered, this, &Widget::hideAction);
            QAction* actionCheck = toolbar->addAction("Check current index");
            connect(actionCheck, &QAction::triggered, this, &Widget::checkAction);
    
            view = new QTreeView;
            layout->addWidget(view);
    
            model = new SimpleModel;
            view->setModel(model);
            view->header()->setHidden(true);
    
            message = new QLineEdit;
            layout->addWidget(message);
            message->setReadOnly(true);
    
        }
    private slots:
        void hideAction()
        {
            model->toggleHide();
        }
        void checkAction()
        {
            message->setText(
                        QString("Current index is (row=%1,column=%2)")
                        .arg(view->currentIndex().row())
                        .arg(view->currentIndex().column())
                        );
        }
    private:
        SimpleModel* model;
        QTreeView*   view;
        QLineEdit*   message;
    };
    
    #include "main.moc"
    
    void main(int argc, char** argv)
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
        a.exec();
    }
    
    
    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #2

      It's MUCH easier and faster to do it via QSortFilterProxyModel. Just reimplement filterAcceptsRow() to return false for the rows you want to hide.
      To force a refresh of the rows to hide you can call invalidateFilter()

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      Y 1 Reply Last reply
      2
      • VRoninV VRonin

        It's MUCH easier and faster to do it via QSortFilterProxyModel. Just reimplement filterAcceptsRow() to return false for the rows you want to hide.
        To force a refresh of the rows to hide you can call invalidateFilter()

        Y Offline
        Y Offline
        YuriQ
        wrote on last edited by
        #3

        @VRonin Seems like good solution. I'll definitely will try this. Thanks.

        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