2017-10-18 153 views
1

我在拖放操作期间使用弹出对话框。当下降发生时会弹出一个对话框,当它被解散时,事件链应该继续,并且在拖动操作结束时允许发生某些事情。如果弹出对话框是FX,那么没有问题,但如果它是Gluon,则拖动完成操作不会发生。对话框导致拖动完成事件不传播

下面是一个示例的代码:在其上的背景变为红色

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(); 
     }); 
    } 
} 

源应被拖动。拖动操作完成后,背景应该恢复为默认值。常规放置目标什么都不做,颜色变化起作用。但是,当弹出目标时弹出对话框,当它关闭时,颜色只会改变FX对话框而不改变胶子对话框。将popup1.showAndWait();更改为popup2

如果重要的是这样的应用程序类

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); 
    } 
} 

,这是gradle这个构建文件:

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' 
} 

也发生在compile 'com.gluonhq:charm:4.3.7'和4.4.0。

在Java 8 b141上运行。为什么会发生?这是一个错误?

+0

在Dialog javadoc页面上,BTW命令行'dialog.setContent(new Label(“只是一个普通对话框,简单而简单”);'缺少'''''。 – Mark

+0

当您在桌面上使用'popup2'运行时,您是否看到NPE? –

+0

@JoséPereda号我还在事件处理程序中加入了try catch,并且没有发现任何东西。我应该看一个特定的地方吗? – Mark

回答

1

JavaFX内置对话框和Gluon对话框不一样。事实上,后者从Layer延伸,而模态和阻塞,如前者。

在Mac上运行张贴代码,我得到一个NPE下降超过popupTarget后,可以使用容易解决:

Platform.runLater(() -> popup2.showAndWait()); 

此外,鉴于拖动事件是由对话框,一个可能的解决方案消耗可能是:

Platform.runLater(() -> 
    popup2.showAndWait() 
     .ifPresent(r -> 
      root.setBackground(new Background(new BackgroundFill(null, null, null))))); 

所以,你可以重构setOnDragDone法,只需创建一个对话框被关闭以及之后可能被调用的方法。

编辑

这些是两个目标和源收到一旦DND事件已开始拖动事件:

目标接收拖累这些事件拖放手势:

DRAG_OVER 
DRAG_OVER 
... // until drop is done: 
// show Dialog 
... 
// hide Dialog 
DRAG_DROPPED 
DRAG_EXITED 
DRAG_EXITED_TARGET 

这些工作与JavaFX和Gluon对话框完全相同(至少在Windows上)。在Mac上,由于NPE,使用Platform.runLater()显然延迟显示对话框并隐藏对话事件,但现在让我们只关注Windows)。

正确的,最后一场比赛后,源接收:

DRAG_DONE 

但只有一个JavaFX对话框。

一些调试后,之所以胶子的对话中止拖拽完成事件可以解释如下:

Scene类有一个DnDGesture私有类:

/** 
* A Drag and Drop gesture has a lifespan that lasts from mouse 
* PRESSED event to mouse RELEASED event. 
*/ 
class DnDGesture { 
    ... 
} 

而且因为它是解释在评论中,它具有从鼠标按下事件到鼠标释放事件的使用寿命。

使用JavaFX内置对话框,这会显示在新的舞台上,因此会显示新的场景。这里的关键是,这个对话框(以及所有的鼠标事件集合)都会在一个新的模式阶段中显示出来,所以一旦对话框被隐藏起来,主阶段就会重新获得焦点并恢复,并且正确地完成dnd手势,因为鼠标是释放。

但使用胶子的对话框,没有第二阶段。一切发生在同一阶段,一旦鼠标被释放,Scene.DnDGesture变为空,所以当DRAG_EXITED_TARGET事件发生在目标中时,正确的调用完成了dnd过程,但此时dndGesture为空,通话不再来源。

我不认为这是一个错误,但更像是一种折衷,因为有很多原因可以避免移动环境中的第二阶段/场景,并保持View/Layer(在单一阶段中)设计。

+0

是的,目前我的解决方法是调用拖放完成的事件处理程序,拖放内容类似于你在第二个示例中只做了runLater,因为我没有收到任何错误。胶子对话框的行为不是像本地人那样行事?这会被认为是一个错误? – Mark

+0

我已经编辑了我的答案,并进一步解释了发生了什么,以及为什么我不认为它是一个错误。 –