Help! New entries to model not sorted when sorting on a column in QTableView



  • How do I make new rows automatically sorted when added to my model?

    By default this example program sorts on column 0, descending.
    Inserting new rows (by pressing button or by ctrl+n), will always add these in the bottom, not sorted.
    Why?

    main.cpp:
    @
    #include <QApplication>

    #include "window.h"

    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    Window mainWin;
    mainWin.show();
    return app.exec();
    }
    @

    window.h:
    @
    #ifndef WINDOW_H
    #define WINDOW_H

    #include <QMainWindow>

    QT_BEGIN_NAMESPACE
    class QTableView;
    class QSortFilterProxyModel;
    QT_END_NAMESPACE

    class Model;

    class Window : public QMainWindow
    {
    Q_OBJECT

    public:
    Window();

    private:
    void createToolBars();

    QTableView *_tableView;
    QSortFilterProxyModel *_sortFilterProxy;
    Model *_model;
    };

    #endif
    @

    window.cpp:
    @
    #include <QTableView>
    #include <QSortFilterProxyModel>
    #include <QAction>
    #include <QToolBar>

    #include "window.h"

    #include "model.h"

    Window::Window()
    {
    _tableView = new QTableView(this);
    _sortFilterProxy = new QSortFilterProxyModel();
    _model = new Model();

    _sortFilterProxy->setSourceModel(_model);
    _tableView->setModel(_sortFilterProxy);
    

    _tableView->setSortingEnabled(true);

    setCentralWidget(_tableView);

    QAction *insertAct = new QAction("Insert row", this);
    insertAct->setShortcuts(QKeySequence::New);
    connect(insertAct, SIGNAL(triggered()), _model, SLOT(insertRow()));
    QToolBar *toolBar = addToolBar(tr("Toolbar"));
    toolBar->addAction(insertAct);
    

    }
    @

    model.h:
    @
    #ifndef MODEL_H
    #define MODEL_H

    #include <QAbstractTableModel>

    class Model : public QAbstractTableModel
    {
    Q_OBJECT

    public:
    Model(QObject *parent = 0);

    QVariant data(const QModelIndex &index = QModelIndex(), int role = Qt::DisplayRole) const;
    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    int columnCount(const QModelIndex &parent = QModelIndex()) const;

    public slots:
    void insertRow();

    private:
    int _columns;
    int _rows;
    };

    #endif
    @

    model.cpp:
    @
    #include <QAbstractTableModel>

    #include "model.h"

    Model::Model(QObject *parent)
    : _rows(3), _columns(6), QAbstractTableModel(parent)
    { }

    QVariant Model::data(const QModelIndex &index, int role) const
    {
    if(!index.isValid())
    {
    return QVariant();
    }

    switch( role )
    {
    case Qt::DisplayRole:
        return (index.row()+1)*(index.column()+1);
    default:
        return QVariant();
    }
    

    }

    int Model::rowCount(const QModelIndex &parent) const
    {
    return _rows;
    }

    int Model::columnCount(const QModelIndex &parent) const
    {
    return _columns;
    }

    void Model::insertRow()
    {
    QAbstractItemModel::beginInsertRows(QModelIndex(), _rows, _rows);
    _rows++;
    QAbstractItemModel::endInsertRows();
    }
    @

    CMakeLists.txt:
    @
    cmake_minimum_required (VERSION 2.6)

    set(PROJECT_NAME "SortTest")
    project (${PROJECT_NAME})

    set(CMAKE_AUTOMOC ON)
    set(CMAKE_BUILD_TYPE Debug)
    set (CMAKE_C_FLAGS "-std=c99")

    #source files
    set(${PROJECT_NAME}_SOURCES
    main.cpp
    window.cpp
    model.cpp)

    #qt
    find_package(Qt4 REQUIRED)

    #project includes
    include_directories(${PROJECT_BINARY_DIR})

    #qt includes
    include(${QT_USE_FILE})
    include_directories(${QT_INCLUDE_DIR}
    ${QT_QTCORE_INCLUDE_DIR}
    ${QT_QTGUI_INCLUDE_DIR})

    #qt libraries
    set(${PROJECT_NAME}_QT_LIBRARIES
    ${QT_QTGUI_LIBRARY}
    ${QT_QTCORE_LIBRARY})

    #our program
    add_executable(${PROJECT_NAME}
    ${${PROJECT_NAME}_SOURCES})

    #linking
    target_link_libraries(${PROJECT_NAME}
    ${${PROJECT_NAME}_QT_LIBRARIES})

    @



  • Hi,
    You might want to add a reset or update of the view in your model (insertRow function). The insert/end rows is just there to 'protect' the view from reading data when you're updating you model data causing corrupt data or non existing data.



  • [quote author="Jeroentje@home" date="1411736618"]Hi,
    You might want to add a reset or update of the view in your model (insertRow function). The insert/end rows is just there to 'protect' the view from reading data when you're updating you model data causing corrupt data or non existing data.
    [/quote]

    But this would remove any selections and such in the view, it also will give a huge impact on preformance.

    Am I really needed to reset my complete model (think 100 000+ elements) because I want to inset a row or two? The framework can't really be this inflexible, can it?



  • Maybe the update (QModelIndex) will do the same (then only the inserted items are updated).
    No idea how the selection will respond to that though.
    Did you read the Model/View docs for that?



  • [quote author="Jeroentje@home" date="1411739082"]Maybe the update (QModelIndex) will do the same (then only the inserted items are updated).
    No idea how the selection will respond to that though.
    Did you read the Model/View docs for that?[/quote]

    If im not mistaken, we don't have a QModelIndex for these rows before they are inserted. I could ofcourse catch the rowsinserted signal, but that can hardly be the way this is supposed to work.

    I've read the docs but can't find my mistake, thats why I'm asking here.



  • emitting layoutChanged() when the row has been inserted gives me the expected behaviour. But my guess is that it is also a very heavy operation. If anyone finds another way to do it ill be very happy.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.