Added FileUtils / TempDirectory from EmailTool.
Moved FileUtils to io package.
This commit is contained in:
+85
-1
@@ -1,15 +1,99 @@
|
||||
# TODO
|
||||
|
||||
- SimpleListProperty auch nutzen bei Collections!
|
||||
|
||||
# Ideen
|
||||
|
||||
# Bindings
|
||||
|
||||
Bindngs kommen über ein spezielles Binding Control, das dann notwendige Bindings beinhaltet.
|
||||
|
||||
Da kann dann auch eine eigene Logik zur Erkennung des Bindings erfolgen oder zusätziche Informationen bezüglich notwendiger Elemente in dem ViewModel
|
||||
Da kann dann auch eine eigene Logik zur Erkennung des Bindings erfolgen oder zusätziche Informationen bezüglich
|
||||
notwendiger Elemente in dem ViewModel
|
||||
|
||||
## Bidirektional Converter für Bindings
|
||||
|
||||
```Java
|
||||
StringConverter<Instant> converter = new StringConverter<>() {
|
||||
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
|
||||
|
||||
@Override
|
||||
public String toString(Instant instant) {
|
||||
return instant == null ? "" : formatter.format(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant fromString(String string) {
|
||||
if (string == null || string.isBlank()) return null;
|
||||
try {
|
||||
LocalDateTime dateTime = LocalDateTime.parse(string, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
return dateTime.atZone(ZoneId.systemDefault()).toInstant();
|
||||
} catch (DateTimeParseException e) {
|
||||
// Optional: Fehlermeldung anzeigen
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Binding einrichten:
|
||||
Bindings.
|
||||
|
||||
bindBidirectional(textField.textProperty(),instantProperty,converter);
|
||||
```
|
||||
|
||||
Overloads von bindBidirectional
|
||||
bindBidirectional(Property<String>, Property<?>, Format)
|
||||
bindBidirectional(Property<String>, Property<T>, StringConverter<T>)
|
||||
bindBidirectional(Property<T>, Property<T>)
|
||||
|
||||
## Unidirektional mit Bindings.createStringBinding()
|
||||
|
||||
```Java
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
|
||||
|
||||
textField.
|
||||
|
||||
textProperty().
|
||||
|
||||
bind(Bindings.createStringBinding(
|
||||
() ->{
|
||||
|
||||
Instant instant = instantProperty.get();
|
||||
return instant ==null?"":formatter.
|
||||
|
||||
format(instant);
|
||||
},
|
||||
instantProperty
|
||||
));
|
||||
```
|
||||
|
||||
Bindings:
|
||||
|
||||
- BooleanBinding
|
||||
- DoubleBinding
|
||||
- FloatBinding
|
||||
- IntegerBinding
|
||||
- LongBinding
|
||||
- StringBinding
|
||||
- ObjectBinding
|
||||
- NumberBinding
|
||||
|
||||
Bindings haben Methoden, die dann weitere Bindings erzeugen.
|
||||
==> Parameter der Methode: Property, Observable und einer Methode, die ein Binding erstellt und das ViewModel<?>, das
|
||||
dann genutzt werden kann, um weitere Properties zu holen ==> Erzeugung von neuen Properties.
|
||||
|
||||
Diese BindingCreators haben Namen, PropertyTyp und ein BindingType.
|
||||
|
||||
# FXMLComponent
|
||||
|
||||
Dient dem Laden einer Komponente und bekommt dazu das fxml, die Daten und ggf. auch eine ModelView.
|
||||
|
||||
# ModelView generieren
|
||||
|
||||
Damit eine ModelView nicht ständig manuell generiert werden muss, ist hier ggf. etwas zu generieren?
|
||||
Ggf. eine eigenes Beschreibungssprache?
|
||||
|
||||
# Aufbau einer Validierung
|
||||
|
||||
- gehört in das ViewModel
|
||||
-
|
||||
@@ -1,12 +1,20 @@
|
||||
package de.neitzel.fx.component;
|
||||
|
||||
import de.neitzel.fx.component.controls.Binding;
|
||||
import de.neitzel.fx.component.controls.FxmlComponent;
|
||||
import de.neitzel.fx.component.model.BindingData;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.layout.Pane;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -16,13 +24,35 @@ import java.util.Map;
|
||||
/**
|
||||
* ComponentLoader is responsible for loading JavaFX FXML components and binding
|
||||
* them to automatically generated ViewModels based on simple POJO models.
|
||||
* <p>
|
||||
* It parses custom NFX attributes in FXML to bind UI elements to properties in the ViewModel,
|
||||
* and supports recursive loading of subcomponents.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ComponentLoader {
|
||||
private Map<String, Map<String, String>> nfxBindingMap = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private Object controller;
|
||||
|
||||
public Parent load(URL fxmlPath) {
|
||||
return load(null, fxmlPath);
|
||||
}
|
||||
|
||||
public Parent load(String fxmlPath) {
|
||||
return load(null, fxmlPath);
|
||||
}
|
||||
|
||||
public Parent load(Object model, URL fxmlPath) {
|
||||
try {
|
||||
AutoViewModel<?> viewModel = new AutoViewModel<>(model);
|
||||
FXMLLoader loader = new FXMLLoader(fxmlPath);
|
||||
loader.setControllerFactory(type -> new ComponentController(viewModel));
|
||||
Parent root = loader.load();
|
||||
controller = loader.getController();
|
||||
return root;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("unable to load fxml: " + fxmlPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an FXML file and binds its elements to a generated ViewModel
|
||||
* based on the given POJO model.
|
||||
@@ -32,83 +62,116 @@ public class ComponentLoader {
|
||||
* @return the root JavaFX node loaded from FXML
|
||||
*/
|
||||
public Parent load(Object model, String fxmlPath) {
|
||||
return load(model, getClass().getResource(fxmlPath));
|
||||
}
|
||||
|
||||
public static <T extends Parent> T load(URL fxmlUrl, Object controller, String nothing) throws IOException {
|
||||
FXMLLoader loader = new FXMLLoader(fxmlUrl);
|
||||
loader.setController(controller);
|
||||
T root = loader.load();
|
||||
|
||||
Map<String, Object> namespace = loader.getNamespace();
|
||||
|
||||
// Nach allen BindingControls suchen:
|
||||
List<Binding> bindingControls = collectAllNodes(root).stream()
|
||||
.filter(n -> n instanceof Binding)
|
||||
.map(n -> (Binding) n)
|
||||
.toList();
|
||||
|
||||
for (Binding bc : bindingControls) {
|
||||
evaluateBindings(bc.getBindings(), namespace);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private static <T> void bindBidirectionalSafe(@NotNull Property<T> source, Property<?> target) {
|
||||
try {
|
||||
AutoViewModel<?> viewModel = new AutoViewModel<>(model);
|
||||
String cleanedUri = preprocessNfxAttributes(fxmlPath);
|
||||
FXMLLoader loader = new FXMLLoader(new URL(cleanedUri));
|
||||
loader.setControllerFactory(type -> new ComponentController(viewModel));
|
||||
Parent root = loader.load();
|
||||
processNfxBindings(root, viewModel, loader);
|
||||
return root;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("unable to load fxml: " + fxmlPath, e);
|
||||
Property<T> targetCasted = (Property<T>) target;
|
||||
source.bindBidirectional(targetCasted);
|
||||
} catch (ClassCastException e) {
|
||||
log.error("⚠️ Typkonflikt beim Binding: %s ⇄ %s%n", source.getClass(), target.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes all UI elements for NFX binding attributes and applies
|
||||
* the appropriate bindings to the ViewModel.
|
||||
*
|
||||
* @param root the root node of the loaded FXML hierarchy
|
||||
* @param viewModel the generated ViewModel to bind against
|
||||
*/
|
||||
private void processNfxBindings(Parent root, AutoViewModel<?> viewModel, FXMLLoader loader) {
|
||||
walkNodes(root, node -> {
|
||||
var nfx = lookupNfxAttributes(node, loader);
|
||||
String target = nfx.get("nfx:target");
|
||||
String direction = nfx.get("nfx:direction");
|
||||
String source = nfx.get("nfx:source");
|
||||
|
||||
if (target != null && direction != null) {
|
||||
Property<?> vmProp = viewModel.getProperty(target);
|
||||
bindNodeToProperty(node, vmProp, direction);
|
||||
}
|
||||
|
||||
if (source != null) {
|
||||
Object subModel = ((Property<?>) viewModel.getProperty(target)).getValue();
|
||||
Parent subComponent = load(subModel, source);
|
||||
if (node instanceof Pane pane) {
|
||||
pane.getChildren().setAll(subComponent);
|
||||
}
|
||||
}
|
||||
});
|
||||
private static <T> void bindSafe(@NotNull Property<T> source, Property<?> target) {
|
||||
try {
|
||||
Property<T> targetCasted = (Property<T>) target;
|
||||
source.bind(targetCasted);
|
||||
} catch (ClassCastException e) {
|
||||
log.error("⚠️ Typkonflikt beim Binding: %s ⇄ %s%n", source.getClass(), target.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively walks all nodes in the scene graph starting from the root,
|
||||
* applying the given consumer to each node.
|
||||
*
|
||||
* @param root the starting node
|
||||
* @param consumer the consumer to apply to each node
|
||||
*/
|
||||
private void walkNodes(Parent root, java.util.function.Consumer<javafx.scene.Node> consumer) {
|
||||
consumer.accept(root);
|
||||
if (root instanceof Pane pane) {
|
||||
for (javafx.scene.Node child : pane.getChildren()) {
|
||||
if (child instanceof Parent p) {
|
||||
walkNodes(p, consumer);
|
||||
} else {
|
||||
consumer.accept(child);
|
||||
private static void evaluateBindings(List<BindingData> bindings, Map<String, Object> namespace) {
|
||||
for (var binding : bindings) {
|
||||
try {
|
||||
Object source = resolveExpression(binding.getSource(), namespace);
|
||||
Object target = resolveExpression(binding.getTarget(), namespace);
|
||||
|
||||
if (source instanceof Property && target instanceof Property) {
|
||||
Property<?> sourceProp = (Property<?>) source;
|
||||
Property<?> targetProp = (Property<?>) target;
|
||||
|
||||
Class<?> sourceType = getPropertyType(sourceProp);
|
||||
Class<?> targetType = getPropertyType(targetProp);
|
||||
|
||||
boolean bindableForward = targetType.isAssignableFrom(sourceType);
|
||||
boolean bindableBackward = sourceType.isAssignableFrom(targetType);
|
||||
|
||||
switch (binding.getDirection().toLowerCase()) {
|
||||
case "bidirectional":
|
||||
if (bindableForward && bindableBackward) {
|
||||
bindBidirectionalSafe(sourceProp, targetProp);
|
||||
} else {
|
||||
log.error("⚠️ Kann bidirektionales Binding nicht durchführen: Typen inkompatibel (%s ⇄ %s)%n", sourceType, targetType);
|
||||
}
|
||||
break;
|
||||
case "unidirectional":
|
||||
default:
|
||||
if (bindableForward) {
|
||||
bindSafe(sourceProp, targetProp);
|
||||
} else {
|
||||
log.error("⚠️ Kann unidirektionales Binding nicht durchführen: %s → %s nicht zuweisbar%n", sourceType, targetType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Fehler beim Binding: " + binding.getSource() + " → " + binding.getTarget(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts custom NFX attributes from a node's properties map.
|
||||
* These attributes are expected to be in the format "nfx:..." and hold string values.
|
||||
*
|
||||
* @param node the node to inspect
|
||||
* @return a map of NFX attribute names to values
|
||||
*/
|
||||
private Map<String, String> extractNfxAttributes(javafx.scene.Node node) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
node.getProperties().forEach((k, v) -> {
|
||||
if (k instanceof String key && key.startsWith("nfx:") && v instanceof String value) {
|
||||
result.put(key, value);
|
||||
private static Class<?> getPropertyType(Property<?> prop) {
|
||||
try {
|
||||
Method getter = prop.getClass().getMethod("get");
|
||||
return getter.getReturnType();
|
||||
} catch (Exception e) {
|
||||
return Object.class; // Fallback
|
||||
}
|
||||
}
|
||||
|
||||
private static Object resolveExpression(@NotNull String expr, @NotNull Map<String, Object> namespace) throws Exception {
|
||||
// z.B. "viewModel.username"
|
||||
String[] parts = expr.split("\\.");
|
||||
Object current = namespace.get(parts[0]);
|
||||
for (int i = 1; i < parts.length; i++) {
|
||||
String getter = "get" + Character.toUpperCase(parts[i].charAt(0)) + parts[i].substring(1);
|
||||
current = current.getClass().getMethod(getter).invoke(current);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
private static @NotNull List<Node> collectAllNodes(Node root) {
|
||||
List<Node> nodes = new ArrayList<>();
|
||||
nodes.add(root);
|
||||
if (root instanceof Parent parent && !(root instanceof FxmlComponent)) {
|
||||
for (Node child : parent.getChildrenUnmodifiable()) {
|
||||
nodes.addAll(collectAllNodes(child));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,61 +191,4 @@ public class ComponentLoader {
|
||||
}
|
||||
// Additional control types (e.g., CheckBox, ComboBox) can be added here
|
||||
}
|
||||
|
||||
private String preprocessNfxAttributes(String fxmlPath) {
|
||||
try {
|
||||
nfxBindingMap.clear();
|
||||
var factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
|
||||
var builder = factory.newDocumentBuilder();
|
||||
var doc = builder.parse(getClass().getResourceAsStream(fxmlPath));
|
||||
var all = doc.getElementsByTagName("*");
|
||||
|
||||
int autoId = 0;
|
||||
for (int i = 0; i < all.getLength(); i++) {
|
||||
var el = (org.w3c.dom.Element) all.item(i);
|
||||
Map<String, String> nfxAttrs = new HashMap<>();
|
||||
var attrs = el.getAttributes();
|
||||
|
||||
List<String> toRemove = new ArrayList<>();
|
||||
for (int j = 0; j < attrs.getLength(); j++) {
|
||||
var attr = (org.w3c.dom.Attr) attrs.item(j);
|
||||
if (attr.getName().startsWith("nfx:")) {
|
||||
nfxAttrs.put(attr.getName(), attr.getValue());
|
||||
toRemove.add(attr.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (!nfxAttrs.isEmpty()) {
|
||||
String fxid = el.getAttribute("fx:id");
|
||||
if (fxid == null || fxid.isBlank()) {
|
||||
fxid = "auto_id_" + (++autoId);
|
||||
el.setAttribute("fx:id", fxid);
|
||||
}
|
||||
nfxBindingMap.put(fxid, nfxAttrs);
|
||||
toRemove.forEach(el::removeAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
// Speichere das bereinigte Dokument als temporäre Datei
|
||||
File tempFile = File.createTempFile("cleaned_fxml", ".fxml");
|
||||
tempFile.deleteOnExit();
|
||||
var transformer = javax.xml.transform.TransformerFactory.newInstance().newTransformer();
|
||||
transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes");
|
||||
transformer.transform(new javax.xml.transform.dom.DOMSource(doc),
|
||||
new javax.xml.transform.stream.StreamResult(tempFile));
|
||||
|
||||
return tempFile.toURI().toString();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Preprocessing failed for: " + fxmlPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> lookupNfxAttributes(javafx.scene.Node node, FXMLLoader loader) {
|
||||
String fxid = loader.getNamespace().entrySet().stream()
|
||||
.filter(e -> e.getValue() == node)
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst().orElse(null);
|
||||
if (fxid == null) return Map.of();
|
||||
return nfxBindingMap.getOrDefault(fxid, Map.of());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ import javafx.scene.layout.Region;
|
||||
* of {@link BindingData} objects. It extends the {@link Region} class and
|
||||
* provides functionality to bind and monitor connections between source
|
||||
* and target properties.
|
||||
*
|
||||
* <p>
|
||||
* The primary purpose of this control is to maintain an observable list
|
||||
* of bindings, allowing developers to track or adjust the linked properties
|
||||
* dynamically.
|
||||
*
|
||||
* <p>
|
||||
* The internal list of bindings is implemented as an {@link ObservableList},
|
||||
* allowing property change notifications to be easily monitored for UI
|
||||
* updates or other reactive behaviors.
|
||||
*
|
||||
* <p>
|
||||
* This class serves as an organizational component and does not provide
|
||||
* any user interaction by default.
|
||||
*/
|
||||
@@ -28,17 +28,32 @@ public class Binding extends Region {
|
||||
* Represents an observable list of {@link BindingData} objects contained within the
|
||||
* {@link Binding} instance. This list is utilized to manage and monitor
|
||||
* the bindings between source and target properties dynamically.
|
||||
*
|
||||
* <p>
|
||||
* The list is implemented as an {@link ObservableList}, allowing changes in the
|
||||
* collection to be observed and reacted to, such as triggering UI updates or
|
||||
* responding to binding modifications.
|
||||
*
|
||||
* <p>
|
||||
* This field is initialized as an empty list using {@link FXCollections#observableArrayList()}.
|
||||
* It is declared as final to ensure its reference cannot be changed, while the
|
||||
* contents of the list remain mutable.
|
||||
*/
|
||||
private final ObservableList<BindingData> bindings = FXCollections.observableArrayList();
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the BindingControl class.
|
||||
* <p>
|
||||
* This default constructor initializes the BindingControl without
|
||||
* any pre-configured bindings. The instance will contain an empty
|
||||
* {@link ObservableList} of {@link BindingData} objects, which can later
|
||||
* be populated as needed.
|
||||
* <p>
|
||||
* The constructor does not perform additional setup or initialization,
|
||||
* allowing the class to be extended or customized as necessary.
|
||||
*/
|
||||
public Binding() {
|
||||
// Empty, the ComponentLoader is used to work on the bindings.
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the observable list of {@code Binding} objects associated with this control.
|
||||
* The returned list allows monitoring and management of the bindings maintained
|
||||
@@ -49,19 +64,4 @@ public class Binding extends Region {
|
||||
public ObservableList<BindingData> getBindings() {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the BindingControl class.
|
||||
*
|
||||
* This default constructor initializes the BindingControl without
|
||||
* any pre-configured bindings. The instance will contain an empty
|
||||
* {@link ObservableList} of {@link BindingData} objects, which can later
|
||||
* be populated as needed.
|
||||
*
|
||||
* The constructor does not perform additional setup or initialization,
|
||||
* allowing the class to be extended or customized as necessary.
|
||||
*/
|
||||
public Binding() {
|
||||
// Absichtlich leer – wird später "ausgewertet"
|
||||
}
|
||||
}
|
||||
@@ -9,27 +9,16 @@ import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FxmlComponent extends StackPane {
|
||||
|
||||
private final StringProperty fxml = new SimpleStringProperty();
|
||||
|
||||
private final StringProperty direction = new SimpleStringProperty("unidirectional");
|
||||
|
||||
private final ObjectProperty<Object> data = new SimpleObjectProperty<>();
|
||||
|
||||
public StringProperty fxmlProperty() { return fxml; }
|
||||
public String getFxml() { return fxml.get(); }
|
||||
public void setFxml(String fxml) { this.fxml.set(fxml); }
|
||||
|
||||
public StringProperty directionProperty() { return direction; }
|
||||
public String getDirection() { return direction.get(); }
|
||||
public void setDirection(String direction) { this.direction.set(direction); }
|
||||
|
||||
public ObjectProperty<Object> dataProperty() { return data; }
|
||||
public Object getData() { return data.get(); }
|
||||
public void setData(Object data) { this.data.set(data); }
|
||||
|
||||
public FxmlComponent() {
|
||||
fxml.addListener((obs, oldVal, newVal) -> load());
|
||||
data.addListener((obs, oldVal, newVal) -> injectData());
|
||||
@@ -37,20 +26,14 @@ public class FxmlComponent extends StackPane {
|
||||
|
||||
private void load() {
|
||||
if (getFxml() == null || getFxml().isBlank()) return;
|
||||
try {
|
||||
ComponentLoader loader = new ComponentLoader();
|
||||
// Option: ControllerFactory verwenden, wenn nötig
|
||||
Parent content = loader.load(getClass().getResource(getFxml()));
|
||||
ComponentLoader loader = new ComponentLoader();
|
||||
Parent content = loader.load(getClass().getResource(getFxml()));
|
||||
|
||||
getChildren().setAll(content);
|
||||
getChildren().setAll(content);
|
||||
|
||||
Object controller = loader.getController();
|
||||
if (controller != null && getData() != null) {
|
||||
injectDataToController(controller, getData());
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Object controller = loader.getController();
|
||||
if (controller != null && getData() != null) {
|
||||
injectDataToController(controller, getData());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +46,22 @@ public class FxmlComponent extends StackPane {
|
||||
}
|
||||
}
|
||||
|
||||
public String getFxml() {
|
||||
return fxml.get();
|
||||
}
|
||||
|
||||
public void setFxml(String fxml) {
|
||||
this.fxml.set(fxml);
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return data.get();
|
||||
}
|
||||
|
||||
public void setData(Object data) {
|
||||
this.data.set(data);
|
||||
}
|
||||
|
||||
private void injectDataToController(Object controller, Object dataObject) {
|
||||
// Daten-Objekt per Reflection zuweisen
|
||||
// Beispiel: Controller hat `setData(User data)`
|
||||
@@ -86,5 +85,25 @@ public class FxmlComponent extends StackPane {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringProperty fxmlProperty() {
|
||||
return fxml;
|
||||
}
|
||||
|
||||
public StringProperty directionProperty() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public String getDirection() {
|
||||
return direction.get();
|
||||
}
|
||||
|
||||
public void setDirection(String direction) {
|
||||
this.direction.set(direction);
|
||||
}
|
||||
|
||||
public ObjectProperty<Object> dataProperty() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ public class BindingData {
|
||||
* within the JavaFX property system.
|
||||
*/
|
||||
private StringProperty direction = new SimpleStringProperty("unidirectional");
|
||||
|
||||
/**
|
||||
* Represents the source of the binding. This property holds a string value
|
||||
* that specifies the originating object or identifier in the binding connection.
|
||||
|
||||
Reference in New Issue
Block a user