Programmatically adding a new row to a QAbstractListModel subclass - qt

Within an already-instantiated QAbstractListModel subclass, how do I add a row with data in each column, and have the associated QListView display the new row?
It seems that the only way to do it is to reimplement insertRow and setData within my model, and then hack them together in some sort of sequence within another function to add a row. Must I do this? Surely Qt must make it easier to add a new row.
Thanks much!
--Dany.

Just change your model's data storage, in between beginInsertRows() and endInsertRows().
For instance, let's say you have a flat list model and your model stores the data internally in a QVector m_data. You want to prepend the list, i.e. insert a row at position 0:
beginInsertRows( QModelIndex(), 0, 0 ); //notify views and proxy models that a line will be inserted
m_data.prepend( somedata ); // do the modification to the model data
endInsertRows(); //finish insertion, notify views/models

I'm afraid you have to do it that way. From the docs:
Models that provide interfaces to resizable list-like data structures can provide implementations of insertRows() and removeRows().

Related

How to change the order of QTableView rows by dragging and store the changes to the model?

I want to know how to change the order of QTableView rows by dragging, and store the order changes to the model?
I use QTableView as view and QSqlTableModel as model. I am using Qt 5.15.
I set:
ui->table_view->setSelectionMode(QAbstractItemView::SingleSelection);
ui->table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->table_view->setEditTriggers(QAbstractItemView::NoEditTriggers);
Methods I tried:
1.
ui->table_view->setSectionsMovable(true);
ui->table_view->setDragEnabled(true);
ui->table_view->setDragDropMode(QAbstractItemView::InternalMove);
ui->table_view->setAcceptDrops(true);
It doesn't take effect. The row cannot be dragged.
2.
ui->table_view->verticalHeader()->setSectionsMovable(true);
ui->table_view->verticalHeader()->setDragEnabled(true);
ui->table_view->verticalHeader()->setDragDropMode(QAbstractItemView::InternalMove);
ui->table_view->verticalHeader()->setAcceptDrops(true);
The row can be dragged by vertical header. But the order of changes will not affect the model.
As far as I know the QTableView does not call moveRows method of the model by itself. Instead drag and drop actions call *mimeData methods.
So, one option would be the following:
In your model you need to implement mimeData and dropMimeData functions. When you drag and drop a row the view will ask for mimeData() of the given row. If you are sure that you need only internal moves you can encode the selected row indices to QMimeData. Then in the dropMimeData() you decode the indices that were selected and use them to call your moveRows() implementation. Return false from this function to prevent removing of the moved out rows.
Another option can be to override the QTableView methods such as dropEvent() in a way, that it calls the model moveRows() method directly.

How do I Insert an item at top of QTreeView

In my app I'd like to insert an item at the top of a QTreeView.
What I have so far will insert an item just above the currently selected item. The code (nicked, I think, from the EditableTreeviewDemo):
QModelIndex index = this->selectionModel()->currentIndex();
QAbstractItemModel *model = this->model();
if (!model->insertRow(index.row(), index.parent()))
return;
I guess what I need is the index to the current first row? How do I get this?
As a side question, what happens to the current index when a row is inserted? Does it continue to point to the same item, or the same row?
Well first you have to know that insertRow is a function from QAbstractItemModel and it will call insertRows (with an s). This function must be redefined in your model subclass if you want to allow insertion of data in your model.
http://doc.qt.io/qt-5/qabstractitemmodel.html#insertRows
Also consider that any parent of a topmost index is a invalid QModelIndex. Then the call to do would be :
model->insertRow(0, QModelIndex());
And because this is the default value for the second parameter, simply call :
model->insertRow(0);
Then in your redefinition of insertRows simply check the validity of you parent index to ensure you news underlying data is created where you want it to be.
For you question, inserting data in the model won't affect the current and selected items.

Qt display not all fields from Model

I'm displaying the query from an QSqlModel in a table view. e.G.
SELECT id, name FROM person;
I don't want to display id in the view, however I need the id when the user clicks on a row in that view.
Is there a model in Qt, which allows me to display only specified columns in views but also providing access to invisible ones?
I used to do it by hiding the columns e.g.:
ui->myview->setColumnHidden( 0, true );
But probably there is a better solution.
Since the OP amended the question to exclude using QTableView the only alternative that would seem to work is the creation of a new class derived from QSortFilterProxyModel. One can override the filterAcceptsColumn method
Documentation on the class QSortFilterProxyModel can be found here
QSortFilterProxyModel can be used for sorting items, filtering out items, or both. The model transforms the structure of a source model by mapping the model indexes it supplies to new indexes, corresponding to different locations, for views to use. This approach allows a given source model to be restructured as far as views are concerned without requiring any transformations on the underlying data, and without duplicating the data in memory.
You'd also have to override MapToSource and SourceToMap . There is a good example of usage in this StackOverflow's answer

data vs listData in Flex itemRenderer

I was wondering what the difference between data and listData in itemRenderers in flex. I have worked with data in all of my itemRenderers.
Basically I want to know when to use which, where each gets set and if I can use them together?
Note that I am asking from a Flex3 point of view.
data is the data that the renderer should display. Use it to work with the original data currently assigned to the renderer.
listData is an additional object to provide you with information about the role of the renderer in the list (rowIndex, columnIndex, list component, uid, ...). Use it to perform some UI related operations such as formatting the first row differently or rows alternating depending on their vertical index, calling the list view component, etc.
Each item of your dataProvider collection is passed to data variable. You entirely define, what is passed to data by defining dataProvider content.
Information about the cell of datagrid/list (such as row/column index, label) is passed to listData (see BaseListData). To use this variable your itemrenderer should implement IDropInListItemRenderer interface.
See details about listData here. The main point is:
The list classes will pass more information to the renderer so that it
can determine which field to use at run-time.
So listData is for advanced usage for more complicated item renderers.
See this:
http://livedocs.adobe.com/flex/3/html/help.html?content=cellrenderer_4.html
And this:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/listClasses/IDropInListItemRenderer.html

QTableView problems with row

Hello guys i new to QT and i am doing Qtableview to add information in 3 columns to infinite row like
|--1--|--2--|--3--|
|--1--|--2--|--3--|
|--1--|--2--|--3--|
this is how i want to insert/append row but this is how i am getting after insert/append row functions.
|--1--|--2--|--3--|
|-----|-----|-----||--1--|--2--|--3--|
|-----|-----|-----||-----|-----|-----||--1--|--2--|--3--|
i am getting empty gaps and increased column count
i am using QStandardItemmodel for model this is code that creates the model item
void tableview::add_tableview() //this is used to add data to tableview
{
//to get data from line edit in add window
QStandardItem *item_1 = new QStandardItem(QString(enter1_edit->text()));
QStandardItem *item_2 = new QStandardItem(QString(enter2_edit->text()));
QStandardItem *item_3 = new QStandardItem(QString(enter3_edit->text()));
list << item_1 << item_2 << item_3;
model->appendRow(list);
//to set the model
main_tableview->setModel(model);
}
The values in the rows are added using qlineedit enter1_edit,enter2_edit & enter3_edit(its in other function/method)
main_tableview is the object of qtableview
Thanks for helping me!
Ding Ding Ding, I have it.
I tried to reproduce your problem without success unil I tried something...suboptimal :).
Is your list by any chance a global entity? If yes (and I assume it is) you keep adding items to it.
First time you call add_tableview() all is good, list is empty, gets three QStandardItem pointers added and is used to append a row with those three items. So far so god.
You call add_tableview() again, now you create another three QStandardItems and APPEND them to the list (which still contains the three from the last call). Invoking appendRow() actually tries to insert six items, from which the first three allready exist in the model. And as you know you mustn't add the same item pointer to a model twice. Thankfully Qt doesn't crash but inserts three empty columns for the item pointers allready in it.
Solution: At the end of your add_tableview() method call list.clear() or use a local variable for the list. The overhead should be minimal.
Best regards
D

Resources