I have custom QTableView class that shows content of custom model based on QAbstractItemModel. In the model I've implemented all needed methods to support changing rows order by DragAndDrop ( using dropMimeData()).
But I do not know how to update selection in the view after model (and view) changed.
For example:
user clicks on the row, it becomes 'selected';
user drags this row to other place;
rows are swaps in the model and view;
BUT selection stays on the first selected row.
How model can notify view to change selection?
NOTE: I cant to create additional signals and slots because don't use MOC.
The solution is:
In function dropMimeData() need to use beginMoveRows() and andMoveRows() around place where data changed.
Need to process signal QAbstractItemModel::rowsMoved of the model, where we can retrieve index of the target row.
Related
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.
I have a model derived from QFileSystemModel. I extended it by a Role which holds a bool value which indicates whether a file has been selected for later use. This model is displayed in a qml TreeView. In this view I can select files via checkboxes. I have a list of QPersistentModelIndex of the selected indices stored in my model.
In a different view (probably a ListView or TableView), I would like to display only items, which have have been selected in the TreeView. In this other view I also want to be able to remove the selection. So the question is whether this can be done with only one model (or maybe a QSortFilterProxyModel inbetween) or whether I need to have two models communicating with each other.
I've created an application to draw objects on a JavaFX pane (rectangle, paths, custom controls etc..).
Now I want to be able to select those objects to move, copy or group them. The javafx Pane don't have a selectionModel by default and I somehow didn't find out how to implement such function.
If someone got an Idea on how to do this, I'll be grateful
You need to create your own selection model.
First you create a class SelectionModel. In that you put a Set. In order to put nodes into that set, you have to create a mouse handler that adds nodes to the model and removes them from the model depending on shift/ctrl pressed while you click on the nodes.
When you move the selection via mouse, you get the position of the currently clicked on node and instead of moving the single node in the event handler you move all nodes of the list in the SelectionModel.
In order to group them, you need to create a class/collection in which you can store the various nodes you selected. Usually the group is just a parent node. But that varies depending on your requirements.
Copy/Paste is a different matter. You need to create some kind of factory that creates and positions new nodes depending on the nodes in your selection model.
Here's an example with code for a start. It shows you how to select nodes.
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.
I have a need here regarding multiple selection of items in the QTreeView. I have two widgets, QTreeView on left and another QGLWidget on the right. If I do a multiple selection, I must highlight the items in the glwidget. Vice versa, I need to highlight the items in the tree view if multiple selection is done on the glwidget. Currently, I am able to update single item by setting the current index of the tree view. Any ideas on how to update the selection of multiple items on the tree view with multiple selection on glwidget?
You can use the tree view's item selection model (treeView->selectionMode(), of type QItemSelectionModel). It has a signal selectionChanged() you can connect to to receive tree view selection changes and apply them to the GL view.
When receiving selection events from the GL view, you can use QItemSelectionModel::select() to propagate them to the tree view.
To enable multiselection on your treeview, call setSelectionMode( MultiSelection ).
Frank was faster, but I still post my (untested) code example for adding an item to the current selection:
treeView->selectionModel()->select(
treeView->model()->index(row, column, parent),
QItemSelectionModel::SelectCurrent);
There are other selection modes too, see the QItemSelectionModel reference. SelectCurrent is a short-hand for Select | Current, so means update current selection by selecting the given items. It does not mean "select as current selection" (replacing previous selection).
In Python (PyQt6) I do :
ui.my_treeView.setSelectionMode(ui.my_treeView.selectionMode().MultiSelection)
It works well.