Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
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)
[GEF4] Cross container drag and drop with JavaFX [message #1734573] Thu, 09 June 2016 13:23 Go to next message
Bojan Stanković is currently offline Bojan StankovićFriend
Messages: 4
Registered: June 2016
Junior Member
Hello everyone,

I've come across an issue while implementing my version of UI container components which I don't know how to resolve so I i would like to ask you a couple of questions.

I'm currently using GEF4 (201506081138 gef4.fx and geometry build) with JavaFX in development of a new e4 platform. While making a graphical designer of UI components out of an EditorPart I've come across an issue when using a drag and drop policy with my containers.

The containers are made out of visual parts that hold FX StackPane components and they are nested as rectangles into one another in such way that for example one big container can hold two smaller ones who are supposed to be in the same "layer" (or z order if you will). Those containers are supposed to be able to hold other simpler components and those should be capable of being transferred between containers.

I've successfully added FXHoverOnHoverPolicy, VisualBoundsGeometryProvider with selection and hover feedback as well as selection handles geometry provider. I have also added FXFocusAndSelectOnClickPolicy through FXClickDragTool key and rellocating the widgets seemed to be working fine. However, once I've set the background color on containers (StackPane widgets) I've noticed that they are not on the same z-order even though they seem to be in the same parent and they don't overlap.

This behavior blocks me in my intent to create a drag and drop feature for simple widgets that will enable dnd of a widget from one subcontainer to the other. However, when I try that, a couple of nasty things happen:

1. Underlying JavaFX component starts changing bounds in parent when I drag my simple widget outside it's original layout bounds. (layout bounds stay the same size)

2. the widget disappears behind the second container while selection geometry provider feedback remains on top and once i drop the widget I cannot select it again because it ends up behind the 2nd container.

I wrote some of the logic in an extended drag and drop policy to detect which container component is going to receive the dropped widget but i also have issues with making content policies adding and removing children from my containers since the dnd policy recognizes only the dragged widget as a host.

I am pretty sure that I'm doing something wrong here, so I would like to ask you what are the steps I can take in order to create a feature like this?
Should I be moving my dragged components to feedback layer somehow in order to avoid JavaFX z-order problems? Should I move my code out of the custom drag and drop policy into a separate ITool custom class( which would make the code make more sense but still don't see how it's going to resolve my problem with dragged objects going behind eachother)?

Cheers,
Bojan
Re: [GEF4] Cross container drag and drop with JavaFX [message #1734670 is a reply to message #1734573] Fri, 10 June 2016 08:47 Go to previous messageGo to next message
Matthias Wienand is currently offline Matthias WienandFriend
Messages: 230
Registered: March 2015
Senior Member
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 Go to previous messageGo to next message
Bojan Stanković is currently offline Bojan StankovićFriend
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 Go to previous messageGo to next message
Matthias Wienand is currently offline Matthias WienandFriend
Messages: 230
Registered: March 2015
Senior Member
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 Go to previous messageGo to next message
Bojan Stanković is currently offline Bojan StankovićFriend
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 Go to previous messageGo to next message
Matthias Wienand is currently offline Matthias WienandFriend
Messages: 230
Registered: March 2015
Senior Member
Hi Bojan,

thank you for the information, however, I do not quite grasp the situation, yet, sorry Sad

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 Wink

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 Go to previous messageGo to next message
Matthias Wienand is currently offline Matthias WienandFriend
Messages: 230
Registered: March 2015
Senior Member
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 #1734843 is a reply to message #1734737] Mon, 13 June 2016 12:57 Go to previous messageGo to next message
Bojan Stanković is currently offline Bojan StankovićFriend
Messages: 4
Registered: June 2016
Junior Member
Hello Matthias,

Thank you for making an effort to understand my questions. I'm attaching an image that should help you understand the app better. It is indeed a software that has some UI designer features.

When I say widgets i mean my part classes that extend an abstract class that extends AbstractFXContentPart<StackPane>. Both widgets and containers extend that abstract part class and they both have a local StackPane which they return on createVisual. That stack pane also holds an instance of an object extending JFX Control that represents the actual widget visual content. For basic widget parts on top of that there's another StackPane in order to soak up the events going through to JFX controls that blocks events from falling through to JFX controls (I've tried setMouseTransparent earlier, before adding the second StackPane on top, couldn't make it work because FXFocusAndSelectOnClickPolicy click didn't trigger for some reason).

Containers are implemented in a similar way. The inner stack pane holds an instance of a class that extends JFX Control. That instance holds the list of JFX Nodes and when I call the addChildVisual or removeChildVisual that I've Overriden in my part class, I'm basically modifying that list. A similar list exists in the model as well and it's modified in Overriden addContentChild and removeContentChild by calling getContent().removeWidget(modelClassInstance) or something similar.

All of these things are placed on an instance of a class that extends AbstractFXContentPart<Group> that I treat as editor surface root part. The real FXRootPart content layer is a parent of this instance. I hope I have managed to clarify a bit what the code organization looks like. Please feel free to give any suggestions to how I can improve the things I'm working on since I'm having quite a few issues (when transporting a basic widget from "Root part" to the container part on drag, my drop event ends up on a totally different place etc.)


EDIT: What is called "Root part" on the image is actually an object extending AbstractFXContentPart<Group> as described earlier.
  • Attachment: image3.png
    (Size: 12.95KB, Downloaded 625 times)

[Updated on: Mon, 13 June 2016 13:22]

Report message to a moderator

Re: [GEF4] Cross container drag and drop with JavaFX [message #1735238 is a reply to message #1734843] Thu, 16 June 2016 14:10 Go to previous messageGo to next message
Matthias Wienand is currently offline Matthias WienandFriend
Messages: 230
Registered: March 2015
Senior Member
Hi Bojan,

thank you for the clarification. I will play with the code a bit and give you a detailed response later today or tomorrow.

Best regards,
Matthias
Re: [GEF4] Cross container drag and drop with JavaFX [message #1742638 is a reply to message #1735238] Tue, 06 September 2016 09:48 Go to previous message
Matthias Wienand is currently offline Matthias WienandFriend
Messages: 230
Registered: March 2015
Senior Member
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
Previous Topic:[GEF4] How to print diagram
Next Topic:Constrain size of InfiniteCanvas
Goto Forum:
  


Current Time: Thu Apr 18 19:00:59 GMT 2024

Powered by FUDForum. Page generated in 0.02580 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top