I'm using a popup dialog during a drag and drop operation. When the drop happens a dialog pops up and when it is dismissed the event chain should continue and allow something to happen when the drag operation ends. If the popup dialog is FX then there is no problem but if it's Gluon the drag done operation doesn't happen.
Here is a sample code:
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import com.gluonhq.charm.glisten.mvc.View;
public class MainView extends View {
HBox root;
public MainView(String name) {
super(name);
Label source = new Label("Source");
configureDragSource(source);
Label target = new Label("Target");
configureDragTarget(target);
Label popupTarget = new Label("Popup Target");
configureDragPopupTarget(popupTarget);
root = new HBox(40, source, target, popupTarget);
setCenter(root);
}
private void configureDragSource(Label source) {
source.setOnDragDetected(e -> {
root.setBackground(new Background(new BackgroundFill(Color.RED, null, null)));
Dragboard db = source.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
content.put(DataFormat.PLAIN_TEXT, source.getText());
db.setContent(content);
});
source.setOnDragDone(e -> root.setBackground(new Background(new BackgroundFill(null, null, null))));
}
private void configureDragTarget(Label target) {
target.setOnDragOver(e -> e.acceptTransferModes(TransferMode.ANY));
}
private void configureDragPopupTarget(Label popupTarget) {
popupTarget.setOnDragOver(e -> e.acceptTransferModes(TransferMode.ANY));
popupTarget.setOnDragDropped(e -> {
javafx.scene.control.Alert popup1 = new javafx.scene.control.Alert(AlertType.INFORMATION);
com.gluonhq.charm.glisten.control.Alert popup2 = new com.gluonhq.charm.glisten.control.Alert(AlertType.INFORMATION);
popup1.showAndWait();
});
}
}
The source should be dragged upon which the background changes to red. When the drag operation is done the backgrounds should return to default. The regular drop target does nothing and the color change works. But when dropping on the popup target the dialog appears and when it is closed the color changes only for the FX dialog and not for the gluon dialog. Change popup1.showAndWait();
to popup2
.
If important this is the application class
import com.gluonhq.charm.glisten.application.MobileApplication;
public class TestApplication extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> new MainView(HOME_VIEW));
}
public static void main(String[] args) {
launch(args);
}
}
and this is the gradle build file:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.3.5'
}
}
apply plugin: 'org.javafxports.jfxmobile'
apply plugin: 'eclipse'
jar {
manifest {
attributes 'Main-Class': 'com.test.TestApplication'
}
}
jfxmobile {
downConfig {
version = '3.3.0'
plugins 'display', 'lifecycle', 'statusbar', 'storage'
}
android {
compileSdkVersion = 19
// manifest = 'src/android/AndroidManifest.xml'
}
ios {
infoPList = file('src/ios/Default-Info.plist')
forceLinkClasses = [
'com.gluonhq.**.*',
'javax.annotations.**.*',
'javax.inject.**.*',
'javax.json.**.*',
'org.glassfish.json.**.*'
]
}
}
eclipse {
classpath {
downloadJavadoc = true
downloadSources = true
}
}
repositories {
jcenter()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
mainClassName = 'com.test.TestApplication'
dependencies {
compile 'com.gluonhq:charm:4.3.5'
}
task wrapper(type: Wrapper) {
gradleVersion = '4.2'
}
Happens also on compile 'com.gluonhq:charm:4.3.7'
and 4.4.0.
Running on Java 8 b141. Why does this happen? Is this a bug?
JavaFX built-in dialogs and Gluon Dialogs are not the same. In fact, the latter extends from
Layer
, while being modal and blocking, like the former.Running on Mac the posted code, I get a NPE after dropping over
popupTarget
, that can be easily solved using:Also, given that the drag event is consumed by the dialog, a possible solution could be:
So you could refactor the
setOnDragDone
method, and just create a method that could be called after the dialog is closed as well.EDIT
These are the drag events that both target and source receive once the dnd event has started:
The target receives these events on a drag and drop gesture:
those work exactly the same with JavaFX and Gluon dialogs (at least on Windows. On Mac because of the NPE, using
Platform.runLater()
delays obviously the show Dialog and hide Dialog events, but lets just focus on Windows for now).Right after that last event, the source receives:
but only with a JavaFX dialog.
After some debugging, the reason why the Gluon's Dialog aborts the drag done event can be explained as follows:
The
Scene
class has aDnDGesture
private class:And as it is explained in the comment, it has a lifespan from mouse pressed event to mouse release event.
Using JavaFX built-in dialog, this is displayed in a new Stage and therefore a new Scene. The key here is that this dialog (and all the set of mouse events) is displayed in a new modal stage, so once the dialog is hidden, the primary stage takes the focus again and resumes, finishing properly the dnd gesture as the mouse is released.
But using Gluon's dialog, there is no second stage. Everything happens in the same stage, and once the mouse is released, the
Scene.DnDGesture
becomes null, so when theDRAG_EXITED_TARGET
event happens in the target, the proper call is done to finish the dnd process, but at this pointdndGesture
is null, and that call doesn't reach the source anymore.I don't consider this a bug, but more like a tradeoff, as there are a number of reasons to avoid a second stage/scene on a mobile environment and keep the View/Layer (in one single stage) design.