setData() versus insertRows() Qt ModelView - c++

In Qt model-view how is setData different than insertRows. I understand that insertRows is just for new rows addition, whereas setData can modify existing data as well. Can setData also be used to insert additional rows in a table or list based model. I am new to Qt, so please pardon if the question is too basic.

No, setData() is to be used to change existing data, or more precisely to manipulate data for an index that exists. You cannot add rows using this method.

setData puts new data into your buffer, insertRows will add new rows into the indexed location of your buffer, increasing the total amount of data you now have. If you are trying to only overwrite data at certain locations I suggest using replace.

Related

Wxsmith how to make WxGrid infinite rows

I want to keep writing data into WxGrid, but i need to set the rows for WxGrid. I've searched some way but the answer that i get is to use Wx.GridTableBase which is for WxPython.
Is there any way to make WxGrid rows infinite?
I'm using codeblocks c++ with WxSmith.
If you're going to have a lot of data in your grid, it is much better (i.e. more efficient) to define your own grid table, i.e. a class deriving from wxGridTableBase, and store your data there.
Okay so i just need to use AppendRows() everytime i need to add rows. it's on the manuals https://docs.wxwidgets.org/3.0/classwx_grid.html

How to update a QStringListModel?

I have the following code:
QStringListModel* m=new QStringListModel(gc.get_lista_file());
ui->lista_immagini_listView->setModel(m);
where gc.get_lista_file() returns a QStringList object and lista_immagini_listView is a QListView.
I need to update my lista_immagini_listView adding a string when I press a button, but if I add my new string to my QStringList object it doesn't update my model (I read the QStringList is passed by copy, so it isn't connected to the model). So, I have to update my QStringListModel but in this way I have to update 2 object (QStringList and QStringListModel) and doesn't seem a good practice.
What is the best way (if exists) to resolve it?
QStringListModel does not allow you to simply add a string (sadly). Simply updating the QStringList does not work because the model stores a copy of the list.
There are basically two ways to get the desired behavior:
1. Reset:
This is the simple way. You just take the list from the model, add the string and reassign it:
QStringList list = m->stringList();
list.append("someString");
m->setStringList(list);
This method does work, but has one big disadvantage: The view will be reset. Any selections the user may have, sorting or the scroll-position will be lost, because the model gets reset.
2. Using the Model:
The second approach is the proper way of doing, but requires some more work. In this you use the functions of QAbstractItemModel to first add a row, and then changing it's data:
if(m->insertRow(m->rowCount())) {
QModelIndex index = m->index(m->rowCount() - 1, 0);
m->setData(index, "someString");
}
This one does properly update the view and keeps it's state. However, this one gets more complicated if you want to insert multiple rows, or remove/move them.
My recommendation: Use the 2. Method, because the user experience is much better. Even if you use the list in multiple places, you can get the list after inserting the row using m->stringList().
You need to only use the string list provided by the QStringListModel - don't keep a separate copy, use QStringListModel::stringList() for reading only. To modify the list, use the model's methods: insertRows, removeRows and setData instead of using QStringList methods.

Qt QTreeWidgetItem text contents vs widget item vs data

upon construction of QTreeWidgetItem you can pass a list of strings, so when you insert it in a table(QTreeWidget), you get the strings listed on a row. However, from the methods of the table you can also call setItemWidget and set a text widget or any sort of widget to be in that row, but it seems incompatible with having a string list, since the widget is drawn over the strings. There is also a setData method for the QTreeWidgetItem, which sets some data that can be retreived, but isn't visible to the user. Is there a cookie-cutter way of properly using all three data storage methods? Are they even compatible or must I stick to only one?
The Constructor of QTreeWidgetItem is convenient to immediately list the desired content.
When inserting a custom widget in a cell, you need to change its autoFillBackgroundproperty to true, so that it is not transparent. See the QTreewidget::setItemWidget description:
The given widget's autoFillBackground property must be set to true,
otherwise the widget's background will be transparent, showing both
the model data and the tree widget item.
QTreeWidgetItem::setData can be used when already having an item and you want to change one of its contents.
Of course you can combine any of these methods, but it is hard to say, which approach is best without knowing your use case. Just one more hint: If you just need a plain stupid representation of data that does not change, using QTreeWidget is fine. But if your displayed data can change, e.g. objects get deleted, added, changed in various locations of your code, a QTreeView with a custom data model might be a better choice.

Re-implement sorting for QTableWidget?

Is there a way to re-implement the sorting function for QTableWidget? I use QComboBox (multicheck) in the first row of my table to filter the data. I also want be able to sort the data in the table, but I want my widget to stay in the first row no matter how I sort the data.
I know that I can re-implement the < operator and set a value as well as a widget in a cell, but that does of course not help me.

Supporting multi-add/delete (and undo/redo) with a QAbstractItemModel (C++)

Greetings,
I've been writing some nasty code to support the undo/redo of deletion of an arbitrary set of objects from my model. I feel like I'm going about this correctly, as all the other mutators (adding/copy-pasting) are subsets of this functionality.
The code is nastier than it needs to me, mostly because the only way to mutate the model involves calling beginInsertRows/beginRemoveRows and removing the rows in a range (just doing 1 row at a time, no need to optimize "neighbors" into a single call yet)
The problem with beginInsertRows/beginRemoveRows is that removal of a row could affect another QModelIndex (say, one cached in a list). For instance:
ParentObj
->ChildObj1
->ChildObj2
->ChildObj3
Say I select ChildObj1 and ChildObj3 and delete them, if I remove ChildObj1 first I've changed ChildObj3's QModelIndex (row is now different). Similar issues occur if I delete a parent object (but I've fixed this by "pruning" children from the list of objects).
Here are the ways I've thought of working around this interface limitation, but I thought I'd ask for a better one before forging ahead:
Move "backwards", assuming a provided list of QModelIndices is orderered from top to bottom just go from bottom up. This really requires sorting to be reliable, and the sort would probably be something naive and slow (maybe there's a smart way of sorting a collection of QModelIndexes? Or does QItemSelectionModel provide good (ordered) lists?)
Update other QModelIndeces each time an object is removed/added (can't think of a non-naive solution, search the list, get new QModelIndeces where needed)
Since updating the actual data is easy, just update the data and rebuild the model. This seems grotesque, and I can imagine it getting quite slow with large sets of data.
Those are the ideas I've got currently. I'm working on option 1 right now.
Regards,
Dan O
Think of beginRemoveRows/endRemoveRows, etc. as methods to ask the QAbstractItemModel base class to fix up your persistent model indexes for you instead of just a way of updating views, and try not to confuse the QAbstractItemModel base class in its work on those indexes. Check out http://labs.trolltech.com/page/Projects/Itemview/Modeltest to exercise your model and see if you are keeping the QAbstractItemModel base class happy.
Where QPersistentModelIndex does not help is if you want to keep your undo/redo data outside of the model. I built a model that is heavily edited, and I did not want to try keeping everything in the model. I store the undo/redo data on the undo stack. The problem is that if you edit a column, storing the persistent index of that column on the undo stack, and then delete the row holding that column, the column's persistent index becomes invalid.
What I do is keep both a persistent model index, and a "historical" regular QModelIndex. When it's time to undo/redo, I check if the persistent index has become invalid. If it has, I pass the historical QModelIndex to a special method of my model to ask it to recreate the index, based on the row, column, and internalPointer. Since all of my edits are on the undo stack, by the time I've backed up to that column edit on the undo stack, the row is sure to be there in the model. I keep enough state in the internalPointer to recreate the original index.
I would consider using a "all-data" model and a filter proxy model with the data model. Data would only be added to the all-data model, and never removed. That way, you could store your undo/redo information with references to that model. (May I suggest QPersistentModelIndex?). Your data model could also track what should be shown, somehow. The filter model would then only return information for the items that should be shown at a given time.