Select objects on a JavaFX Pane - javafx

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.

Related

How to generate Kanban with lists based on relationship between Item A, Item B and yet another sub-relationship with Item A?

I am trying to create a Kanban view based on several relationships between datasources.
The case
I have:
- Tasks datasource
- Task_Stages datasource (e.g. To Do / Doing / Done)
- Tasks many-to-many relationship with Tasks as in Master Task / Sub-Tasks
The Issue
I am trying to use grid-layout and its grid-cells as the typical "List" in a Kanban. Where lists are representing the Stages
Within a grid-cell I am trying to set a List-layout widget to represent a typical Kanban item.
If I set the grid's datasource to Task_Stages, each grid-cell would represent a state, e.g. To do / doing / done. In this case, the list-layout widget would show absolutely all Task records.
I am struggling to set it to show only Tasks, which are related as Sub-Tasks to a selected Task.
What I tried
I've tried a large number of relationship combinations using several layers of panels, but all fail.
e.g. I set up a Main-Panel as Task:Sub-Tasks, then the grid as Sub-Task:Stages - in this case it shows only 1 grid cell that represents the stage of the first sub-task record.
This is how it looks with the above example:
*Only one Stage is shown, instead of showing all stages as different "lists"(grid-cells)
*The tasks visualized in the cell do not bear the relationship with the master task and are just tasks that have that stage type selected
Is there another way I can achieve this?
In order to get this working correctly you will probably need to do the following:
Set your main panel datasource to Stages.
In your Stages datasource make sure you don't apply any filters, so
that all stages will show as in 'To Do/Doing/Done'.
Still in your Stages datasource set a prefetch for Tasks, then use
the 'Advanced' option under prefetch settings to prefetch
Tasks.relations.Subtasks.
Back to your main panel, drag in a new Grid or make sure your
existing grid datasource is set to 'Inherited: Stages'.
For reference purposes drag in a label and set the binding to
#datasource.item.YourStagesName, so it will reflect your correct
stage in each panel. Drag in a list widget into the grid cell and
set the datasource to 'Stages: Tasks (relation)'.
Drag in a list widget into the list row and set the datasource to
'Tasks: SubTasks (relation)'.
Relatively speaking this should correct your issue but may require some additional testing. I did not test this setup myself but have successfully implemented something similar. The secret here is to prefetch all relations even if they are multiple levels deep by using the advanced prefetch option. Also keep in mind that the more tasks you have the more this process of prefetching multiple relations deep can slow down the performance of your app.

How to update selection in the QTableView after drag row

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.

Setting multiple selection in QTreeView

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.

How to select an QGraphicsItem without selecting whole group (to which this item belongs)

I wonder if it is possible to select item that belongs to one group, without selecting whole group.
What I trying to make is a group of items, that can be moved (all items are moved together) but none of them can't be moved individually. But I want also to be able to select items inside this group and then do something with them, like reordering, deleting, changing their color, etc.
The other problem is, there can be group of groups. I wish also to be able to select these groups inside parent group. I was thinking that this could be problem, because we are not able to determine which group users want to select. For demonstration purpose, lets say that we have graphic's scene composed of following items:
Group A which contains group B. The group B contains 3 lines.
If I press double click on group A, then I am then able to select group B. If I again press double click on B, then I am able to select lines inside group B. Pressing Esc does opposite as double click. The problem is, I have no idea how to do that, because all selection is routed to the parents, and than back to all its children.
You can't use QGraphicsItemGroup to do this because selecting one item in a group automaticaly selects all other memebrs of the group.
I'd subclass QGraphicsItem to create a 'RootItem' class. This class would contain two lists. One is a list of ordinary QGraphicsItems that make up the visual elements of the group itself, parented to this RootItem. The other list is of other RootItems that are parented to this one (e.g. Group B).
You would just need to make sure that you carefully controlled which items are selectable at any one time and how the interactions propagate between items.
Hope this helps.

One QStandardItemModel for different QTableView, Generic vs Specific Views

I really don't know if this makes sense but this is what I trying to do:
I'm doing my game's editor in QT. Currently I'm using a QStandardItemModel to store all my scene items. These items have names, position, Textures(vector of Texture which is a custom class), Animations (vector of Animation), etc.
I find it useful to have one item for row cause I can add or remove these items easily besides having them in a single place so changing this model should affect the entire app.
Now, I'm trying to do specific views for say the "Textures" of a certain item. This QTableView should show the texture's name, path etc. So, basically how can I grab the vector of Textures in the general model and fill another view without doing another model?
You will want to use a QSortFilterProxy Model. Set one up like this.
QTableView *tableView = new QTableView;
MyItemModel *sourceModel = new MyItemModel(this);
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(sourceModel);
proxyModel->setFilterKeyColumn(column_#_to_filter_by);
proxyModel->setFilterRegExp(a_regex_that_matches_the_item_you_want_to_display);
tableView->setModel(proxyModel);
You should be able to use one model and different proxies to setup different views.

Resources