При перетаскивании элементов из другого приложения в DnD Узел в JavaFX Операционная система или исходное приложение обрабатывают визуальное отображение перетаскиваемых элементов, поскольку они являются источником перетаскиваемых файлов.
Это относится и к этому приложению: пользователь имеет возможность перетаскивать определенные категории файлов, и эти файлы принимаются только в зависимости от их расширений (
Код: Выделить всё
.png
Код
Интерфейс DragAndDropBehavior имеет единственный метод handleDroppedFiles(List files), который будет обрабатывать файлы после их удаления.
Код: Выделить всё
import java.io.File;
import java.util.List;
public interface DragAndDropBehavior {
void handleDroppedFiles(List files);
}
Код: Выделить всё
import java.io.File;
public abstract class BaseDropController implements DragAndDropBehavior {
protected boolean hasAllowedExtension(File f, String... extensions) {
var name = f.getName().toLowerCase();
for (var ext : extensions)
if (name.endsWith(ext))
return true;
return false;
}
protected void notifyError(String message) {
System.err.println(message);
}
}
Код: Выделить всё
import java.io.File;
import java.util.List;
public class ImageDropController extends BaseDropController {
@Override
public void handleDroppedFiles(List files) {
var image = files.stream().filter(f -> hasAllowedExtension(f, ".png", ".jpg", ".jpeg", ".webp")).findFirst();
image.ifPresentOrElse(
file -> {
System.out.println("Dropped file: " + file.getAbsoluteFile());
},
() -> notifyError("No image file found.")
);
}
}
Код: Выделить всё
import javafx.beans.property.*;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import javafx.scene.layout.StackPane;
import java.io.File;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
public final class DragAndDropPane extends StackPane {
private final ObjectProperty acceptedExtensions = new SimpleObjectProperty();
private final ObjectProperty onFilesDropped = new SimpleObjectProperty();
private final BooleanProperty highlight = new SimpleBooleanProperty(false);
public DragAndDropPane() {
getStyleClass().add("drop-pane");
var label = new Label("Drop files here");
setAlignment(label, Pos.CENTER);
getChildren().add(label);
setOnDragOver(e -> {
if (e.getGestureSource() != this && e.getDragboard().hasFiles()) {
if (acceptsAny(e.getDragboard().getFiles())) {
e.acceptTransferModes(TransferMode.MOVE);
highlight.set(true);
}
}
e.consume();
});
setOnDragExited(e -> {
highlight.set(false);
e.consume();
});
setOnDragDropped(e -> {
var dragBoard = e.getDragboard();
boolean success = false;
if (dragBoard.hasFiles() && acceptsAny(dragBoard.getFiles())) {
var handler = getOnFilesDropped();
if (handler != null)
handler.accept(dragBoard.getFiles());
success = true;
}
e.setDropCompleted(success);
e.consume();
});
highlight.addListener((_, _, hi) ->
pseudoClassStateChanged(javafx.css.PseudoClass.getPseudoClass("active"), hi));
}
private boolean acceptsAny(List files) {
var extensions = getAcceptedExtensions();
if (extensions == null || extensions.isEmpty())
return true;
return files.stream().anyMatch(file ->
extensions.stream().anyMatch(extension -> file.getName().toLowerCase().endsWith(extension.toLowerCase()))
);
}
public void setAcceptedExtensions(Set extensions) {
acceptedExtensions.set(extensions);
}
public void setOnFilesDropped(Consumer c) {
onFilesDropped.set(c);
}
public Set getAcceptedExtensions() {
return acceptedExtensions.get();
}
public ObjectProperty acceptedExtensionsProperty() {
return acceptedExtensions;
}
public Consumer getOnFilesDropped() {
return onFilesDropped.get();
}
public ObjectProperty onFilesDroppedProperty() {
return onFilesDropped;
}
}
Код: Выделить всё
ImageDropView
Код: Выделить всё
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.layout.StackPane;
import java.io.IOException;
import java.util.Set;
public final class ImageDropView {
private final Parent root;
@FXML
private DragAndDropPane drop;
@FXML
private StackPane preview;
private final ImageDropController controller = new ImageDropController();
public ImageDropView() {
try {
var loader = new FXMLLoader(getClass().getResource("ImageDropView.fxml"));
loader.setController(this);
this.root = loader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
drop.setAcceptedExtensions(Set.of(".png", ".jpg", ".jpeg", ".webp"));
drop.setOnFilesDropped(controller::handleDroppedFiles);
}
public Parent getRoot() {
return root;
}
}
Код: Выделить всё
Код: Выделить всё
import javafx.scene.Parent;
public final class DropViewFactory {
public static Parent create(MediaType type) {
return switch (type) {
case IMAGE -> new ImageDropView().getRoot();
case VIDEO -> new VideoDropView().getRoot();
};
}
}
Код: Выделить всё
public enum MediaType {IMAGE, VIDEO}
Код: Выделить всё
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MainController {
@FXML
private BorderPane root;
public void openImageDialog() {
open(MediaType.IMAGE, "Import Image");
}
public void openVideoDialog() {
open(MediaType.VIDEO, "Import Video");
}
private void open(MediaType type, String title) {
var stage = new Stage();
stage.setTitle(title);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setScene(new Scene(DropViewFactory.create(type), 900, 600));
stage.show();
}
}
Код: Выделить всё
import javafx.application.Application;
import javafx.stage.Stage;
import test.MainController;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
MainController mainController = new MainController();
mainController.openImageDialog();
}
}
Когда файлы перетаскиваются на DragAndDropPane, система устанавливает значок файла(ов). Например, если перетащить четыре файла, система отобразит форму с уменьшенной непрозрачностью. Я хочу заменить значки одним значком, который отображает количество перетаскиваемых элементов в правом нижнем углу.
В этих двух похожих вопросах (post1, post2) оба хотят одного и того же, но оба имеют перетаскиваемый элемент, поступающий из приложения JavaFX. Кроме того, в документации setDragView это работает, только если источник элемента поступает из приложения.
Подробнее здесь: https://stackoverflow.com/questions/797 ... s-file-sys