I'd like to remove expandable attribute on some elements in QTreeView (populated with model inherited from QFileSystemModel). I can easily collapse this elements right after they are expanded, but they will be still visible in QTreeView as expandable.
How can I show them as unexpandable ones?
I believe you just have to override the default behaviour in the rowCount of your QFileSystemModel derived class to return zero rows for when that QModelIndex of the row you don't want to be expandable.
See http://qt-project.org/doc/qt-5.0/model-view-programming.html#models particularly the Tree Model diagram.
Related
Quick question
Is there an easy/quick way to map a QListWidget or QStandardItemModel (for QListView) item to my application logic?
Complete Question
Note: I will use undistinctly both QListWidget or QListView and itsQStandardItemModel. From my current point of view for this question, switching from one to another is trivial.
I face usually the need to have a QListView or equivalent in an HMI, which shows some text value and need to react on selection/click.
In the SLOT, in order to perform the required action, the row need to be identified. Qt::DisplayRole is NOT appropriate because some texts could be duplicated and QStrings are not the best way to identify data in Computer Science.
// Click on a row
connect( &myView, &QListView::clicked,
[&myView, this]( const QModelIndex &idx)
{
// E.G. need to update the database for this row. Which row?
});
Possible solutions:
Maintain a map to retrieve the ID from the QModelIndex row.
Save in the model row any ID, making easy to apply any operation.
First option is tedious: it requires to connect the model for keeping the map and the model synchronized.. Same logic again and again.
Second option seem by far the best: I save the (e.g. database id) and use it afterward; But, QListView model (up to what I know) does NOT include this very friendly and useful ID. So until now I had extended again and again the models for QListView.
How to map the QModelIndex back to my application logic? Do I really have to extend the model for that simple operation?
RELATED QUESTION: QTreeView: maintaining mapping between QModelIndex and underlying data
What about creating the QAbstractModel manually, this way you have complete control how the QModelIndexes are created, and you can use that to do stuff.
I'v implemented thousands of Qt Models, and I have never liked the QStandardItemModel approach as I would usually need to write more boilerplate than if I had come with the model myself.
Inherit from your QAbstractList/Table/TreeModel
implement index()
create a method for direct item access
.
// Click on a row
connect( &myView, &QListView::clicked,
[&myView, this]( const QModelIndex &idx)
{
auto& myItem = idx.model()->directAccess(idx.row());
});
profit.
I am trying to use the QStandardItem and QStandardItemModel to drive a TreeView in Qt.
In Qt the typical model to control the TreeView, TableView & ListView includes the concept of rows and columns, but also parent/child relationships.
I find the documentation very confusing, because it seems these are interdependent (e.g. to add a child to a QStandardItem, appendRow() is used), but nowhere I have found is dedicated to explaining exactly how.
If I had to guess, I would say: "rows are equivalent to children. columns have meaning only within an item itself". Is this correct?
Qt item model is recursive: each item is a table of items. It is incorrect to say that rows are equivalent to children: each index can have a child, no matter what its row column.
Of course, not all views can handle all models. Specifically, no Qt's built-in views can handle children in columns other than 0. But you certainly could implement a view that does!
I have searched QT doc for reference but I got some questions.
Here is the implementation in QT doc:
bool TableModel::removeRows(int position, int rows, const QModelIndex &index)
{
Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row) {
listOfPairs.removeAt(position);
}
endRemoveRows();
return true;
}
I think it uses index.row in the tableview to directly locate the data in the model. But what if I enable sorting for the tableview? After sorting, the index in the tableview doesn't correspond to the data in the model. The first row in the tableview may be the third data in the model.
How can I locate the data in model through tableview?
And are there any better implementations for removeRow() function?
you can use tableWidgetItem->setData(0, Qt::UserRole, "Desired Identity");
it will be always unique even when you sort the rows. refer
QTableWidget find a row through userdata
As the official documentation says ,
There are two ways of approaching sorting in the model/view architecture:
If your model is sortable, i.e, if it reimplements the QAbstractItemModel::sort() function, both QTableView and QTreeView provide an API that allows you to sort your model data programmatically.
The alternative approach, if your model does not have the required interface or if you want to use a list view to present your data, is to use a proxy model to transform the structure of your model before presenting the data in the view
So what happens when you change the sorting depends on how you arrange sorting for your model: either sorting in the view changes the arrangement of rows in the model or it only changes that arrangement for the proxy model.
If you use the proxy model, you can insert there some mapping between proxy model's rows (as the view sees them with the current sorting) and the original model's rows. Or you can just add some mapping between the row and the actual data item for that row in the original model - you can in fact even embed a void* to the data item directly into QModelIndex in your model's reimplementation of QAbstractItemModel::createIndex and then retrieve the pointer to the item from the index passed to methods such as removeRow. Another possibility is to operate with some unique integer identifier of the item instead of the direct pointer to it. It's therefore up to you how which way of mapping between rows and the actual model items to choose.
I want to have a qtreewidget with 1 column header but its children have more columns, I tried below code but I want to hide subsidies header too.
treeView = new QTreeView;
treeView->setModel(completer->model());
treeView->header()->hide();
treeView->expandAll();
thanks
You should reimplement QHeaderView for your needs, because QTreeView uses number of columns for root items.
First I want to thank you in advance for your answers. I insert one QStandardItem in one QStandardItemModel and then display this model in a Tree View (A). After this I append the same item (pointer) to a new QStandardItemModel wich is associated with another Tree View (B). It is only displayed one empty item instead one item with the same text in this second case. If I make a copy of the item, the result the expected. Why can I not append the same item in two different models?
In this case is not useful to use QSortFilterProxyModel because modelA and modelB have the same data but following a very different structure.
Thank you very much.
If it is not possible to do this, which solution you suggest me? I though maintaining a correspondence between table models by using hash tables, but I think there is a easier solution.
I copy one code example.
QStandardItem * item = generateExampleItem();
modelA->invisibleRootItem()->appendRow(item); // will be visible to the user
modelB->invisibleRootItem()->appendRow(item); // will be invisible to the user
ui.treeViewA->setModel(modelA);
ui.treeViewB->setModel(modelB);
ui.treeViewA->show();
ui.treeViewB->show();