I want to use QAbstractItemModel as many times before which will hold a tree structure from an external model. This model can send notifications before deleting a row and after finishing deleting a row. These notofications can happen at any time (within same GUI thread).
QAbstractItemModel has the beginRemoveRows and endRemoveRows which is then connected to the model signals. What I don't understand is how I get the QModelIndex. My underlying data model does not know anything about QAbstractItemModel which is per design because I wan to use that in other places where Qt is inacceptable.
What is the right way to get the QModelIndex when I know what is the index of the element inside the underlying data structure and have access to the parent?
Related
I have a model derived from QAbstractItemModel and I implemented Drag&Drop functionality via MIME types (via overriding of QAbstractItemModel::dropMimeData()...).
Short Version/TLDR;
My question is: Is there some signal that QAbstractItemModel emits when MIME data handling is fully complete?
Long Version
When a user reorders a model item via drag&drop, there are some adjustments I need to do in other Views. For this reason, I created a custom signal that I emit right at the end of my override of QAbstractItemModel::dropMimeData(). HOWEVER, when this signal is emited, the moved items have not yet been really moved: they have been copied, but the old items have not yet been removed; hence, I have duplicated and unordered items.
I have some newbie question. I'm not sure if I understand Model-View-Controller design pattern correctly.
Maybe I will start from describing my problem. I'm reading some data from file. This can take let's say 10 seconds and after that I present those data in the table. The question is how should I store those data? Besides QStandardItemModel should I have another container to which I will read data from file and use it in other threads? For example, I have QStandardItemModel in Gui thread and I create another container let's say QVector. I load data from file to QVector and then I move data from QVector to QStandardItemModel?
I can't use QStandardItemModel in other thread and read data directly from file to QStandardItemModel because GUI freeze as I know because QStandardItemModel emits signal to update view after appendRow.
Or maybe I should create custom model and add method to update view only when whole file is loaded into QStandardItemModel? QTableView has own container for data and it's not synchronized with the model? Is it possible/correct way?
What with situation when I read a new file?
Thanks for any help.
I think you can do such steps for resolve your problem:
When you need to load new data from file, set model for your QTableView in nullptr.
Fill QStandardItemModel (this model was the model for your QTableView) in non-main (non-GUI) thread with data from file.
Set model with data for your QTableView in main (GUI) thread.
Of course, the simplest way to solve your problem also may be to show for user something like this: "Data loading, please wait...", while you load data in QStandardItemModel in main (GUI) thread.
I have a really big tree structure and I cant load the complete tree into Ram on client side. I am using Qt's QTreeView.
I want to load the sub elements of an item dynamically when the user expands the element.
Is there some signal that triggers when the user opens an item in the tree?
I am using the tutorial Simple Tree Model Example. When I do changes to the model the view has also to be updated. And I dont want to loose the focus to avoid user confusion!
and after some time (request to the server)...
You need to implement a subclass of QAbstractItemModel that can process needed amount of data. When an item is expanded in the view, it calls QAbstractItemModel::rowCount to determine children count and then QAbstractItemModel::flags and QAbstractItemModel::data to get children data. If requested data is not available at the moment, you should return placeholder data (i.e. 1 row containing "Loading"), and start a request. When the data is received, emit rowsAboutToBeInserted and rowsInserted signals to notify the view about new data (you should also notify it about removing "Loading" row). The view will then call rowCount, data, and flags methods again, and your model should now provide loaded data. Use QCache to keep last accessed data in memory.
Previously, I asked about running model and view in different threads and now, I understand how it poses a problem. To circumvent the problem, I was thinking of duplication of data. When data is modified by the worker thread, it simultaneously sends an update to GUI/Model thread to update the model with the same data (so there exist a exact copy of data with the GUI/model).
Does this sound like a plausible approach? Other method is to use direct widgets with default models like QTableWidget etc. but then I need to do a lot of things that are powered by QTableView by default.
Please suggest!
Link to other question: Design Pattern, Qt Model/View and multiple threads
There are 2 scenarios that are possible but in either case you will need at least 2 objects as follows:
Data Object
Contains all functions required for maintaining and manipulating data. Data is stored in Pointers to objects describing data. Data Structures for this I will leave up to you.
Model
Contains a vector of pointers to data that is currently being displayed
Scenario 1
Data in QTableView is display only in which case on a QTimer signal or a different signal the data storage is locked and vector for display model is cut and put into the model and reset() is called to have QTableView repainted with new data.
Scenario 2
You can manipulate data via custom ItemEditor in QTableView. In this case the top widget that has QTableView should have references to your data object and QTableView and a signal handler for the signal emitted by the ItemEditor when the edit is complete. This signal handler will then lock the data structure inside data object and update it, once done it may cut a new vector to display but more often then not it won't have to.
How you will set up the locking, searching, etc is entirely up to you.
I'm implementing my 3rd "naive" model as QAbstractItemModel inheriting class.
So far it worked well.
However, I've been using read-only "static" models in my views and only changed the model of some views depending on the user's actions. So I used my_view->setModel( a_model ); to update a view.
Now I need to have one of the views to keep a unique model but that model needs to be update sometimes, using a special function "update()" function that I call in the code when required.
At the end of the update() function, I just call emit dataChanged( ... ); with the corresponding data.
It seems that it doesn't update the view this model is connected to. The only way to make the view update seems to do something like my_view->setModel( nullptr ); then my_view->setModel( a_model ); again.
What are the possible reasons for an emit dataChanged( ... ); to not trigger view's display update?
I've been debugging my model implementation functions and the index() function get called but not the data(). I'm a bit worried that maybe I didn't understood something about the model/view system in the case of changing model (that is not changed through the view but programmatically).
It's an open-source project so you chan check the full model code there (it's a bit hacky I think, not used to model/view system of Qt) : http://code.google.com/p/art-of-sequence/source/browse/tools/aosdesigner/view/model/LayerObjectsModel.cpp?spec=svn4fe209aa3e82f2c7cd42192581a890e28bada9b0&r=4fe209aa3e82f2c7cd42192581a890e28bada9b0
The code of the widget managing the view is available there : http://code.google.com/p/art-of-sequence/source/browse/tools/aosdesigner/view/LayersView.cpp?spec=svn4fe209aa3e82f2c7cd42192581a890e28bada9b0&r=4fe209aa3e82f2c7cd42192581a890e28bada9b0
I checked a bit Qt documentation. dataChanged() should be emitted when existing data of the model changes.
If you are adding rows to the model check beginInsertRows and endInsertRows
From the insertRows Qt documentation:
If you implement your own model, you can reimplement this function if
you want to support insertions. Alternatively, you can provide your
own API for altering the data. In either case, you will need to call
beginInsertRows() and endInsertRows() to notify other components that
the model has changed.
If you are removing rows from the model check correspondingly beginRemoveRows and endRemoveRows
Also have a look at beginResetData
When a model radically changes its data it can sometimes be easier to
just call this function rather than emit dataChanged() to inform other
components when the underlying data source, or its structure, has
changed.