parent parameter for qmodelindex when getting the index - c++

Here is the line of code:
QModelIndex id = tm->index(r, ec, QModelIndex());
So i have my own model which is tm and i am trying to access its index. r stands for the row and ec is for the column. I notice from examples that they add QModelIndex() on the third parameter. The third parameter stands for the parent index.
tm is just a simple QTableView. Is it really necessary to provide QModelIndex ? I tried reading the Qt manual but i can't seem to find any simple explanations when to supply a parent index.

Quoting from the documentation:
An invalid model index can be constructed with the QModelIndex constructor. Invalid indexes are often used as parent indexes when referring to top-level items in a model.
...
Each top-level item in a model is represented by a model index that does not have a parent index - in this case, parent() will return an invalid model index, equivalent to an index constructed with the zero argument form of the QModelIndex() constructor.
So if you do not have nested data (like in your QTableView), the parent index will always be an invalid one.
The signature of QAbstractItemModel::index is:
QModelIndex QAbstractItemModel::index(int row, int column, const QModelIndex & parent = QModelIndex()) const
The last parameter is optional, in your case you can just omit it to supply an invalid model index.

Related

how I use the listView from QT to take and show my vector?

have two functions .getProjects() and .getEmployees(), from another class "manage.h", that basically return a vector with all the projects/employees I've added until now.
How can I show them in my QT interface?
I've created two buttons (in a stackedWidget), one to get all the projects when clicked and the other one for the employees, and I've also used a listView that should show all my data when I click one of the two buttons, but how I tell the listView to take and show my function?
void MainWindow::on_showAllProjects_pushButton_clicked()
{
ui->listView->something(manage.getProjects());
}
You first need a model for your QListView.
QListView inherits QAbstractItemView which has the method of adding a model.
QItemSelectionModel *m = ui->listview->selectionModel();
ui->listview->setModel(new model);
Then you can start inserting rows into this model, by using a method from QAbstractItemModel, which is this one:
bool insertRow(int row, const QModelIndex &parent = QModelIndex())
Then use this method to set the data of this last item you inserted (the last row), you can access it by providing the last index of the model
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
Set the first argument to ui->listview->model->rowCount()
And the second element is an element from your vector, so you gonna have to iterate through it.

Proper way to implement an editable QAbstractListModel subclass for QML ListView

I am trying to make an editable model for a ListView in QML, using QAbstractListModel. Since it is stated in the Qt Documentation, I tried implementing setData() for my model, but I am facing several issues.
The setData() member function is defined as such:
bool setData(const QModelIndex &index, const QVariant &value, int role)
However, in my ListView delegate I have something like this:
MouseArea
{
anchors.fill: parent
onClicked: elementClicked(index)
}
Is there a proper way to cast the index to a QModelIndex to use it in setData()? I tried to craft a QModelIndex using this:
void MainWindow::onElementClicked(int index)
{
AbstractItem x = mListModel.getItem(index); //Getting AbstractItem at specific index...
x.setStatus(); //Changing a boolean value of AbstractItem
QModelIndex idx = MIListModel.index(0, index, QModelIndex()); //using 0, since the ListView only has 1 row.
qDebug() << index;
MIListModel.setData(idx, x, Qt::EditRole); //...and then trying to pass it in setData() to replace the original one.
qDebug() << "OK";
}
But then setData() always returns false. Using qDebug() << index.row() and qDebug() << index.column() inside setData(), I found out that the value for both row and column is -1, thus causing the failure.
Also, do I have to implement Qt::ItemFlags flags(const QModelIndex &index) const? In the Qt Documentation(it's the same link as above) they state that it is needed, but I found no relevant example of it being used for QML.
Finally, I am having trouble passing AbstractItem to setData(), since I am getting this:
cannot convert argument 2 from 'const QVariant' to 'const AbstractItem &'
with
[
T=AbstractItem
]
To resolve this, I tried using Q_DECLARE_METATYPE(AbstractItem), but I still get the same error. The only way I could temporarily solve this was changing the setData() member function to use a AbstractItem instead a QVariant. Is this even good practice?
To sum up my problem, I have these questions:
How can I cast an int to a QModelIndex to use in setData().
Do I also have to reimplement flags() to get an editable model. If so, how?
Is it a good idea to change the second argument of setData() to one of my choice? If not, how do I convert my class to QVariant?
If possible, I would also like a source where I can further study using QAbstractListModel with QML.
Edit: Removed additional question as it was off-topic.

How to access QStandardItemModel and it's data using a QModelIndex?

I have a clicked()-signal which knows a selected index which is of the type QModelIndex.
void onListClicked(const QModelIndex & index) { /* ... */ }
No I want to access the data of the clicked item. I found out I can access the model using model():
void onListClicked(const QModelIndex & index)
{
QStandardItemModel * model {index.model()};
}
But this fails as the model() getter only allows me to return an QAbstractItemModel.
error: invalid conversion from 'const QAbstractItemModel*' to 'QStandardItemModel*' [-fpermissive]
How to access the QStandardItemModel or even better the selected QStandardItem? My unique identifier is stored in QStandardItem::data().
What I need is something like that:
void onListClicked(const QModelIndex & index)
{
QStandardItemModel * model {index.model()};
QStandardItem * item {model->itemFromIndex(index)};
qDebug() << item->data().toString();
}
But that does not work. Why is that so difficult. What do I miss here?
I think you can get the data directly from the model index:
void onListClicked(const QModelIndex & index) {
index.data(Qt::UserRole + 1);
// ...
}
You can use any other role to retrieve different kind of data.
Just cast it:
QStandardItemModel *model { static_cast<QStandardItemModel *>(model()); }
I had the same problem, as I need to retrieve my special model:
auto myModel=const_cast<MySpecialModel*>(dynamic_cast<const MySpecialModel*>(modelIndex.model()));
This was a perfectly working solution for me.
But, there seems to be an important issue doing so:
http://doc.qt.io/qt-5/qmodelindex.html
It says there:
A const pointer to the model is returned because calls to non-const functions of the model might invalidate the model index and possibly crash your application.
Unfortunately, the docs didn't say, why there might be a possible crash and what one shouldn't do.

Displaying std::map in a QTableView

I have a some sort of data stored in a std::map and need to display that in a QTableView.
So I've my model class from QAbstractItemModel, but I'm faced with a problem:
The "data" method gives me a QModelIndex that contains the expected row-number of the data-entry. But since I'm using a map and not a vector, I can't randomly access it with the row parameter.
So my idea was to overwrite the "index"-method that generates the QModelIndex object and contain the appropriate hash-key for each object.
But that doesn't make it any easier, since I'd be required to have to get the hash-key by row-number again.
Of course i could iterate through the entire map from begin() to end() to find the n-th row/element, but that would be extremely inefficient.
Do you have any advice how to approprietly display std::map in a QTableView?
struct Data {
...
};
std::map<int, Data> dataMapping;
QModelIndex index ( int row, int column, const QModelIndex & parent );
QVariant data ( const QModelIndex & index, int role );

QSortFilterProxyModel sort multiple columns

I am trying to implement a table that is sortable on more than one column. Qt's QSortFilterProxyModel only supports sorting on one column (at least in Qt 4.6.2).
I've found this solution by dimkanovikov on github, but it lacks dynamic updating on added rows. What I mean by this, is that the model is changed and the beginInsertRows(), beginRemoveRows(), their corresponding end..-methods and the dataChanged() signals are emitted. Ideally I would like to only these rows to be updated, but the model should at least react to such changes.
There's another FAQ item on Qt's site that sorts a QTableWidget, but it lacks dynamic updating, too.
I am new to Qt and I'd like to get some pointers on how I should go about this.
You can set the sorting role of the QSortFilterProxyModel to something different then the default Qt::DisplayRole withsetSortRole(Qt::UserRole). Then, in your model's data() method return a proper sort key if it gets called with the role Qt::UserRole, e.g. by concatenating the strings of the involved columns.
There's one slightly inelegant solution, that is always used to sort multiple columns.
You have to subclass QSortFilterProxyModel and reimplement bool lessThan(const QModelIndex &rLeft, const QModelIndex &rRight) const. Instead of only comparing between the two given indices, check all the columns:
int const left_row = rLeft.row();
int const right_row = rRight.row();
int const num_columns = sourceModel()->columnCount();
for(int compared_column = rLeft.column(); compared_column<num_columns; ++compared_column) {
QModelIndex const left_idx = sourceModel()->index(left_row, compared_column, QModelIndex());
QModelIndex const right_idx = sourceModel()->index(right_row, compared_column, QModelIndex());
QString const leftData = sourceModel()->data(left_idx).toString();
QString const rightData = sourceModel()->data(right_idx).toString();
int const compare = QString::localeAwareCompare(leftData, rightData);
if(compare!=0) {
return compare<0;
}
}
return false;
Then you can call sort(0) on your QSortFilterProxyModel subclass and it will sort all the columns. Also don't forget to call setDynamicSortFilter(true) when you want the sorted rows to be dynamically resorted when the model data changes.
To support sorting on arbitrary columns in ascending or descending order, you would have to keep this info in a QList and compare accordingly when lessThan is called. In the list you would have the columns in order of their priority and do the comparisons in the same order. You should also sort the other "inactive" columns in some predefined order, otherwise they will not be sorted by default.