使用 JavaFX 将图像拖到 window 之外
Drag Image outside the window with JavaFX
大家,
我想在我的应用程序中插入一个可以从应用程序中拖放的图形。一旦图形在 window 之外发布,应打开未解码/透明 window,其中仅显示此图形。
Stage newStage = new Stage();
StackPane stack = new StackPane();
ImageView imageView = new ImageView(new Image(this.getClass().getResourceAsStream(InBoxEnum.Graphic.INBOXLOGO.getFilename())));
stack.getChildren().add(imageView);
imageView.setOnDragDetected(event -> {
Dragboard dragboard = imageView.startDragAndDrop(TransferMode.MOVE);
dragboard.setDragView(imageView.snapshot(null, null));
ClipboardContent content = new ClipboardContent();
content.put(DRAGGABLE_INBOX_TYPE, "dontcare");
dragboard.setContent(content);
event.consume();
});
imageView.setOnDragDone(event -> {
System.out.println(event.getScreenX());
System.out.println(event.getScreenY());
});
Scene scene = new Scene(stack, 500, 500);
newStage.setScene(scene);
newStage.show();
DragDetected 事件到目前为止也没有问题。
问题是在 dragDone 事件中,鼠标的位置始终为 0,我无法判断鼠标是在我的应用程序内部还是外部。如果在应用程序内松开鼠标,则不会发生任何事情。
我也试过机器人 Class,但我总是得到一个静态的奇怪 x/y 位置。
我正在使用JAVA11(采纳JDK)。
感谢您的帮助
使用 Robot
对我来说效果很好(Oracle JDK 11 + JavaFX 12)。由于您实际上不想拖放任何图像数据,因此您可以通过立即创建一个新舞台并使用 ImageView
的 MOUSE_DRAGGED
更新 [=17] 的位置来简单地解决此问题=]:
Stage newStage = new Stage();
StackPane stack = new StackPane();
ImageView imageView = new ImageView(new Image(...));
stack.getChildren().add(imageView);
class DragHandler implements EventHandler<MouseEvent> {
Stage dragTarget;
@Override
public void handle(MouseEvent event) {
if (dragTarget != null) {
// move stage
dragTarget.setX(event.getScreenX());
dragTarget.setY(event.getScreenY());
event.consume();
}
}
}
final DragHandler dragHandler = new DragHandler();
imageView.setOnDragDetected(event -> {
// init stage at half transparency
Group root = new Group(new ImageView(imageView.getImage()));
root.setOpacity(0.5);
Scene displayScene = new Scene(root);
displayScene.setFill(null);
Stage displayStage = new Stage();
displayStage.initStyle(StageStyle.TRANSPARENT);
displayStage.setScene(displayScene);
displayStage.setX(event.getScreenX());
displayStage.setY(event.getScreenY());
displayStage.show();
dragHandler.dragTarget = displayStage;
event.consume();
});
imageView.setOnMouseDragged(dragHandler);
imageView.setOnMouseReleased(event -> {
if (dragHandler.dragTarget != null) {
if (stack.contains(event.getX(), event.getY())) { // check, if drop happened inside the bounds of the scene root
dragHandler.dragTarget.hide();
} else {
// make stage fully opaque & cleanup
dragHandler.dragTarget.getScene().getRoot().setOpacity(1);
imageView.setImage(null);
}
dragHandler.dragTarget = null;
event.consume();
}
});
Scene scene = new Scene(stack, 500, 500);
newStage.setScene(scene);
newStage.show();
建议的解决方案基于 。
主要更改封装在 withinBounds
方法中,该方法用于定义拖动是否在 window 范围内结束。此方法基于this答案:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
public class DragOut extends Application {
@Override
public void start(Stage primaryStage) {
ImageView imageView = new ImageView("https://findicons.com/files/icons/345/summer/128/cake.png");
StackPane stack = new StackPane(imageView);
DragHandler dragHandler = new DragHandler();
imageView.setOnDragDetected(event -> {
Stage displayStage = makeNewStage(imageView.getImage());
displayStage.setX(event.getScreenX());
displayStage.setY(event.getScreenY());
dragHandler.setStage(displayStage);
displayStage.show();
event.consume();
});
imageView.setOnMouseDragged(dragHandler);
imageView.setOnMouseReleased(event -> {
if (! withinBounds(event, imageView.getScene().getWindow()) && dragHandler.dragTarget != null) {
// make stage fully opaque & cleanup
dragHandler.showStage();
imageView.setImage(null);
event.consume();
}else{
dragHandler.closeStage();
}
dragHandler.setStage(null);
});
Scene scene = new Scene(stack, 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
private Stage makeNewStage(Image image) {
Group root = new Group(new ImageView(image));
root.setOpacity(0.5); // init stage at half transparency
Stage displayStage = new Stage(StageStyle.TRANSPARENT);
displayStage.setScene(new Scene(root, null));
return displayStage;
}
private boolean withinBounds(MouseEvent event, Window window) {
Point2D mouseLoc = new Point2D(event.getScreenX(), event.getScreenY());
Rectangle2D windowBounds = new Rectangle2D(window.getX(), window.getY(),
window.getWidth(), window.getHeight());
return windowBounds.contains(mouseLoc);
}
class DragHandler implements EventHandler<MouseEvent> {
private Stage dragTarget;
@Override
public void handle(MouseEvent event) {
if (dragTarget != null) {
// move stage
dragTarget.setX(event.getScreenX());
dragTarget.setY(event.getScreenY());
event.consume();
}
}
void setStage(Stage stage){
dragTarget = stage;
}
void showStage(){
if (dragTarget != null) {
dragTarget.getScene().getRoot().setOpacity(1);
}
}
void closeStage(){
if (dragTarget != null) {
dragTarget.close();
}
}
}
public static void main(final String[] args) {
launch(args);
}
}
大家,
我想在我的应用程序中插入一个可以从应用程序中拖放的图形。一旦图形在 window 之外发布,应打开未解码/透明 window,其中仅显示此图形。
Stage newStage = new Stage();
StackPane stack = new StackPane();
ImageView imageView = new ImageView(new Image(this.getClass().getResourceAsStream(InBoxEnum.Graphic.INBOXLOGO.getFilename())));
stack.getChildren().add(imageView);
imageView.setOnDragDetected(event -> {
Dragboard dragboard = imageView.startDragAndDrop(TransferMode.MOVE);
dragboard.setDragView(imageView.snapshot(null, null));
ClipboardContent content = new ClipboardContent();
content.put(DRAGGABLE_INBOX_TYPE, "dontcare");
dragboard.setContent(content);
event.consume();
});
imageView.setOnDragDone(event -> {
System.out.println(event.getScreenX());
System.out.println(event.getScreenY());
});
Scene scene = new Scene(stack, 500, 500);
newStage.setScene(scene);
newStage.show();
DragDetected 事件到目前为止也没有问题。
问题是在 dragDone 事件中,鼠标的位置始终为 0,我无法判断鼠标是在我的应用程序内部还是外部。如果在应用程序内松开鼠标,则不会发生任何事情。
我也试过机器人 Class,但我总是得到一个静态的奇怪 x/y 位置。
我正在使用JAVA11(采纳JDK)。
感谢您的帮助
使用 Robot
对我来说效果很好(Oracle JDK 11 + JavaFX 12)。由于您实际上不想拖放任何图像数据,因此您可以通过立即创建一个新舞台并使用 ImageView
的 MOUSE_DRAGGED
更新 [=17] 的位置来简单地解决此问题=]:
Stage newStage = new Stage();
StackPane stack = new StackPane();
ImageView imageView = new ImageView(new Image(...));
stack.getChildren().add(imageView);
class DragHandler implements EventHandler<MouseEvent> {
Stage dragTarget;
@Override
public void handle(MouseEvent event) {
if (dragTarget != null) {
// move stage
dragTarget.setX(event.getScreenX());
dragTarget.setY(event.getScreenY());
event.consume();
}
}
}
final DragHandler dragHandler = new DragHandler();
imageView.setOnDragDetected(event -> {
// init stage at half transparency
Group root = new Group(new ImageView(imageView.getImage()));
root.setOpacity(0.5);
Scene displayScene = new Scene(root);
displayScene.setFill(null);
Stage displayStage = new Stage();
displayStage.initStyle(StageStyle.TRANSPARENT);
displayStage.setScene(displayScene);
displayStage.setX(event.getScreenX());
displayStage.setY(event.getScreenY());
displayStage.show();
dragHandler.dragTarget = displayStage;
event.consume();
});
imageView.setOnMouseDragged(dragHandler);
imageView.setOnMouseReleased(event -> {
if (dragHandler.dragTarget != null) {
if (stack.contains(event.getX(), event.getY())) { // check, if drop happened inside the bounds of the scene root
dragHandler.dragTarget.hide();
} else {
// make stage fully opaque & cleanup
dragHandler.dragTarget.getScene().getRoot().setOpacity(1);
imageView.setImage(null);
}
dragHandler.dragTarget = null;
event.consume();
}
});
Scene scene = new Scene(stack, 500, 500);
newStage.setScene(scene);
newStage.show();
建议的解决方案基于
主要更改封装在 withinBounds
方法中,该方法用于定义拖动是否在 window 范围内结束。此方法基于this答案:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
public class DragOut extends Application {
@Override
public void start(Stage primaryStage) {
ImageView imageView = new ImageView("https://findicons.com/files/icons/345/summer/128/cake.png");
StackPane stack = new StackPane(imageView);
DragHandler dragHandler = new DragHandler();
imageView.setOnDragDetected(event -> {
Stage displayStage = makeNewStage(imageView.getImage());
displayStage.setX(event.getScreenX());
displayStage.setY(event.getScreenY());
dragHandler.setStage(displayStage);
displayStage.show();
event.consume();
});
imageView.setOnMouseDragged(dragHandler);
imageView.setOnMouseReleased(event -> {
if (! withinBounds(event, imageView.getScene().getWindow()) && dragHandler.dragTarget != null) {
// make stage fully opaque & cleanup
dragHandler.showStage();
imageView.setImage(null);
event.consume();
}else{
dragHandler.closeStage();
}
dragHandler.setStage(null);
});
Scene scene = new Scene(stack, 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
private Stage makeNewStage(Image image) {
Group root = new Group(new ImageView(image));
root.setOpacity(0.5); // init stage at half transparency
Stage displayStage = new Stage(StageStyle.TRANSPARENT);
displayStage.setScene(new Scene(root, null));
return displayStage;
}
private boolean withinBounds(MouseEvent event, Window window) {
Point2D mouseLoc = new Point2D(event.getScreenX(), event.getScreenY());
Rectangle2D windowBounds = new Rectangle2D(window.getX(), window.getY(),
window.getWidth(), window.getHeight());
return windowBounds.contains(mouseLoc);
}
class DragHandler implements EventHandler<MouseEvent> {
private Stage dragTarget;
@Override
public void handle(MouseEvent event) {
if (dragTarget != null) {
// move stage
dragTarget.setX(event.getScreenX());
dragTarget.setY(event.getScreenY());
event.consume();
}
}
void setStage(Stage stage){
dragTarget = stage;
}
void showStage(){
if (dragTarget != null) {
dragTarget.getScene().getRoot().setOpacity(1);
}
}
void closeStage(){
if (dragTarget != null) {
dragTarget.close();
}
}
}
public static void main(final String[] args) {
launch(args);
}
}