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

Problem mapping QSpinBox to current item row in QAbstractItemModel-based model.



  • Hello everybody,

    I would like to map QSpinBox value to the row number of the current item in a model tracked by QItemSelectionModel as follows:

    • When QItemSelectionModel changes current row, the QSpinBox value must change.

    • When QSpinBox value changes, QItemSelectionModel must change the current item.

    • The QSpinBox range must be [0, model.rowCount() - 1], and change when number of rows in the model changes.

    This is what I tried (based on Simple Widget Mapper example):

    MyModel model;
    QItemSelectionModel selection(&model);
    QSpinBox * spinBox = new QSpinBox();
    QDataWidgetMapper * mapper = new QDataWidgetMapper();
    
    mapper->setModel(&model);
    mapper->addMapping(spinBox, model.ID_COLUMN);
    
    connect(&selection, SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
    mapper, SLOT(setCurrentModelIndex(const QModelIndex &)));
    
    connect(mapper, SIGNAL(currentIndexChanged(const QModelIndex &)),
    &selection, SLOT(setCurrentIndex(const QModelIndex &)));
    

    The model reimplements data() and reports item's row for ID_COLUMN when the role is Qt::DisplayRole:

    class MyModel : public QAbstractItemModel
        {
        public:
    
            enum {ID_COLUMN = 0, ..., COLUMN_COUNT };
    
    	QVariant data(const QModelIndex & index, int role) const override;
    
           // ...  other methods
    };
    
    QVariant MyModel::data(const QModelIndex & index, int role) const
    {
        if((!indexIsValid(index)) || (index.column() != ID_COLUMN))
        {
            return QVariant();
        }
    
        switch(role)
        {
            case Qt::DisplayRole:
                return QVariant(QString::number(index.row()));
           // ...  other cases
        }
    
        return QVariant();
    }
    

    The above code does not work: the spin box range is incorrect, the spin box value changes have no effect on current item. When selection changes the current row, the spin box value is set to 0, not to the current row.

    Please suggest what might be missing. Perhaps additional roles in data() must be implemented? And how to tie the model's row index range to the spin box range?

    Thank you in advance!

    Roni.


  • Lifetime Qt Champion

    Hi,

    QDataWidgetMapper is for interacting with database a model content which is not what you are currently doing.

    I'd rather connect the QSpinBox valueChanged signal to a slot that will update the current selected index using the value provided by the spin box and then do the same for the currentIndexChanged and update the spin box from the slot.

    Hope it helps



  • Thank you, @SGaist. I originally wrote a solution like you suggested, and it worked. It also required changing the range of the spin box whenever the rows where inserted or deleted from the model.

    Than I saw the Simple Widget Mapper Example, and it seemed like a simpler solution. The text said:

    "The QDataWidgetMapper class allows information obtained from a model to be viewed and edited in a collection of widgets instead of in an item view."

    The example used QStandardItemModel, so it was not clear how a custom model should support this interface...


  • Lifetime Qt Champion

    Quote from the documentation: The QDataWidgetMapper class provides mapping between a section of a data model to widgets.

    The important part here is section of a data model. What you are manipulating here is not a section of a data model



  • Thank you for the explanation, @SGaist, I will go back to the original approach.


Log in to reply