tags:

views:

509

answers:

3

This is a Qt-specific question.

It's convenient to be able to add new data to a table by typing content into a blank row at the bottom of a table. When the data is committed, a new blank row is added to the table.

Has anyone found a way of implementing this in a generic way, that fits into Qt's model-view programming architecture? My closest attempt involves creating a proxy model, such that the rowCount() returned from the model is always one greater than the source model.

QAbstractTableModel* sourceModel ; // Data is stored here
QBlankRowModel* model ; // Proxy model that adds one to rowCount()
QTableView* view ; // View
view->setModel( model ) ;
model->setSourceModel( sourceModel ) ;

Any suggestions are welcome. Thanks.

A: 

Sounds like a reasonable solution, as it should work for any model that you might want as the actual table model, ie. SqlTableModel or just a plain one. As long as you add the row when the user is done editing and take care not to add the row when the user did not add any data.

Harald Scheirich
+1  A: 

Your solutions seems a little hackish. Your problem is not only additions, it's also editions. What happens when your user edits a row, the typed data goes directly to your "data layer" even before the user commits his edition?

A better solution would be to restrict the role of your sourceModel. Rather than being a "direct" representation of your data, it should be a "buffered" representation of it. When the sourceModel is created, you make a copy of your data in some kind of Row() instances. The sourceModel, having its own copy of the data can then freely play around, perform editions and additions, and only commit the data to your model layer when the user commits his edits.

If you want a PyQt example of such a table, you can look at the source of a project of mine:

http://hg.hardcoded.net/moneyguru/

You might have to dig around to actually find the "buffering" logic because it's not in the PyQt code itself, but rather the "cross-platform" part of the code:

http://hg.hardcoded.net/moneyguru/src/tip/core/gui/table.py

This logic is then used in my QAbstractItemModel subclass:

http://hg.hardcoded.net/moneyguru/src/tip/qt/controller/table.py

Virgil Dupras
+2  A: 

From a design-perspective, this should be part of the view, not the model. Therefore, I suggest implementing a view with the functionality and leave the model unchanged. KOffice Kexi does just this with kexitableview (screenshot, documentation). Maybe you want to use some of their code.

BTW, you might still be able to use your hack and combine it with my suggestion by putting it inside a new table view implementation YourTableView:

  1. QBlankRowModel re-implements the QAbstractTableModel interface. It returns sourceModel.rowCount()+1 as the QBlankRowModel::rowCount(). It returns a QVariant() if the n+1th row is requested in QBlankRowModel::data(). All the rest within QBlankRowModel is forwarded to the sourceModel (with editing the n+1th row in QBlankRowModel buffered and replaced with inserting into the sourceModel when finished).

  2. The new YourTableView inherits from QTableView and wraps the sourceModel within YourTableView::setModel(), calling QTableView::setModel(QBlankRowModel(sourceModel)).

Thereby, your hack is localized at one point.

stephan