Home » Eclipse Projects » GEF » [GEF4] Cross container drag and drop with JavaFX(How to resolve issues with JavaFX z-order when using drag and drop through GEF policies)
|
Re: [GEF4] Cross container drag and drop with JavaFX [message #1734670 is a reply to message #1734573] |
Fri, 10 June 2016 08:47 |
|
Hi Bojan,
it is hard for me to understand the situation without source code and/or screenshots. However, drag and drop within one scene is definitely possible ("Logo Example" palette), and it is also possible between two independent scenes.
You can setup some kind of "glass pane" that is above everything else. When a visual is dragged, you put it into the glass pane, and move it within the glass pane to its final position. When it is dropped, you can put it into the new underlying container.
Currently, I do not think this would be a new ITool, but rather an AbstractTransactionPolicy that can be used to move visuals to the glass pane and back to an underlying container. The policy would then be used by the interaction policies that need it. If you only have one interaction policy that would need this feature, then I would not use an AbstractTransactionPolicy, though.
Best regards,
Matthias
[Updated on: Fri, 10 June 2016 08:54] Report message to a moderator
|
|
|
Re: [GEF4] Cross container drag and drop with JavaFX [message #1734699 is a reply to message #1734670] |
Fri, 10 June 2016 12:11 |
Bojan Stanković Messages: 4 Registered: June 2016 |
Junior Member |
|
|
Hello Matthias,
thank you for your answer. I cannot provide any source code because the current implementation is pretty large and complex. You were on the point with your answers . I have used my version of glass pane already by adding an FX stack pane on top of my visual part which provided me with the ability to select a visual part without triggering actual underlying FX controls the visual part consists of.
Now, as far as I understood your suggestion is to put some kind of a glass pane on top of everything and then distribute the mouse click event through it once there is a visual part underneath and when dragged the visual part would be transferred to that glass pane and then on drop placed somewhere underneath it? What would you recommend for a glass pane in that case? I've used StackPane earlier but since it extends Control it already has some mouse events handling logic by default and i had to redefine the event dispatcher and reorder the event chain in order to pass through or hold some mouse events.
I was also thinking of moving the visual part to the selection feedback layer that is used to draw selection geometry when dragged. Is there any reason why this wouldn't be a good practice?
I will try to provide some imagery soon.
Best regards,
Bojan
[Updated on: Fri, 10 June 2016 12:23] Report message to a moderator
|
|
|
Re: [GEF4] Cross container drag and drop with JavaFX [message #1734710 is a reply to message #1734699] |
Fri, 10 June 2016 13:33 |
|
Hi Bojan,
I think I understand the situation now: You are using the default layer setup: content-layer, feedback-layer, handle-layer. The problem is that mouse events are consumed by JavaFX Controls that are used as part of the visualization. In this case, you do not need a glass pane at all. Instead, you can set the mouse-transparent property of the controls to true so that mouse events are not processed by the controls. As long as the visual parts use a Parent (or subclasses thereof) as their "main" visual, and this visual is not mouse-transparent, the events should be processed by registered OnClick and OnDrag policies.
Best regards,
Matthias
|
|
|
Re: [GEF4] Cross container drag and drop with JavaFX [message #1734717 is a reply to message #1734710] |
Fri, 10 June 2016 14:28 |
Bojan Stanković Messages: 4 Registered: June 2016 |
Junior Member |
|
|
Hello Matthias,
Thank you for your advice. I am indeed using that layer setup. My parts are using StackPane (which extends region) and all the other controls are added to that stack pane. My first solution was to use setMouseTransparent to disable the added controls from responding to mouse events but I probably didn't set it right at that point so I had to invent the local "glass pane" for each widget and it seems to be working fine for me atm because it allows me, when I assign the DnD policy, to control widgets on root pane and within containers as well (on which I dont have glass pane, and i have event dispatchers that send events to inner widgets when cicked on them and send events to the container if clicked anywhere else within the container).
However, what I'm interested in is, if there is an out of the box solution (through policy or a tool) that allows me to display the dragged component on top of all other graphics (because at the moment it seems to go behind some containers when I drag it from a root part for example, only selection remains visible on top, the component goes behind visually which means it keeps the original z order of the root pane). That's why I was asking if it's a good practice to try to move the visual part to selection feedback layer, so it could stay on top.
I am also using content policy to detach and attach a dragged widget from old parent container to the new parent container and it looks something like this:
final ForwardUndoCompositeOperation compositeMoveOperation = new ForwardUndoCompositeOperation("Composite move");
ContentPolicy<Node> childPolicy = part.<ContentPolicy<Node>> getAdapter(ContentPolicy.class);
childPolicy.init();
childPolicy.removeFromParent();
ContentPolicy<Node> newPolicy = newParent.<ContentPolicy<Node>> getAdapter(ContentPolicy.class);
newPolicy.init();
newPolicy.addContentChild(part.getContent(), 0);
compositeMoveOperation.add(childPolicy.commit());
compositeMoveOperation.add(newPolicy.commit());
part.getRoot().getViewer().getDomain().execute(compositeMoveOperation);
this is all happening in my own drag and drop policy that extends FXRelocateOnDragPolicy and this particular section of code is executed in overriden release method. The problem is I get an IllegalStateException when I try to undo this operation with the following message :
Quote:
Located a ContentPart which controls the same (or an equal) content element but is already bound to a parent. A content element may only be controlled by a single ContentPart.
I should also point out that in the same class in overriden press method section of code there's a section of code that executes another policy via commit(policy); from AbstractPolicy (this was added because I had to perform some checks and override default behavior of FXDragTool that makes every click undoable and I needed it to work just for drag).
Thank you for your time.
Best regards,
Bojan
[Updated on: Fri, 10 June 2016 14:29] Report message to a moderator
|
|
|
Re: [GEF4] Cross container drag and drop with JavaFX [message #1734724 is a reply to message #1734717] |
Fri, 10 June 2016 16:27 |
|
Hi Bojan,
thank you for the information, however, I do not quite grasp the situation, yet, sorry
If I understand correctly, you have a number of content parts. These content parts are displaying JavaFX controls, which can be added to and removed from a content part via DnD. The content parts use a StackPane as their "main" visual.
However, I still have some questions:
- What is the "root pane" in your application? Do you mean the visual of the root part, i.e. the content layer?
- What is a widget? I suppose all JavaFX controls are widgets?
- Which content parts are you using and how are they organized? For example, is there a ControlPart for the visualization of individual JavaFX Controls, and a ContainerPart for the layout of other parts, or do you only have only the ControlPart and it serves both purposes?
- Can a ContainerPart/ControlPart contain other ContainerParts/ControlParts?
- Why do you exclusively use StackPane as the main visual? Also, within a StackPane, all visuals are placed on top of each other. Would it not be more convenient to use other JavaFX layout panes? For example, you could have a HorizontalContainerPart that lays out its children using HBox, i.e. horizontally, etc.
- There is only one root part, therefore, what exactly do you mean by dragging something "from a root part"?
- Is the visualization correct after the dragged parts are dropped?
- Do you want to have the visuals in the foreground only while dragging?
Since all content part visuals are placed in-order within the content layer, the Z-order is determined by the part order, i.e. the order of the parts' children. Therefore, you could possibly solve this by reordering the dragged part to the end of the root's children list when the interaction starts. I will prepare a snippet to demonstrate this over the weekend.
The feedback layer is above the content layer, however, there is no simple way of moving a visual part from the content layer to the feedback layer. You could possibly extend FXRootPart to add an intermediate layer between content layer and feedback layer. The subclass could also provide methods to move a visual from the content layer to the intermediate layer and vice versa. Depending on the situation this could be an elegant solution, however, it does not feel quite right for me, yet
Moreover, the customized event dispatchers should really not be necessary, IMHO. If the JavaFX controls are wrapped in a ControlPart that does not use a JavaFX Control as its main visual (which would consume mouse events), but, for example, a StackPane (as in your situation), then setting the actual JavaFX Controls to be mouse transparent should solve the issue of event propagation.
Best regards,
Matthias
|
|
|
Re: [GEF4] Cross container drag and drop with JavaFX [message #1734737 is a reply to message #1734724] |
Fri, 10 June 2016 19:18 |
|
Hi Bojan,
sorry for the inconvenience, I read everything again from the beginning, and now I understand it, I think. Somehow, I was thinking of a UI-builder-like scenario before. Now, I think your situation is similar to the following:
Semantic Model: Classes with corresponding Attributes
Content Parts: ClassPart as parent for AttributePart
Visualization: Within one viewer; ClassPart provides the container for AttributePart
Interaction: Drag an attribute from one class to another
Is this example comparable to your situation?
I will answer the questions related to the error message and to the init(), commit() mechanism together with my next response.
Best regards,
Matthias
[Updated on: Fri, 10 June 2016 19:21] Report message to a moderator
|
|
| | |
Re: [GEF4] Cross container drag and drop with JavaFX [message #1742638 is a reply to message #1735238] |
Tue, 06 September 2016 09:48 |
|
Sorry for the massive delay, I was inactive in the forums in the previous months, and concentrated on finishing the last courses at college.
Anyway, I have written a small app that displays buttons. The buttons can be clicked per default, which increases the button's scale. When the <Shift> key is pressed while dragging a button, it is not rescaled, but instead it is only moved. This is accomplished by setting mouse-transparent to true while <Shift> is pressed. The following ButtonPart implements that behavior:
package com.itemis.sample.ui.builder.fx;
import java.util.Collections;
import java.util.List;
import org.eclipse.gef.common.collections.CollectionUtils;
import org.eclipse.gef.mvc.fx.parts.AbstractFXContentPart;
import org.eclipse.gef.mvc.viewer.IViewer;
import com.google.common.collect.SetMultimap;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.input.KeyEvent;
public class ButtonPart extends AbstractFXContentPart<Group> {
private Button button;
@Override
protected Group createVisual() {
// create group
Group group = new Group();
group.setPickOnBounds(true);
// create button
button = new Button();
button.setOnAction((ae) -> {
double sx = button.getScaleX() * 1.125;
button.setScaleX(sx);
button.setScaleY(sx);
});
// put button into group
group.getChildren().add(button);
return group;
}
@Override
protected SetMultimap<? extends Object, String> doGetContentAnchorages() {
return CollectionUtils.emptySetMultimap();
}
@Override
protected List<? extends Object> doGetContentChildren() {
return Collections.emptyList();
}
@Override
protected void doRefreshVisual(Group visual) {
button.setText(getContent().toString());
}
@Override
protected void register(IViewer<Node> viewer) {
super.register(viewer);
viewer.getRootPart().getVisual().getScene().addEventFilter(KeyEvent.ANY, (ke) -> {
button.setMouseTransparent(ke.isShiftDown());
});
}
}
Therefore, a glass pane does not need to be used if a parent visual can be made clickable.
Regarding init() and commit() you can also use the methods provided by AbstractInteractionPolicy, but the code looks good so far.
Best regards,
Matthias
|
|
|
Goto Forum:
Current Time: Thu Apr 18 19:00:59 GMT 2024
Powered by FUDForum. Page generated in 0.02580 seconds
|