Beim Ziehen von Elementen aus einer anderen Anwendung in den DnD-Knoten in JavaFX Das Betriebssystem oder die Quellanwendung übernimmt die visuelle Anzeige der gezogenen Elemente, da es die Quelle der gezogenen Datei(en) ist.
Dies ist bei dieser App der Fall: Der Benutzer hat die Möglichkeit, bestimmte Kategorien von Dateien per Drag-and-Drop zu verschieben, und diese Dateien werden nur aufgrund ihrer Erweiterungen akzeptiert (
Code: Select all
.pngDer Code
Die Schnittstelle DragAndDropBehavior verfügt über eine einzelne Methode handleDroppedFiles(List files), die die Dateien nach dem Ablegen verarbeitet.
Code: Select all
import java.io.File;
import java.util.List;
public interface DragAndDropBehavior {
void handleDroppedFiles(List files);
}
Code: Select all
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);
}
}
Code: Select all
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.")
);
}
}
Code: Select all
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;
}
}
Code: Select all
ImageDropViewCode: Select all
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;
}
}
Code: Select all
Code: Select all
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();
};
}
}
Code: Select all
public enum MediaType {IMAGE, VIDEO}
Code: Select all
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();
}
}
Code: Select all
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();
}
}
Wenn die Datei(en) auf das DragAndDropPane gezogen werden, legt das System das Symbol der Datei(en) fest. Wenn beispielsweise vier Dateien gezogen werden, zeigt das System das Formular mit reduzierter Deckkraft an. Ich möchte die Symbole durch ein einzelnes Symbol ersetzen, das die Anzahl der Elemente anzeigt, die in der unteren rechten Ecke gezogen werden.
In diesen beiden ähnlichen Fragen (Beitrag 1, Beitrag 2) wollen beide dasselbe, aber beide haben ein ziehbares Element, das aus der JavaFX-Anwendung stammt. Außerdem funktioniert es in den setDragView-Dokumenten nur, wenn die Quelle des Elements aus der App stammt.
Mobile version