Document FX and injection and integrate the Designer reference example
This commit is contained in:
+78
-6
@@ -1,13 +1,85 @@
|
||||
# fx-example
|
||||
# Person desk reference application
|
||||
|
||||
A person desk that uses [`fx`](../fx/README.md) and [`injection`](../injection/README.md). The guides use this module as the worked example.
|
||||
This runnable application demonstrates [NeitzelLib FX](../fx/README.md) and [injection](../injection/README.md) together. It edits one Person with a home Address, nested Note, visit list, selected visit and tags. Use it as a reference for wiring a real screen; the [minimal quick start](../fx/docs/quick-start.md) is the smaller starting point for a new project.
|
||||
|
||||
The desk shows a direct binding in each direction, a converter, a computed binding, a view model subclass, a component with a nested note, a repeat, a table with a starting width and an open column, a date column, a list of simple values, and messages. The container side shows `@Config`, `@Singleton`, `@Named`, and injection by constructor, field, and setter.
|
||||
## Build and run
|
||||
|
||||
From the NeitzelLib root, with Java 21:
|
||||
From the NeitzelLib root with JDK 21:
|
||||
|
||||
```bash
|
||||
mvn -pl fx-example -am javafx:run
|
||||
./mvnw -pl fx-example -am install
|
||||
./mvnw -f fx-example/pom.xml javafx:run
|
||||
```
|
||||
|
||||
The launch class is `de.neitzel.fx.example.Main`. The model is an ordinary `Person`. The view is `Desk.fxml`. `DeskLoadsTest` loads that same desk.
|
||||
The first command installs local `1.0-SNAPSHOT` artifacts; the second runs only the application module. Do not combine `javafx:run` with `-am`, since the parent has no JavaFX launcher. The repository currently ignores Surefire failures; verify XML reports as shown in the [quick start](../fx/docs/quick-start.md), even when Maven reports success.
|
||||
|
||||
The packaged alternative, after `package` or `install`, is:
|
||||
|
||||
```bash
|
||||
java -jar fx-example/target/fx-example-1.0-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
Keep the adjacent `target/libs` directory with the JAR: the manifest refers to those copied runtime dependencies. A desktop session is required. This example has no `module-info.java`; it is a classpath application.
|
||||
|
||||
## Follow the code
|
||||
|
||||
Paths below are relative to this module. Java sources share `src/main/java/de/neitzel/fx/example/`; FXML resources share `src/main/resources/de/neitzel/fx/example/view/`.
|
||||
|
||||
| File/type | Responsibility |
|
||||
| --- | --- |
|
||||
| `Main` | Plain Java launcher calling `Application.launch` |
|
||||
| `DeskApp` | Scan configuration, fresh sample Model, ViewLoader, Scene and message popup registration |
|
||||
| `model/Person`, `Address`, `Note`, `Role` | JavaBean data and enum; no JavaFX properties required |
|
||||
| `view/DeskController` and `Desk.fxml` | Screen handlers, computed greeting, controls and binding declarations |
|
||||
| `view/PersonViewModel` | Handwritten ViewModel subclass with a derived title |
|
||||
| `view/AddressForm` and `AddressForm.fxml` | Reusable home subform and injected heading, containing NoteForm |
|
||||
| `view/NoteForm` and `NoteForm.fxml` | Nested Component bound to the note |
|
||||
| `view/VisitForm` and `VisitForm.fxml` | Fresh form per repeated Address |
|
||||
| `view/VisitRow` and `VisitRow.fxml` | Table row with editable fields and a trailing Remove button |
|
||||
| `src/test/resources/de/neitzel/fx/example/NameLine.fxml` | Test-only second View of the same Person without reusable Component nodes |
|
||||
| `view/AgeConverter`, `StreetConverter`, `VisitedOnConverter` | Text adaptation, validation failures and ISO dates |
|
||||
|
||||
Use the actual source directories to locate helper services such as `AgeSuffix`, `StreetPolicy` and `FormHeading`. The injection guide explains constructor, field and setter injection with these types. No code generation is required to run this example; `PersonViewModel` is handwritten.
|
||||
|
||||
## Try the behaviors
|
||||
|
||||
1. Change Name. The Model and name echo follow; title and computed greeting refresh. The draft field uses `direction="model"`: its edits write to the Model but later changes from another field do not overwrite it.
|
||||
2. Edit Age using its `years ` text format. An invalid value stays visible while the previous Model value is retained. A message explains the failure; a valid value clears that conversion failure.
|
||||
3. Edit the home street. The path-bound label follows. Empty street input fails through `StreetConverter`; the parent receives the child message with the `home.street` source prefix.
|
||||
4. Edit the nested note. AddressForm's inner NoteForm binds to its own Model. The `Opened as ...` label records initial setup rather than tracking every later city edit.
|
||||
5. Add a visit. Both the repeated forms and Table gain a row. Edit a street in one representation and observe the same Address in the other. The Table's Remove button delegates to the controller.
|
||||
6. Select a visit in the ComboBox or Table. Both use the `selectedVisit` Attribute. Resize, sort and filter Table columns; filtering and sorting affect displayed rows without reordering the Model's list.
|
||||
7. Edit the visited date in ISO form (`yyyy-MM-dd`). Invalid text keeps the old date. Add a tag to see a shared ObservableList of simple values.
|
||||
8. Try the information, warning and fatal message buttons. Severity is data and logging behavior; a fatal message does not itself exit the application. Close each non-blocking popup normally.
|
||||
|
||||
Changing a JavaBean setter directly after loading does not notify controls. All edits above go through ViewModel properties or observable collections. The [architecture guide](../fx/docs/architecture.md) explains this distinction and why you should normally use a new context for a separate window.
|
||||
|
||||
## Automated regression coverage
|
||||
|
||||
`src/test/java/de/neitzel/fx/example/DeskLoadsTest.java` loads the real Desk FXML on JavaFX and checks initial values, all binding directions, derived/computed text, conversion failures and recovery, child messages, Table edits/removal, message severities and boolean/enum write-back. It also demonstrates that a direct bean setter leaves controls unchanged and that another simple View reuses the same Model's ViewModel.
|
||||
|
||||
Run the reactor tests without installing artifacts with:
|
||||
|
||||
```bash
|
||||
./mvnw -pl fx-example -am clean verify
|
||||
```
|
||||
|
||||
Inspect Surefire XML reports; a successful Maven exit alone is insufficient with the current parent configuration. JavaFX tests need a usable graphical environment. See the Designer integration section below for the optional preview setup; ordinary application tests do not require the Designer.
|
||||
|
||||
## Open the example in NeitzelFXDesigner
|
||||
|
||||
The repository root includes `neitzel-fx-designer.json` with the `person-desk` context. It selects `fx-example`, classpath launch, the `designer-preview` Maven profile, the local runtime key `java21`, and `de.neitzel.fx.example.preview.DeskPreviewProvider`. Configure your own JDK path for that key; machine paths are not part of the shared project configuration.
|
||||
|
||||
The optional profile adds the Designer preview API only to the test source set, compiles `src/designer/java`, includes its resources, and produces Model metadata for Person, Address and Note. It does not add a runtime dependency to the ordinary application, replace its handwritten PersonViewModel, or generate a default ViewModel registry.
|
||||
|
||||
After preparing the Designer's local preview API and metadata processor artifacts, build with:
|
||||
|
||||
```bash
|
||||
./mvnw -pl fx-example -am -Pdesigner-preview verify
|
||||
```
|
||||
|
||||
Check XML test reports as for the normal build. Follow `docs/user-guide/quick-start.md` in the [NeitzelFXDesigner repository](https://gitea.neitzel.de/konrad/NeitzelFXDesigner) for the complete artifact preparation, library-example setup script, local runtime mapping, application launch and Build and Refresh workflow. That guide covers both the standalone host and IntelliJ integration; this profile alone is not a Designer installation.
|
||||
|
||||
FXML documents carry `neitzel-model` processing instructions for discovery. The preview provider offers `desk`, `address`, `visit`, `row` and `note` samples for the corresponding documents. Every session receives fresh sample Models and an injection context; the preview does not install the application's message popups. Open the document, Build and Refresh, choose its matching sample, then start interactive preview. Editing the preview's data does not save those values into the application source.
|
||||
|
||||
The role choices are populated in `DeskController.initialize()` rather than using an application-enum `fx:constant` in FXML, because the current Designer projection cannot resolve that application constant. This is a Designer limitation, not a restriction of NeitzelLib or ordinary FXMLLoader. The regular application still shows the same Role values.
|
||||
|
||||
@@ -97,4 +97,54 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>designer-preview</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>de.neitzel.fxdesigner</groupId>
|
||||
<artifactId>designer-preview-api</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>designer-preview-sources</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals><goal>add-test-source</goal><goal>add-test-resource</goal></goals>
|
||||
<configuration>
|
||||
<sources><source>src/designer/java</source></sources>
|
||||
<resources><resource><directory>src/designer/resources</directory></resource></resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<proc>full</proc>
|
||||
<annotationProcessorPaths combine.self="override">
|
||||
<path>
|
||||
<groupId>de.neitzel.fxdesigner</groupId>
|
||||
<artifactId>designer-model-processor</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
<compilerArgs>
|
||||
<arg>-Adesigner.models=de.neitzel.fx.example.model.Person,de.neitzel.fx.example.model.Address,de.neitzel.fx.example.model.Note</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package de.neitzel.fx.example.preview;
|
||||
|
||||
import de.neitzel.fx.example.DeskApp;
|
||||
import de.neitzel.fx.example.model.Address;
|
||||
import de.neitzel.fx.example.view.DeskController;
|
||||
import de.neitzel.fx.example.view.PersonViewModel;
|
||||
import de.neitzel.fxdesigner.preview.PreviewProvider;
|
||||
import de.neitzel.fxdesigner.preview.PreviewSession;
|
||||
import de.neitzel.injection.ApplicationContext;
|
||||
|
||||
/** Independent samples for the nested, repeated and table-row Address components. */
|
||||
public final class AddressPreviewProvider implements PreviewProvider<Address, ApplicationContext> {
|
||||
@Override
|
||||
public Class<Address> modelType() {
|
||||
return Address.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreviewSession<Address, ApplicationContext> open(String id) {
|
||||
if (!java.util.Set.of("address", "visit", "row").contains(id))
|
||||
throw new IllegalArgumentException("Unknown address example: " + id);
|
||||
var person = DeskApp.sample();
|
||||
var context = new ApplicationContext(DeskApp.class);
|
||||
// An independently previewed row still needs the parent action's state.
|
||||
// No Desk.fxml is loaded and no popup listener is installed.
|
||||
if ("row".equals(id))
|
||||
context.getComponent(DeskController.class).setViewModel(new PersonViewModel(person));
|
||||
return new SampleSession<>(
|
||||
"address".equals(id) ? person.getHome() : person.getVisits().getFirst(), context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.neitzel.fx.example.preview;
|
||||
|
||||
import de.neitzel.fx.example.DeskApp;
|
||||
import de.neitzel.fx.example.model.Person;
|
||||
import de.neitzel.fxdesigner.preview.PreviewProvider;
|
||||
import de.neitzel.fxdesigner.preview.PreviewSession;
|
||||
import de.neitzel.injection.ApplicationContext;
|
||||
|
||||
/** Optional test-source preview adapter; it never enters the application distribution. */
|
||||
public final class DeskPreviewProvider implements PreviewProvider<Person, ApplicationContext> {
|
||||
@Override
|
||||
public Class<Person> modelType() {
|
||||
return Person.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreviewSession<Person, ApplicationContext> open(String id) {
|
||||
if (!"desk".equals(id)) throw new IllegalArgumentException("Unknown desk example: " + id);
|
||||
return new SampleSession<>(DeskApp.sample(), new ApplicationContext(DeskApp.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package de.neitzel.fx.example.preview;
|
||||
|
||||
import de.neitzel.fx.example.DeskApp;
|
||||
import de.neitzel.fx.example.model.Note;
|
||||
import de.neitzel.fxdesigner.preview.PreviewProvider;
|
||||
import de.neitzel.fxdesigner.preview.PreviewSession;
|
||||
import de.neitzel.injection.ApplicationContext;
|
||||
|
||||
/** Independent sample for the nested note editor. */
|
||||
public final class NotePreviewProvider implements PreviewProvider<Note, ApplicationContext> {
|
||||
@Override
|
||||
public Class<Note> modelType() {
|
||||
return Note.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreviewSession<Note, ApplicationContext> open(String id) {
|
||||
if (!"note".equals(id)) throw new IllegalArgumentException("Unknown note example: " + id);
|
||||
return new SampleSession<>(
|
||||
DeskApp.sample().getHome().getNote(), new ApplicationContext(DeskApp.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package de.neitzel.fx.example.preview;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import de.neitzel.fx.example.view.DeskController;
|
||||
import de.neitzel.fx.view.ViewLoader;
|
||||
|
||||
import javafx.application.Platform;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
class PreviewProvidersTest {
|
||||
@BeforeAll
|
||||
static void startToolkit() throws Exception {
|
||||
var ready = new CountDownLatch(1);
|
||||
try {
|
||||
Platform.startup(ready::countDown);
|
||||
} catch (IllegalStateException alreadyRunning) {
|
||||
ready.countDown();
|
||||
}
|
||||
assertTrue(ready.await(10, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
private static void onFx(Runnable action) throws Exception {
|
||||
var result = new CompletableFuture<Void>();
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
try {
|
||||
action.run();
|
||||
result.complete(null);
|
||||
} catch (Throwable e) {
|
||||
result.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
result.get(20, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deskSamplesAreFreshAndLoadTheRealDesk() throws Exception {
|
||||
onFx(
|
||||
() -> {
|
||||
var provider = new DeskPreviewProvider();
|
||||
var first = provider.open("desk");
|
||||
var second = provider.open("desk");
|
||||
assertNotSame(first.model(), second.model());
|
||||
assertNotSame(first.model().getHome(), second.model().getHome());
|
||||
assertNotSame(first.context(), second.context());
|
||||
var view =
|
||||
ViewLoader.load(
|
||||
DeskController.class.getResource("Desk.fxml"),
|
||||
first.model(),
|
||||
first.context());
|
||||
assertNotNull(view.getRoot().lookup("#nameField"));
|
||||
assertEquals("Ada Lovelace", first.model().getName());
|
||||
assertTrue(first.ready().toCompletableFuture().isDone());
|
||||
assertThrows(IllegalArgumentException.class, () -> provider.open("unknown"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void componentSamplesAndIndependentRowActionHaveRequiredState() throws Exception {
|
||||
onFx(
|
||||
() -> {
|
||||
var addresses = new AddressPreviewProvider();
|
||||
var home = addresses.open("address");
|
||||
assertNotNull(home.model().getNote());
|
||||
var visit = addresses.open("visit");
|
||||
assertNotNull(visit.model().getVisitedOn());
|
||||
var row = addresses.open("row");
|
||||
assertDoesNotThrow(
|
||||
() ->
|
||||
row.context()
|
||||
.getComponent(DeskController.class)
|
||||
.removeVisit(row.model()));
|
||||
var note = new NotePreviewProvider().open("note");
|
||||
assertEquals("Kept at home", note.model().getText());
|
||||
assertThrows(IllegalArgumentException.class, () -> addresses.open("desk"));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> new NotePreviewProvider().open("desk"));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.neitzel.fx.example.preview;
|
||||
|
||||
import de.neitzel.fxdesigner.preview.PreviewSession;
|
||||
import de.neitzel.injection.ApplicationContext;
|
||||
|
||||
/** The sample owns no timers, network connections or background work to release. */
|
||||
record SampleSession<M>(M model, ApplicationContext context)
|
||||
implements PreviewSession<M, ApplicationContext> {
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
format=1
|
||||
count=5
|
||||
example.0.id=desk
|
||||
example.0.label=Person desk
|
||||
example.0.modelType=de.neitzel.fx.example.model.Person
|
||||
example.0.providerClass=de.neitzel.fx.example.preview.DeskPreviewProvider
|
||||
example.0.viewResource=de/neitzel/fx/example/view/Desk.fxml
|
||||
example.0.componentPackage=de.neitzel.fx.example.view
|
||||
|
||||
example.1.id=address
|
||||
example.1.label=Home address
|
||||
example.1.modelType=de.neitzel.fx.example.model.Address
|
||||
example.1.providerClass=de.neitzel.fx.example.preview.AddressPreviewProvider
|
||||
example.1.viewResource=de/neitzel/fx/example/view/AddressForm.fxml
|
||||
example.1.componentPackage=de.neitzel.fx.example.view
|
||||
|
||||
example.2.id=visit
|
||||
example.2.label=Repeated visit
|
||||
example.2.modelType=de.neitzel.fx.example.model.Address
|
||||
example.2.providerClass=de.neitzel.fx.example.preview.AddressPreviewProvider
|
||||
example.2.viewResource=de/neitzel/fx/example/view/VisitForm.fxml
|
||||
example.2.componentPackage=de.neitzel.fx.example.view
|
||||
|
||||
example.3.id=row
|
||||
example.3.label=Table row
|
||||
example.3.modelType=de.neitzel.fx.example.model.Address
|
||||
example.3.providerClass=de.neitzel.fx.example.preview.AddressPreviewProvider
|
||||
example.3.viewResource=de/neitzel/fx/example/view/VisitRow.fxml
|
||||
example.3.componentPackage=de.neitzel.fx.example.view
|
||||
|
||||
example.4.id=note
|
||||
example.4.label=Address note
|
||||
example.4.modelType=de.neitzel.fx.example.model.Note
|
||||
example.4.providerClass=de.neitzel.fx.example.preview.NotePreviewProvider
|
||||
example.4.viewResource=de/neitzel/fx/example/view/NoteForm.fxml
|
||||
example.4.componentPackage=de.neitzel.fx.example.view
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.neitzel.fx.example.view;
|
||||
|
||||
import de.neitzel.fx.example.model.Address;
|
||||
import de.neitzel.fx.example.model.Role;
|
||||
import de.neitzel.fx.view.HasViewModel;
|
||||
import de.neitzel.fx.view.Message;
|
||||
import de.neitzel.fx.view.ViewModel;
|
||||
@@ -8,6 +9,7 @@ import de.neitzel.fx.view.ViewModelClass;
|
||||
import jakarta.inject.Singleton;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
@@ -35,6 +37,16 @@ public class DeskController implements HasViewModel {
|
||||
@FXML
|
||||
private TextField tagField;
|
||||
|
||||
/** Role values are supplied in the application runtime, not instantiated by the designer host. */
|
||||
@FXML
|
||||
private ChoiceBox<Role> roleChoice;
|
||||
|
||||
/** Supplies enum choices before the declarative value binding is applied. */
|
||||
@FXML
|
||||
public void initialize() {
|
||||
roleChoice.getItems().setAll(Role.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* The person view model, set before the bindings run.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?neitzel-model de.neitzel.fx.example.model.Address?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
@@ -9,7 +10,7 @@
|
||||
<?import de.neitzel.fx.view.DirectBinding?>
|
||||
|
||||
<fx:root type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml" spacing="6">
|
||||
xmlns:fx="http://javafx.com/fxml/1" spacing="6">
|
||||
<padding>
|
||||
<Insets top="4" right="4" bottom="4" left="4"/>
|
||||
</padding>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?neitzel-model de.neitzel.fx.example.model.Person?>
|
||||
|
||||
<?import javafx.collections.FXCollections?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
@@ -13,7 +13,6 @@
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import de.neitzel.fx.example.model.Role?>
|
||||
<?import de.neitzel.fx.example.view.AddressForm?>
|
||||
<?import de.neitzel.fx.view.BindingList?>
|
||||
<?import de.neitzel.fx.view.Column?>
|
||||
@@ -22,7 +21,7 @@
|
||||
<?import de.neitzel.fx.view.Repeat?>
|
||||
<?import de.neitzel.fx.view.Table?>
|
||||
|
||||
<VBox xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="de.neitzel.fx.example.view.DeskController"
|
||||
spacing="8" prefWidth="520">
|
||||
<padding>
|
||||
@@ -70,14 +69,7 @@
|
||||
<Label text="Title" GridPane.rowIndex="5" GridPane.columnIndex="0"/>
|
||||
<Label fx:id="titleLabel" id="titleLabel" GridPane.rowIndex="5" GridPane.columnIndex="1"/>
|
||||
<Label text="Role" GridPane.rowIndex="6" GridPane.columnIndex="0"/>
|
||||
<ChoiceBox fx:id="roleChoice" id="roleChoice" GridPane.rowIndex="6" GridPane.columnIndex="1">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<Role fx:constant="READER"/>
|
||||
<Role fx:constant="AUTHOR"/>
|
||||
</FXCollections>
|
||||
</items>
|
||||
</ChoiceBox>
|
||||
<ChoiceBox fx:id="roleChoice" id="roleChoice" GridPane.rowIndex="6" GridPane.columnIndex="1"/>
|
||||
<Label text="Home street" GridPane.rowIndex="7" GridPane.columnIndex="0"/>
|
||||
<Label fx:id="homeStreetLabel" id="homeStreetLabel" GridPane.rowIndex="7" GridPane.columnIndex="1"/>
|
||||
</GridPane>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?neitzel-model de.neitzel.fx.example.model.Note?>
|
||||
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
@@ -7,7 +8,7 @@
|
||||
<?import de.neitzel.fx.view.DirectBinding?>
|
||||
|
||||
<fx:root type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml" spacing="6">
|
||||
xmlns:fx="http://javafx.com/fxml/1" spacing="6">
|
||||
<fx:define>
|
||||
<BindingList>
|
||||
<DirectBinding control="noteField" property="text" path="text" direction="both"/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?neitzel-model de.neitzel.fx.example.model.Address?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
@@ -8,7 +9,7 @@
|
||||
<?import de.neitzel.fx.view.DirectBinding?>
|
||||
|
||||
<fx:root type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml" spacing="6">
|
||||
xmlns:fx="http://javafx.com/fxml/1" spacing="6">
|
||||
<padding>
|
||||
<Insets top="4" right="4" bottom="4" left="4"/>
|
||||
</padding>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?neitzel-model de.neitzel.fx.example.model.Address?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
@@ -7,7 +8,7 @@
|
||||
<?import de.neitzel.fx.view.DirectBinding?>
|
||||
|
||||
<fx:root type="javafx.scene.layout.HBox" xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml" spacing="8">
|
||||
xmlns:fx="http://javafx.com/fxml/1" spacing="8">
|
||||
<fx:define>
|
||||
<BindingList>
|
||||
<DirectBinding control="streetField" property="text" path="street" direction="both"/>
|
||||
|
||||
Reference in New Issue
Block a user