A framework for easily creating forms for a JavaFX UI.

Overview

Bugs Code Smells Lines of Code Maintainability Rating Quality Gate Status Reliability Rating Security Rating Technical Debt Vulnerabilities

FormsFX

Forms for business application made easy. Creating forms in Java has never been this easy!

Download Build Status

Maven

To use this framework as part of your Maven build simply add the following dependency to your pom.xml file.

<dependency>
  <groupId>com.dlsc.formsfx</groupId>
  <artifactId>formsfx-core</artifactId>
  <version>11.3.2</version>
</dependency>

What is FormsFX?

Creating forms in JavaFX is a tedious and very error-prone task. FormsFX is a framework which solves this problem. It enables the developer to create forms with ease and creates well-designed and user-friendly forms by default. FormsFX offers a fluent API that is very easy to understand and reduces the amount of coding needed. It creates all the necessary bindings for the properties and it just works.

Main Features

  • Simple and understandable Fluent API
  • Different semantic items
  • Pre-defined controls
  • Validation
  • Localisation
Form loginForm = Form.of(
        Group.of(
                Field.ofStringType(model.usernameProperty())
                        .label("Username"),
                Field.ofStringType(model.passwordProperty())
                        .label("Password")
                        .required("This field can’t be empty")
        )
).title("Login");

Semantics

FormsFX offers different semantic layers. The largest entity is the form. It contains groups and sections, which in turn act as containers for fields. Fields are the end user's primary point of interaction as they handle data input and presentation.

Defining a form

Creating a form is as simple as calling Form.of().

Form.of(
        Group.of(
                Field.ofStringType("")
                        .label("Username"),
                Field.ofStringType("")
                        .label("Password")
                        .required("This field can’t be empty")
        ),
        Group.of(…)
).title("Login");

Fields have a range of options that define their semantics and change their functionality.

Option Description
label(String) Describes the field’s content in a concise manner. This description is always visible and usually placed next to the editable control.
tooltip(String) This contextual hint further describes the field. It is usually displayed on hover or focus.
placeholder(String) This hint describes the expected input as long as the field is empty.
required(boolean)
required(String)
Determines, whether entry in this field is required for the correctness of the form.
editable(boolean) Determines, whether end users can edit the contents of this field.
id(String) Describes the field with a unique ID. This is not visible directly, but can be used for styling purposes.
styleClass(List&lt;String&gt;) Adds styling hooks to the field. This can be used on the view layer.
span(int)
span(ColSpan)
Determines, how many columns the field should span on the view layer. Can be a number between 1 and 12 or a ColSpan fraction.
render(SimpleControl) Determines the control that is used to render this field on the view layer.

The following table shows how to create different fields and how they look by default:

String Control

String Control
Field.ofStringType("CHF")
     .label("Currency")
Integer Control
Field.ofIntegerType(8401120)
     .label("Population")
Double Control
Field.ofDoubleType(41285.0)
       .label("Area")
Boolean Control
Field.ofBooleanType(false)
     .label("Independent")
ComboBox Control
Field.ofSingleSelectionType(Arrays.asList("Zürich (ZH)", "Bern (BE)", …), 1)
     .label("Capital")
RadioButton Control
Field.ofSingleSelectionType(Arrays.asList("Right", "Left"), 0)
     .label("Driving on the")
     .render(new SimpleRadioButtonControl<>())
CheckBox Control
Field.ofMultiSelectionType(Arrays.asList("Africa", "Asia", …), Collections.singletonList(2))
     .label("Continent")
     .render(new SimpleCheckBoxControl<>())
ListView Control
Field.ofMultiSelectionType(Arrays.asList("Zürich (ZH)", "Bern (BE)", …), Arrays.asList(0, 1, …))
     .label("Biggest Cities")

Rendering a form

The only point of interaction is the FormRenderer. It delegates rendering of further components to other renderers.

Pane root = new Pane();
root.getChildren().add(new FormRenderer(form));

All fields have a default control that is used for rendering. This can be changed to another compatible implementation using the render() method.

Field.ofMultiSelectionType(…)
        .render(new SimpleCheckBoxControl<>())

Model

Forms are used to create and manipulate data. In order to use this data in other parts of an application, model classes can be used. These classes contain properties, which are then bound to the persisted value of a field.

StringProperty name = new SimpleStringProperty("Hans");
Field.ofStringType(name);

The persist() and reset() methods can be used to store and revert field values, which in turn updates the binding.

Fields in FormsFX store their values in multiple steps. For free-form fields, like StringField or DoubleField, the exact user input is stored, along with a type-transformed value and a persistent value. The persistence is, by default, handled manually, but this can be overridden by setting the BindingMode to CONTINUOUS on the form level.

Localisation

All displayed values are localisable. Methods like label(), placeholder() accept keys which are then used for translation. By default, FormsFX includes a ResourceBundle-based implementation, however, this can be exchanged for a custom implementation.

private ResourceBundle rbDE = ResourceBundle.getBundle("demo.demo-locale", new Locale("de", "CH"));
private ResourceBundle rbEN = ResourceBundle.getBundle("demo.demo-locale", new Locale("en", "UK"));

private ResourceBundleService rbs = new ResourceBundleService(rbEN);

Form.of(…)
        .i18n(rbs);

Validation

All fields are validated whenever end users edit the contained data. FormsFX offers a wide range of pre-defined validators, but also includes support for custom validators using the CustomValidator.forPredicate() method.

Validator Description
CustomValidator Define a predicate that returns whether the field is valid or not.
DoubleRangeValidator Define a number range which is considered valid. This range can be limited in either one direction or in both directions.
IntegerRangeValidator Define a number range which is considered valid. This range can be limited in either one direction or in both directions.
RegexValidator Valiate text against a regular expression. This validator offers pre-defined expressions for common use cases, such as email addresses.
SelectionLengthValidator Define a length interval which is considered valid. This range can be limited in either one direction or in both directions.
StringLengthValidator Define a length interval which is considered valid. This range can be limited in either one direction or in both directions.

Advantages

  • Less error-prone
  • Less code needed
  • Easy to learn
  • Easy to understand
  • Easy to extend

Documentation

Comments
  • Single Selection Type Fields Not Persisting

    Single Selection Type Fields Not Persisting

    I just started using FormsFX and it's been great so far. I was able to create a form with string, integer, and boolean type fields and them update a model via properties with no issues. I run into a problem though, when I try to add a single selection type field. The following are the snippets of code showing what I did (I basically followed what's in the demo application):

        private final ListProperty<Integer> allServings =
                new SimpleListProperty<>(FXCollections.observableArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        private final ObjectProperty<Integer> serving = new SimpleObjectProperty<>(1);
    
       /**
         * References the <code>Form</code> that is bound to this <code>Recipe</code>.
         *
         * @since 1.0.0
         */
        private Form formInstance;
    
        /**
         * Retrieves or creates an instance of a FormFX form using the given <code>Recipe</code>.
         *
         * @return An instance of a FormFX form using the given <code>Recipe</code>.
         *
         * @since 1.0.0
         */
        public Form getOrCreateFormInstance() {
            if (Objects.isNull(this.formInstance)) {
                createForm();
            }
    
            return this.formInstance;
        }
    
        /**
         * Helper method to initialize the FormFX form field of this <code>Recipe</code>.
         *
         * @since 1.0.0
         */
        private void createForm() {
            this.formInstance = Form.of(Group.of(
                    Field.ofStringType(titleProperty())
                         .label("Title")
                         .placeholder("e.g. Chicken Wings")
                         .required("A title is required for all recipes."),
                    Field.ofStringType(descriptionProperty())
                         .label("Description")
                         .placeholder("e.g. Delicious Honey BBQ wings")
                         .required("A description is required for all recipes."),
                    Field.ofIntegerType(caloriesProperty())
                         .label("Calories")
                         .placeholder("e.g. 500")
                         .span(ColSpan.HALF)
                         .required("The number of calories is required for all recipes."),
                    Field.ofIntegerType(cookTimeProperty())
                         .label("Cooking Time")
                         .placeholder("e.g. 60")
                         .span(ColSpan.HALF)
                         .required("The total cooking time (in minutes) is required for all recipes."),
                    Field.ofSingleSelectionType(allServingsProperty(), servingProperty())
                         .label("Serving Size")
                         .placeholder("Serving Size")
                         .required("The serving size is required for all recipes."),
                    Field.ofStringType(directionsProperty())
                         .label("Cooking Directions")
                         .placeholder("e.g. Bake at 375 degrees in the over for an hour and a half.")
                         .required("Cooking directions are required for all recipes."),
                    Field.ofBooleanType(publishedProperty())
                         .label("Publish Recipe")))
                                    .title("Recipe Form");
        }
    
        public Integer getServing() {
            return serving.get();
        }
    
        public void setServing(Integer serving) {
            this.serving.set(serving);
        }
    
        public ObjectProperty<Integer> servingProperty() {
            return serving;
        }
    
        public ObservableList<Integer> getAllServings() {
            return allServings.get();
        }
    
        public void setAllServings(ObservableList<Integer> allServings) {
            this.allServings.set(allServings);
        }
    
        public ListProperty<Integer> allServingsProperty() {
            return allServings;
        }
    
    

    Here is the method that I use to save the form fields to the database:

        @FXML
        public void save(ActionEvent event) {
            this.recipe.getOrCreateFormInstance().persist();
            if (!this.recipe.getOrCreateFormInstance().isValid()) {
                return;
            }
    
            if (this.recipe.getId() == 0) {
                saveRecipe(this.recipe);
            }
            else {
                updateRecipe(this.recipe);
            }
        }
    
    

    All other form fields save except the serving field. Am I doing anything incorrectly based on the code I've shared? Please let me know if you need anymore context.

    bug 
    opened by wemgl 9
  • Support additional descriptions on Field

    Support additional descriptions on Field

    Similar to https://github.com/dlemmermann/PreferencesFX/issues/23 sometimes you'd like additional text to be displayed under a Field's name or it's renderer. This text may be used as a hint to the user to let them know what data may be entered as the Field's value.

    It may be worth using Node as a type instead of just String as this would allow for additional elements (such as icons) to be embedded in the description.

    I propose to add two more properties to Field: labelDescription(Node) and valueDescription(Node)/fieldDescription(Node).

    opened by aalmiray 2
  • How to access form element values?

    How to access form element values?

    Hi,

    Just a question - in the demo project, what is the way to access the current values in the form elements, for example the text the user types in to the Country Name field? It seemed to me like when you call .persist() it should save the current form state, but apparently I'm wrong? Any guidance would be appreciated. Any chance of adding a quick demo for this to the readme?

    I wanted to add the setter in the model for Country.name then do this:

            save.setOnAction(event -> model.getFormInstance().persist());
            save.setOnAction(event -> System.out.println(model.getCountry().getName()));
    
    opened by mips171 1
  • Bump junit from 4.11 to 4.13.1 in /formsfx-core

    Bump junit from 4.11 to 4.13.1 in /formsfx-core

    Bumps junit from 4.11 to 4.13.1.

    Release notes

    Sourced from junit's releases.

    JUnit 4.13.1

    Please refer to the release notes for details.

    JUnit 4.13

    Please refer to the release notes for details.

    JUnit 4.13 RC 2

    Please refer to the release notes for details.

    JUnit 4.13 RC 1

    Please refer to the release notes for details.

    JUnit 4.13 Beta 3

    Please refer to the release notes for details.

    JUnit 4.13 Beta 2

    Please refer to the release notes for details.

    JUnit 4.13 Beta 1

    Please refer to the release notes for details.

    JUnit 4.12

    Please refer to the release notes for details.

    JUnit 4.12 Beta 3

    Please refer to the release notes for details.

    JUnit 4.12 Beta 2

    No release notes provided.

    JUnit 4.12 Beta 1

    No release notes provided.

    Commits
    • 1b683f4 [maven-release-plugin] prepare release r4.13.1
    • ce6ce3a Draft 4.13.1 release notes
    • c29dd82 Change version to 4.13.1-SNAPSHOT
    • 1d17486 Add a link to assertThrows in exception testing
    • 543905d Use separate line for annotation in Javadoc
    • 510e906 Add sub headlines to class Javadoc
    • 610155b Merge pull request from GHSA-269g-pwp5-87pp
    • b6cfd1e Explicitly wrap float parameter for consistency (#1671)
    • a5d205c Fix GitHub link in FAQ (#1672)
    • 3a5c6b4 Deprecated since jdk9 replacing constructor instance of Double and Float (#1660)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump junit from 4.12 to 4.13.1

    Bump junit from 4.12 to 4.13.1

    Bumps junit from 4.12 to 4.13.1.

    Release notes

    Sourced from junit's releases.

    JUnit 4.13.1

    Please refer to the release notes for details.

    JUnit 4.13

    Please refer to the release notes for details.

    JUnit 4.13 RC 2

    Please refer to the release notes for details.

    JUnit 4.13 RC 1

    Please refer to the release notes for details.

    JUnit 4.13 Beta 3

    Please refer to the release notes for details.

    JUnit 4.13 Beta 2

    Please refer to the release notes for details.

    JUnit 4.13 Beta 1

    Please refer to the release notes for details.

    Commits
    • 1b683f4 [maven-release-plugin] prepare release r4.13.1
    • ce6ce3a Draft 4.13.1 release notes
    • c29dd82 Change version to 4.13.1-SNAPSHOT
    • 1d17486 Add a link to assertThrows in exception testing
    • 543905d Use separate line for annotation in Javadoc
    • 510e906 Add sub headlines to class Javadoc
    • 610155b Merge pull request from GHSA-269g-pwp5-87pp
    • b6cfd1e Explicitly wrap float parameter for consistency (#1671)
    • a5d205c Fix GitHub link in FAQ (#1672)
    • 3a5c6b4 Deprecated since jdk9 replacing constructor instance of Double and Float (#1660)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • make property of data field generic

    make property of data field generic

    This PR consists only of a breaking change. Never the less I would like to discuss the possibility to get this merged.

    Breaking Change

    • Remove generic parameter P from DataField. This was the type of the property which was used in the DataField. The new implementation works with any Property and therefore is no longer dependent onto the exact type P.

    I do not think this breaking changes will have much influence on users because the change is only noticeable if someone sub-class DataField instead of using one of the provided sub-classes.

    opened by sclassen 1
  • Required field fails when I18N is enabled

    Required field fails when I18N is enabled

    Define a Field with required(true) and enabled I18N by invoking i18n(). This will cause an exception because there's no errorMessage associated with this field however the errorMessageKey property has an empty String as value but the check is made against a null value.

    The offending code is found in DataField.validate()

        if (!validateRequired(newValue)) {
            if (isI18N() && requiredErrorKey.get() != null) {
                errorMessageKeys.setAll(requiredErrorKey.get());
            } else if (requiredError.get() != null) {
                errorMessages.setAll(requiredError.get());
            }
    
            valid.set(false);
            return false;
        }
    

    Interestingly enough, formatting after transforming the value (inside the same validate() method) has the correct check

        try {
            transformedValue = valueTransformer.transform(newValue);
        } catch (Exception e) {
            if (isI18N() && !formatErrorKey.get().isEmpty()) {
                errorMessageKeys.setAll(formatErrorKey.get());
            } else if (!formatError.get().isEmpty()) {
                errorMessages.setAll(formatError.get());
            }
    
            valid.set(false);
            return false;
        }
    

    Full stack trace follows

    Exception in thread "JavaFX Application Thread" java.util.MissingResourceException: Can't find resource for bundle java.util.PropertyResourceBundle, key 
        at java.util.ResourceBundle.getObject(ResourceBundle.java:450)
        at java.util.ResourceBundle.getString(ResourceBundle.java:407)
        at com.dlsc.formsfx.model.util.ResourceBundleService.translate(ResourceBundleService.java:62)
        at com.dlsc.formsfx.model.structure.Field.lambda$null$5(Field.java:170)
        at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
        at java.util.Iterator.forEachRemaining(Iterator.java:116)
        at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
        at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
        at com.dlsc.formsfx.model.structure.Field.lambda$new$6(Field.java:171)
        at com.sun.javafx.binding.ListExpressionHelper$SingleChange.fireValueChangedEvent(ListExpressionHelper.java:239)
        at com.sun.javafx.binding.ListExpressionHelper.fireValueChangedEvent(ListExpressionHelper.java:109)
        at javafx.beans.property.ListPropertyBase.fireValueChangedEvent(ListPropertyBase.java:200)
        at javafx.beans.property.ListPropertyBase.lambda$new$39(ListPropertyBase.java:56)
        at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
        at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
        at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
        at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
        at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
        at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
        at javafx.collections.ModifiableObservableListBase.setAll(ModifiableObservableListBase.java:90)
        at javafx.collections.ObservableListBase.setAll(ObservableListBase.java:250)
        at javafx.beans.binding.ListExpression.setAll(ListExpression.java:364)
        at com.dlsc.formsfx.model.structure.DataField.validate(DataField.java:303)
        at com.dlsc.formsfx.model.structure.DataField.lambda$new$3(DataField.java:126)
        at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
        at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
        at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
        at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
        at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
        at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
        at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
        at javafx.beans.property.StringProperty.setValue(StringProperty.java:57)
        at com.sun.javafx.binding.BidirectionalBinding$TypedGenericBidirectionalBinding.changed(BidirectionalBinding.java:599)
        at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
        at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
        at javafx.scene.control.TextInputControl$TextProperty.fireValueChangedEvent(TextInputControl.java:1389)
        at javafx.scene.control.TextInputControl$TextProperty.markInvalid(TextInputControl.java:1393)
        at javafx.scene.control.TextInputControl$TextProperty.controlContentHasChanged(TextInputControl.java:1332)
        at javafx.scene.control.TextInputControl$TextProperty.access$1600(TextInputControl.java:1300)
        at javafx.scene.control.TextInputControl.lambda$new$162(TextInputControl.java:139)
        at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
        at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
        at javafx.scene.control.TextField$TextFieldContent.delete(TextField.java:96)
        at javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:1200)
        at javafx.scene.control.TextInputControl.updateContent(TextInputControl.java:556)
        at javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:548)
        at javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:510)
        at javafx.scene.control.TextInputControl.replaceSelection(TextInputControl.java:1084)
        at javafx.scene.control.TextInputControl.deletePreviousChar(TextInputControl.java:889)
        at com.sun.javafx.scene.control.skin.TextFieldSkin.deleteChar(TextFieldSkin.java:589)
        at com.sun.javafx.scene.control.behavior.TextFieldBehavior.deleteChar(TextFieldBehavior.java:198)
        at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.deletePreviousChar(TextInputControlBehavior.java:311)
        at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.callAction(TextInputControlBehavior.java:143)
        at com.sun.javafx.scene.control.behavior.BehaviorBase.callActionForEvent(BehaviorBase.java:218)
        at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.callActionForEvent(TextInputControlBehavior.java:127)
        at com.sun.javafx.scene.control.behavior.BehaviorBase.lambda$new$74(BehaviorBase.java:135)
        at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
        at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
        at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
        at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
        at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
        at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
        at javafx.event.Event.fireEvent(Event.java:198)
        at javafx.scene.Scene$KeyHandler.process(Scene.java:3964)
        at javafx.scene.Scene$KeyHandler.access$1800(Scene.java:3910)
        at javafx.scene.Scene.impl_processKeyEvent(Scene.java:2040)
        at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2501)
        at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:217)
        at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:149)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent$352(GlassViewEventHandler.java:248)
        at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
        at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:247)
        at com.sun.glass.ui.View.handleKeyEvent(View.java:546)
        at com.sun.glass.ui.View.notifyKey(View.java:966)
    
    opened by aalmiray 1
  • DataField assumes edited value can be transformed to a suitable String representation

    DataField assumes edited value can be transformed to a suitable String representation

    DataField<V> assumes that V can be safely transformed to a String literal that makes sense for that particular type, but that's not often the case, specially when dealing with types (domain classes) for which an overridden version of toString() is not available or returns a rather cryptic value.

    This design decision imposes a constraint on edited values as it's expected of them to provide a suitable toString() implementation, while at the same time requiring an external transformer (from String to V) by means of FormsFX's ValueTransformer.

    It would be much better if JavaFX's StringConverter would be used instead, as it provides both sides of the equation. Retrofitting DataField with StrinfConverter can be done in a compatible way, by deprecating ValueTransformer and redirecting is String -> T transformation to an ad-hoc StringConverter.fromString. Also, a pre-instantiated StringConverter can take care of the default String conversion.

    opened by aalmiray 1
  • Open SimpleControl impls for extension

    Open SimpleControl impls for extension

    I have the need to change the renderer of a StringField. While I can create a custom implementation of SimpleControlsimilar to SimpleTextControlI'd have to duplicate code as the SimpleTextControl defines most of its state & behavior using the private visibility modifier.

    It would be better to migrate to protected, applying the factory method pattern where it makes sense, allowing subclasses to override specific behavior.

    opened by aalmiray 1
  • Trigger an event when Form is persisted/reset

    Trigger an event when Form is persisted/reset

    Currently there's no way for a component to react when a Form is persisted/reset. Triggering an event would make it easier for transforming pipelines to handle data updates.

    opened by aalmiray 1
  • Embed additional content inside a Group/Section

    Embed additional content inside a Group/Section

    The following screenshot shows text, a link, and a button as part of the first Group/Section (Intellij preferences).

    formsfx-extra-content

    The current API only allows elements of type Field to be embedded on a Group/Section. AFAICT building a screen like this will require two separate Form instances.

    opened by aalmiray 1
  • Dynamic Forms,Access to values

    Dynamic Forms,Access to values

    So this may be similar to one of the open or closed issues,but please hear my case ,

    How does one handle dynamic form inputs with this library, from my end I failed to capture the new values from the text input fields. My forms are being built by a JSON data sort that creates forms on the fly, but I have failed to capture the input from the user, according to the API, I seem or it seems like I can't access that from the API, I can say I have attempted to exhaust all possible options from trying to leverageKeyEvent.KEY_PRESSED (terrible idea), to even to use changedProperty() , even tried to use the native reactive API components of the JavaFX but still only get boolean values from this class javafx.beans.property.SimpleBooleanProperty.

    I have studied the demo code but it fails to give practical hints to what I am looking for , may be I am miss guided please help me .

    opened by kinsleykajiva 0
  • com.dlsc.formsfx.model.structure.Element visibility

    com.dlsc.formsfx.model.structure.Element visibility

    Hi 👋,

    Could you, please, guide me how to change visibility for com.dlsc.formsfx.model.structure.Element ?

    For example, I need to change visibility of one of my components. In Swing and JavaFX I just can setVisible(false) or setVisible(true). How can I do this with FormsFX?

    Thank you for help!

    Best regards, Alex

    opened by aldanchenko 0
  • Using JavaBeanXXProperty will not update the model

    Using JavaBeanXXProperty will not update the model

    Hello. I used the JavaBeanDoubleProperty, JavaBeanStringProperty, etc. in my model, but the form is not updating the fields if changed in the GUI.

            p = new ObservableGameMainPaneProperties.GameMainPaneProperties();
            np = new ObservableGameMainPaneProperties(p);
            this.form = Form.of(Group.of(//
                    Field.ofStringType(np.kernelName).label("Name").required("Not empty"), //
                    Field.ofIntegerType(np.seed).label("Seed").required("Not empty"), //
                    Field.ofIntegerType(np.width).label("Width").required("Not empty"), //
                    Field.ofIntegerType(np.height).label("Height").required("Not empty"), //
                    Field.ofDoubleType(np.z).label("Z").required("Not empty"), //
                    Field.ofIntegerType(np.dim).label("Dimension").required("Not empty") //
            ));
    
    

    I created a demo project https://github.com/devent/formsfx-javabeanproperty-test You have to change the field "Dimension" to "4". I expect that if I do that then the field ObservableGameMainPaneProperties#GameMainPaneProperties#dim is also set to 4.

    opened by devent 0
  • Setting spacing/padding between fields

    Setting spacing/padding between fields

    It is possible to use FormRenderer to set the spacing between Groups/Sections but I do not see a way to set the spacing between fields. I tried using GroupRenderer however its constructor is protected and there is I see to access FormRenderer specific group so it can access a specific field (I tried using getChildren() but made more mess).

    Is there a different option I should have used?

    Note: I just hope this project isn't dead as it really helps solve some issues and saves time.

    opened by YovelB 0
  • Setting width of Labels

    Setting width of Labels

    Hi there,

    Having difficulty setting the width of the Labels.. would be good to have room for a little more text. Have been able to adjust the individual widths of the label and the control with CSS but this is creating an overlap as shown in image below. Any help would be much appreciated!

    Many thanks

    .changeLabel .label {

    -fx-font-family: "DS-Digital Bold";
    -fx-font-size: 130%;
    -fx-min-width:150px;
    

    }

    .changeLabel .combo-box-base{ -fx-max-width:150px; }

    image
    opened by pauliamgiant 7
  • Why SingleSelectionField not

    Why SingleSelectionField not "only persists values when explicitly requested" like other fields?

    My version:

        <dependency>
          <groupId>com.dlsc.formsfx</groupId>
          <artifactId>formsfx-core</artifactId>
          <version>1.3.1</version>
        </dependency>
    

    For example:

    import com.dlsc.formsfx.model.structure.Field;
    import com.dlsc.formsfx.model.structure.Form;
    import com.dlsc.formsfx.model.structure.Group;
    import com.dlsc.formsfx.view.renderer.FormRenderer;
    import javafx.application.Application;
    import javafx.beans.property.*;
    import javafx.collections.FXCollections;
    import javafx.scene.Scene;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    
    public class FormsfxApp extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
    
        @Override
        public void start(Stage primaryStage) throws Exception {
    
            StringProperty name = new SimpleStringProperty("my name");
            name.addListener((observable, oldValue, newValue) -> System.out.println("new name:" + newValue));
            IntegerProperty age = new SimpleIntegerProperty(10);
            age.addListener((observable, oldValue, newValue) -> System.out.println("new age:" + newValue));
    
            ObjectProperty<String> selected = new SimpleObjectProperty<>("aaa");
            selected.addListener((observable, oldValue, newValue) -> System.out.println("select:" + newValue));
            ListProperty<String> items = new SimpleListProperty<>(
                    FXCollections.observableArrayList("aaa", "bbb", "ccc")
            );
    
            Form form = Form.of(
                    Group.of(
                            Field.ofStringType(name),
                            Field.ofIntegerType(age),
                            Field.ofSingleSelectionType(items, selected)
                    )
            ).title("test persist");
    
            BorderPane borderPane = new BorderPane();
            borderPane.setCenter(new FormRenderer(form));
            primaryStage.setScene(new Scene(borderPane, 1000, 600));
            primaryStage.show();
        }
    }
    

    screen shot

    Other Fields like StringField and IntegerField change property only when form.persis() is called explicitly. But selected property in SingleSelectionField is eagerly modified in every time I select other item in combo box.

    I find there is a persistentSelection field in SingleSelectionField:

    https://github.com/dlsc-software-consulting-gmbh/FormsFX/blob/cf37703cd514536f0548cd3b09b187cc6e6ac8e9/formsfx-core/src/main/java/com/dlsc/formsfx/model/structure/SingleSelectionField.java#L50

    But why it is not exposed for user?

    opened by DQinYuan 0
Releases(v11.5.0)
Owner
DLSC Software & Consulting GmbH
DLSC Software & Consulting GmbH
Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE 8 and provides the functionalities to use and handle easily Tiles in your JavaFX application.

Lib-Tile Intention Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE and provides the functionalities to use and handle easily Tile

Peter Rogge 13 Apr 13, 2022
A Java framework for creating sophisticated calendar views (JavaFX 8, 9, 10, and 11)

CalendarFX A Java framework for creating sophisticated calendar views based on JavaFX. A detailed developer manual can be found online: CalendarFX 8 D

DLSC Software & Consulting GmbH 660 Jan 6, 2023
A library for creating and editing graph-like diagrams in JavaFX.

Graph Editor A library for creating and editing graph-like diagrams in JavaFX. This project is a fork of tesis-dynaware/graph-editor 1.3.1, which is n

Steffen 125 Jan 1, 2023
Tray Icon implementation for JavaFX applications. Say goodbye to using AWT's SystemTray icon, instead use a JavaFX Tray Icon.

FXTrayIcon Library intended for use in JavaFX applications that makes adding a System Tray icon easier. The FXTrayIcon class handles all the messy AWT

Dustin Redmond 248 Dec 30, 2022
DataFX - is a JavaFX frameworks that provides additional features to create MVC based applications in JavaFX by providing routing and a context for CDI.

What you’ve stumbled upon here is a project that intends to make retrieving, massaging, populating, viewing, and editing data in JavaFX UI controls ea

Guigarage 110 Dec 29, 2022
An Android library that allows you to easily create applications with slide-in menus.

An Android library that allows you to easily create applications with slide-in menus. You may use it in your Android apps provided that you cite this project and include the license in your app. Thanks!

Jeremy Feinstein 11.1k Jan 4, 2023
Tool for creating custom GUIs using packets.

Tool for creating custom GUIs using packets.

Geo3gamer 0 Feb 14, 2022
Docking framework for JavaFX platform

Docking framework for JavaFX platform AnchorFX is a gratis and open source library for JavaFX to create graphical interfaces with docking features Anc

Alessio Vinerbi 197 Oct 15, 2022
A JavaFX UI framework to create fully customized undecorated windows

CustomStage A JavaFX undecorated stage which can fully be customized Donations If this project is helpful to you and love my work and feel like showin

Oshan Mendis 186 Jan 6, 2023
Desktop/Mobile JavaFX application framework

Basilisk is desktop/mobile application development platform for the JVM. Inspired by Griffon, Basilisk leverages JavaFX and JavafXPorts to bring the s

Basilisk 55 Feb 10, 2022
an Application Framework for implementing the MVVM Pattern with JavaFX

mvvmFX is an application framework which provides you necessary components to implement the MVVM pattern with JavaFX. MVVM is the enhanced version of

Alexander Casall 438 Dec 28, 2022
Lightweight JavaFX Framework for Kotlin

TornadoFX JavaFX Framework for Kotlin Important: TornadoFX is not yet compatible with Java 9/10 Oracle is intending to decouple JavaFX from the JDK. W

Edvin Syse 3.6k Dec 29, 2022
A lightweight RCP framework for JavaFX applications.

WorkbenchFX The one and only framework to build large JavaFX Applications! Maven To use this framework as part of your Maven build simply add the foll

DLSC Software & Consulting GmbH 471 Jan 8, 2023
😉PrettyZoo is a GUI for Zookeeper created by JavaFX and Apache Curator Framework.

?? Pretty nice Zookeeper GUI, Support Win / Mac / Linux Platform

vran 2.4k Jan 5, 2023
JavaFX micro-framework that follows MVVM Pattern with Google Guice dependency Injection

ReactiveDeskFX (JavaFX and Google Guice MVVM Pattern micro-framework) JavaFX micro-framework to develop very fast JavaFX components with minimal code

TangoraBox 3 Jan 9, 2022
Collection of Binding helpers for JavaFX(8)

Advanced-Bindings for JavaFX (8) advanced-bindings is a collection of useful helpers and custom binding implementations to simplify the development of

Manuel Mauky 63 Nov 19, 2022
A library of +70 ready-to-use animations for JavaFX

AnimateFX A library of ready-to-use animations for JavaFX Features: Custom animations Custom interpolators Play/Stop animation Play an animation after

Loïc Sculier 366 Jan 5, 2023
BootstrapFX: Bootstrap for JavaFX

BootstrapFX BootstrapFX is a partial port of Twitter Bootstrap for JavaFX. It mainly provides a CSS stylesheet that closely resembles the original whi

Kordamp 810 Dec 28, 2022
Allow runtime modification of JavaFX CSS

cssfx ⚠ WARNING ⚠ In version 11.3.0 we have relocated & refactored the project. maven groupId has been changed to fr.brouillard.oss java module name h

Matthieu Brouillard 134 Jan 2, 2023