Functional Reactive Programming (FRP) for JavaFX

Related tags

GUI reduxfx
Overview

ReduxFX

Functional Reactive Programming (FRP) for JavaFX

Build Status Bintray Maven License

Lines of Code Bugs Vulnerabilities Code Smells Duplicated Lines Technical Dept Ratio Code Coverage

ReduxFX in 1 minute

ReduxFX is a set of libraries that enable you to use functional reactive programming in your JavaFX applications.

The libraries are written in plain Java. Therefore you can use any language that runs on the JVM and still reap the benefits of functional programming. All data structures of a ReduxFX application are immutable and all functions are pure. This simplifies the creation, testing, and maintenance of code compared to imperative programming, which ultimately leads to faster development and fewer bugs.

All changes and messages "flow" in a single circular stream, which makes it perfectly clear what is going on in your application and helps to quickly find the source of any bug. On top of it, this architecture enables advanced development tools like a "time travelling debugger" that can be used to step back and forth in your application, which again makes it easier to understand the application code and find bugs.

How to add ReduxFX to your project

ReduxFX consists of several libraries. To simplify the start, you can use the aggregate reduxfx-all, which contains all ReduxFX-libraries.

Maven

<dependency>
    <groupId>com.netopyr.reduxfx</groupId>
    <artifactId>reduxfx-all</artifactId>
    <version>0.4.1</version>
    <type>pom</type>
</dependency>

Functional Reactive UI Programming

The following section is a brief introduction of the core concepts of functional reactive UI programming taken from my article "MVC is dead - what comes next?" If you are familiar with functional reactive UI programming and already bought into it, you can jump straight to the TodoMVC JavaFX example.

On the face of it, frameworks like React.js with the Redux-architecture, Elm, and Cycle.js seem quite different. But under the hood, all of them share a simple idea, which is sketched in the following picture:

alt Overview functional reactive UI programming

The first thing to note when looking at the picture is that everything – all changes, events, and updates – flow in a single direction to form a cycle. The cycle consists of four data-structures (State, Virtual DOM, Event, and Action) and four components (View()-Function, DOM-Driver, ActionCreator, and Updater). The DOM-Driver is provided by the framework, while the other components have to be implemented by the application developer.

Let’s assume our application, a todo-list, is already running for a while and the user presses a button to create a new entry in the todo-list. This will result in a button-clicked event in the DOM, which is captured by the DOM-Driver and forwarded to one of our ActionCreators.

The ActionCreator takes the DOM-event and maps it to an action. Actions are an implementation of the Command Pattern, i.e. they describe what should be done, but do not modify anything themselves. In our example, we create an AddToDoItemAction and pass it to the Updater.

The Updater contains the application logic. It keeps a reference to the current state of the application. Every time it receives an action from one of the ActionCreators, it generates the new state. In our example, if the current state contains three todo-items and we receive the AddToDoItemAction, the Updater will create a new state that contains the existing todo-items plus a new one.

The state is passed to the View()-Function, which generates the so-called Virtual DOM. As the name suggests, the Virtual DOM is not the real DOM, but it is a data-structure that only describes the DOM.

The Virtual DOM is passed to the DOM-Driver which will update the DOM and wait for the next user input. With this, the cycle ends.

Advantages

Functional reactive UI Programming has three major advantages over traditional approaches, all of them are huge: straightforward testing, a comprehensive flow of events, and time travels (yes, seriously).

Straightforward testing

The View()-Function and the ActionCreators are simple mappings, while the Updater performs a fold (also often called a reduce) on the Actions it receives.

All components are pure functions and pure functions are extremely easy to test.

The outcome of a pure function depends only on the input parameters and they do not have any side effects. To test a pure function, it is sufficient to create the input parameter, run the “function under test” and compare the outcome. No mockups, no dependency injection, no complex setup, and no other techniques are necessary that take the fun out of testing.

Comprehensive Flow of Events

Reactive programming is a lot of fun – except when it is not. The control flow of graphical user interfaces is inherently event-based. An application has to react to button-clicks, keyboard input, and other events from users, sensors, and servers. Applying reactive techniques, be it the Observer Pattern, data-bindings, or reactive streams, comes naturally.

Unfortunately, these techniques come with a price. If a component A calls a component B, it is simple to see the connection in your IDE or debugger. But if both components are connected via events, the relationship is not as obvious. The larger the application becomes, the harder it gets to understand its internals.

The architecture of a functional reactive application avoids these problems by defining a simple flow of events that all components must follow.

No matter how large your application grows, the flow of events will never change.

Time Travel

Functional reactive applications allow you to travel back and forth in time – at least in the context of your application. If we store the initial state and all actions, we can use a technique called “Event Sourcing”. By replaying the actions, we can recalculate every state the application was in. If we replay only the last n-1, n-2, n-3… actions, we can actually step back in time. And by modifying the recorded stream of actions while applying them, we can even change the past. As you can imagine this can be very handy during development and bugfixing.

The first time-traveling debuggers have been built, but I think we have only started to understand the possibilities, and more amazing tools will be released in the near future.

TodoMVC JavaFX Example

All data structures in the TodoMVC JavaFX Example are immutable. Unfortunately the standard collections in the JDK are problematic, if you want to enforce immutability. Therefore in the example makes heavy use of Javaslang and its truly immutable collections.

State

The package com.netopyr.reduxfx.todo.state contains all classes related to the state of the TodoMVC JavaFX Example. The main class is AppModel.

public final class AppModel {

    private final String newTodoText;
    private final Seq<TodoEntry> todos;
    private final Filter filter;
    
    // constructor, getters, and toString()
    // ...

}

The property todos is of type Seq, which is part of Javaslang. Seq is similar to Iterable in the JDK, because it is the supertype of all sequential data structures in Javaslang, though Seq offers much more functionality. In other words todos is a list of TodoEntries.

The property newTodoText contains the text stored in the TextField for new todo-entries. Last but not least, the property filter stores the filter which is currently set (ALL, ACTIVE or COMPLETED).

public final class TodoEntry {

    private final int id;
    private final String text;
    private final boolean completed;
    private final boolean hover;
    private final boolean editMode;
    
    // constructor, getters, and toString()
    // ...

}    

A TodoEntry has five properties, which store the id, the text describing the todo-item, a flag to signal if it is completed, and two flags that define if the user is currently hovering over the entry and if the todo-item is in edit mode.

View-Function

The View-Function kept in the package com.netopyr.reduxfx.todo.view defines the view of the TodoMVC JavaFX example. This is the least stable part of ReduxFX and you can expect significant changes in the future in this area.

The view in a functional reactive UI application is defined as a mapping from the application state (AppModel in this example) to the corresponding VirtualScenegraph. The VirtualScenegraph is an immutable data structure that defines what the real JavaFX should look like.

The current API of ReduxFX is an attempt to combine the readability of a template-like approach with the expressiveness of a functional approach. The entry point is the class MainView.

public class MainView {

    private MainView() {}

    public static VNode<Action> view(AppModel state) {
        return
            VBox(
                alignment(Pos.CENTER),
                minWidth(Region.USE_PREF_SIZE),
                minHeight(Region.USE_PREF_SIZE),
                maxWidth(Region.USE_PREF_SIZE),
                maxHeight(Region.USE_PREF_SIZE),
                stylesheets("main.css"),

                Label(
                        id("title"),
                        text("todos")
                ),

                AddItemView(state),
                ItemOverviewView(state),
                ControlsView(state)
            );
    }
}

There is just one method view(), which takes an AppModel and returns a VNode, the root node of the VirtualScenegraph. Within the view()-method three kind of methods to define the VirtualScenegraph are used. VBox() and Label() define regular JavaFX Nodes. The methods alignment(), stylesheets(), minWidth() etc. set properties of these nodes. Last but not least there are AddItemView(), ItemOverviewView(), and ControlsView() which specify custom components of the application. The most interesting custom component is probably ItemOverviewView.

class ItemOverviewView {

    static VNode<Action> ItemOverviewView(AppModel state) {
        return AnchorPane(
            minWidth(Region.USE_PREF_SIZE),
            // more properties
            // ...
            ListView(
                // more properties
                // ...
                items(state.getTodos()
                    .filter(todoEntry -> {
                        switch (state.getFilter()) {
                            case COMPLETED:
                                return todoEntry.isCompleted();
                            case ACTIVE:
                                return !todoEntry.isCompleted();
                            default:
                                return true;
                        }
                    })
                ),
                cellFactory(todoEntry -> ItemView((TodoEntry) todoEntry))
            )
        );
    }
}

The method ItemOverviewView() is very similar to the MainView-method. It takes the current application state AppModel and returns the root node of that part of the VirtualScenegraph that specifies the list of items. The interesting part is the definition of a ListView. There are two main properties items and cellFactory.

The property items contains the list of todo-items that should be shown. Depending on the filter setting, we want to show all items or filter either the completed or active entries. As you can see, using a declarative approach makes it pretty simple to define such a filtered list.

With the cellFactory, we can setup a mapping between an entry in the items-list and the VirtualScenegraph. In the example we want to show an ItemView for each entry, which is another custom component.

Action Creators

Action Creators map UI-events to application specific actions. The package com.netopyr.reduxfx.todo.actions contains everything related to actions.

All Actions in this example implement the marker interface Action.

public interface Action {
}

Each action has two parts, a factory method and an implementation. The factory methods of all actions are defined in the Actions class. The following code snippet shows the factory method for DeleteTodoAction.

public final class Actions {

    private Actions() {}
    
    public static Action deleteTodo(int id) {
        return new DeleteTodo(id);
    }

    // more factory methods and Action-classes
    // ...
}

DeleteTodo is immutable and contains a single property id, which references the todo-entry that needs to be deleted. Adding the factory method helps to hide the actual Actions implementation from the event-handlers.

public static final class DeleteTodo implements Action {

    private final int id;

    // constructor, getter, and toString()
    // ...
}

Updater

The heart of every ReduxFX-application is the updater. It is a BiFunction, which takes the old state and an action and calculates the new state. In this application, it is defined in the class Updater.

The example uses the pattern-matching API of Javaslang. Each branch handles one specific action-type. Below you can see an excerpt from the updater of the example application. It shows the cases of the actions NewTextfieldChanged and AddTodo.

The action NewTextFieldChanged is triggered when the text in the textfield above the todo-list is changed. The action has a single property text which contains the new value. A new AppModel is created with the updated value for newTodoText, while the todo-entries and filter are copied from the old state. This is a typical implementation of the updater. Only a small section is changed, while most parts are just copied.

final AppModel newState =

        Match(action).of(

                Case(instanceOf(NewTextFieldChangedAction.class),
                        newTextFieldChangedAction ->
                                state.withNewTodoText(newTextFieldChangedAction.getText())
                ),

                Case(instanceOf(AddTodoAction.class),
                        state.withNewTodoText("")
                                .withTodos(
                                        state.getTodos().append(
                                                TodoEntry.create()
                                                        .withId(
                                                                state.getTodos()
                                                                        .map(TodoEntry::getId)
                                                                        .max()
                                                                        .getOrElse(-1) + 1
                                                        )
                                                        .withText(state.getNewTodoText())
                                        )
                                )
                ),
        
                // more branches
                // ...

The AddTodo-action is slightly more complex. We define the new state, for which we clear the newTodoText, i.e. we clear the Textfield. For the todo-entries we take the old list and add a new TodoEntry. The collection returned from oldState.getTodos() is a Javaslang collection. Calling append() does not modify the original list, but returns the new list.

The id of the new TodoEntry is the current maximum id + 1. The text is taken from newTodoText of the old state. (The newTodoText of the new state is cleared, while the old state still points to the current value.) All flags are set to false initially. The filter is again just copied from the old state.

Launcher

The launcher TodoMVC is the last part of the example. As usual in JavaFX, we extend the Application class. To start a ReduxFX application, we need to define the initial state. In our case it has an empty newTodoText, zero todo-items, and the filter is set to show all entries. Next we need to call ReduxFX.start with the initial state, the updater-function, the view-function, and the stage where the SceneGraph should be shown.

public class Launcher extends Application {

    public void start(Stage primaryStage) throws Exception {

        final AppModel initialState = new AppModel("", Array.empty(), Filter.ALL);

        ReduxFX.start(initialState, Todos::update, MainView::view, primaryStage);

        primaryStage.setTitle("TodoMVCFX - ReduxFX");
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Summary

The experiment was successful. Not only did it show that one is able to write a JavaFX application with a functional reactive approach, but it even turned out to be quite a lot of fun.

There are certainly still areas that need improvement. Sometimes Java's verbosity is annoying. On the other hand being able to define truly immutable data structures and to take advantage of static types makes some parts even more suitable for this approach than a JavaScript implementation.

If you have any comments, suggestions or questions, please create a new issue. If you want to help spread the word, I am certainly also happy about any tweet, post or other mentioning of ReduxFX.

Further Reading

ReduxFX and the outside world

Comments
  • FXML support

    FXML support

    Hi Michael,

    at javaland we have already discussed about how we could add FXML support to ReduxFX. I've worked on a prototype that is inspired by the angular implementation of Redux. I've tried to get this working with your existing ReduxFX codebase but I had a hard time to get it working so instead I created the prototype in a separate repository: https://github.com/lestard/redux-javafx-example. I hope that we can integrate this into your ReduxFX project at some point.

    Separating Redux and JavaFX

    In my prototype I've created a simple Redux implementation that is completely separated from any JavaFX specific code: https://github.com/lestard/redux-javafx-example/blob/master/src/main/java/redux/ReduxStore.java It takes the initial state and a reducer. Like with the original redux you have a dispatch method that is used to dispatch actions and you can add subscribers that are invoked when the store is updated.

    In the example I was creating the Views with standard JavaFX classes and FXML. My "Controller"-classes that are backing the FXML files implement an interface View which provides 2 features:

    1. a dispatch method that can be used to dispatch new actions
    2. some select methods. This is what I've taken from Angular-Redux.

    The select method takes a "Selector" (a Function that takes the State as argument and returns a specific slice or value from this state) and returns an ObservableValue or an ObservableList. Everytime the store gets updated these observables will get the new values provided by the selector. This way you can bind your JavaFX Controls to the state of the Redux store.

    This can look like this:

    public class ControlsView implements View {
    
        @FXML
        public Label itemsLeftLabel;
    
        public void initialize(){
            itemsLeftLabel.textProperty().bind(
                    Bindings.concat(select(Selectors.numberOfItemsLeft), " items left"));
        }
    
        public void all() {
            dispatch(Actions.setFilter(Filter.ALL));
        }
    
        public void active() {
            dispatch(Actions.setFilter(Filter.ACTIVE));
        }
    
        public void completed() {
            dispatch(Actions.setFilter(Filter.COMPLETED));
        }
    }
    

    It means that all UI components are stateful. I know that this is not as clean and elegant as your VNode approach but this way we can use FXML.

    ListViews

    As you've already mentioned at javaland the handling of ListViews is problematic. I've had this problem already for FluxFX and I've copied the solution from there. It's solved with a special CellFactory that updates items when the underlying data has changed. This is also not a really clean solution but at least it works ;-) Maybe we can find a better approach. As I've said, it's all just a prototype.

    Open questions

    I hope you find the time to take a look at the prototype. Maybe we could change the API of ReduxFX so that it's not coupled to your VNode approach only. At the moment we have this code to startup ReduxFX:

    ReduxFX.start(initialState, Todos::update, MainView::view, primaryStage);
    

    In my example I've come up with this API:

    ReduxStore<AppModel> store = ReduxStore.create(initialState, Updater::update);
    
    ReduxJavaFX.connect(store);
    

    This separates the Redux Store and the UI part. This is similar to redux and react-redux. Maybe we could do the same for the Java(FX) library: A Core Redux library and a separate module with your VSceneGraph and another module with the FXML approach?

    Bonus Middleware

    While developing I've got the need for debugging and implemented a Logging-Middleware, inspired by the middleware concept of the original Redux implementation. Maybe this sort of extension mechanism could be added to ReduxFX too.

    kind regards, Manuel

    opened by manuel-mauky 11
  • fix IndexOutOfBoundException in Patcher on RemovePatch

    fix IndexOutOfBoundException in Patcher on RemovePatch

    I've found a possible IndexOutOfBoundException in Patcher.java.

    Think of the following example: Before the an Action is applied a TreeView has 3 Children. After the Action, the TreeView is empty. The Differ calculates that 3 RemovePatches have to be applied to he VSceneGraph.

    This is done in Differ.java (Line 108-110). However, the problem here is the iteration. The for loop runs from 0 to 2 and adds the RemovePatches in this order. Now we have:

    RemovePatch(index=0,...) RemovePatch(index=1,...) RemovePatch(index=2,...)

    In Patcher 148-155 these patches are applied. However, the third patch can't be applied because there is no element with index=2 left anymore. Instead an IndexOutOfBoundException is thrown.

    To fix this the order of the patches has to be reversed. The patch with the highest index has to be applied first. To do this I've reversed the for-loop in Differ.java to count from 2 to 0 instead.

    I've tried out this fix with a small app and it solved the problem without noticing any negative side effects. However, I don't know if this breaks some other use-cases that I haven't thought about.

    opened by manuel-mauky 3
  • Can't seem to get 0.3.0 from JCenter or MavenCentral

    Can't seem to get 0.3.0 from JCenter or MavenCentral

    Gradle/Ivy seems to want a redux-all artifact that doesn't exist:

    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Could not resolve all dependencies for configuration ':compileClasspath'.
    > Could not resolve com.netopyr.reduxfx:reduxfx:0.3.0.
      Required by:
          project :
       > Could not resolve com.netopyr.reduxfx:reduxfx:0.3.0.
          > Could not parse POM https://jcenter.bintray.com/com/netopyr/reduxfx/reduxfx/0.3.0/reduxfx-0.3.0.pom
             > Could not find com.netopyr.reduxfx:reduxfx-all:0.3.0.
               Searched in the following locations:
                   https://jcenter.bintray.com/com/netopyr/reduxfx/reduxfx-all/0.3.0/reduxfx-all-0.3.0.pom
                   https://jcenter.bintray.com/com/netopyr/reduxfx/reduxfx-all/0.3.0/reduxfx-all-0.3.0.jar
    
    bug in progress 
    opened by chronodm 3
  • add selection to ListView

    add selection to ListView

    At the moment the VNode ListView doesn't support selection of items (at least I haven't seen the possibility to do so). This includes 2 aspects: I like to be able to define which items are selected based on the state and I like to dispatch an action when the user selects an item.

    I've tried to add this functionality and to provide a PullRequest but I haven't understood how to add this with the existing builders. I think the reason is that the selection is not just a property on the ListView but instead in normal JavaFX you have to use the SelectionModel from the ListView.

    If you can give me some hints on how this should be implemented I'm happy to provide a PullRequest.

    opened by manuel-mauky 2
  • ActionType vs. the class of the action

    ActionType vs. the class of the action

    Hello @netopyr ,

    thanks for creating reduxfx, it looks really nice. @lestard told me yesterday about it...

    I just looked into the documentation. Isn't the ActionType redundant to the action class? Since an action could carry some data, an updater implementation would anyway need to cast the action to the specific action class to access the "action data". Therefor an updater implementation could implement "the switch" using instanceof (with if/else if/else... or of course some fancy javaslang pattern matching) without using the ActionType.

    Would do you think?

    Best regards, Peti

    opened by Petikoch 2
  • Add separate fxml module

    Add separate fxml module

    I've refactored the code to use FXML files and moved it to it's own sub-module so that it can be used by library users.

    In this process I've also refactored the code so that now no singleton is used anymore. Instead the user has to use some dependency injection library to access the redux store from the FXML controllers. For this purpose I've introduces two interfaces (Dispatcher and Selector) that the controllers can use. This way the user also doesn't need to implement a separate View interface.

    I've also tried to get the API a little closer to your functional API.

    opened by manuel-mauky 1
  • Problem with ReduxFX.start and Bifunction

    Problem with ReduxFX.start and Bifunction

    Hello,

    I'm trying to implement an example with ReduxFX but I have a problem that is keeping me from using this project.

    Here's an example:

    @Override
        public void start(Stage mainStage) throws Exception {
            final AppState initialState = AppState.create();
    
            ReduxFX.start(
                initialState,
                IncrementReducer::update,
                HomeView::view,
                mainStage);
        }
    
    public class HomeView {
    
        public static VNode view(AppState state) {
            Objects.requireNonNull(state, "The parameter 'state' must not be null");
    
            return Stage().....;
        }
    }
    
    public class IncrementReducer {
    
    
        public static AppState update(AppState state, Object action) {
            Objects.requireNonNull(state, "The parameter 'state' must not be null");
            Objects.requireNonNull(action, "The parameter 'action' must not be null");
    
            // This is part of Javaslang's pattern-matching API. It works similar to the regular switch-case
            // in Java, except that it is much more flexible and returns a value.
            // We check which of the cases is true and in that branch we specify the newState.
            return Match(action).of(
    
                    // If the action is a IncCounterAction, we return a new AppState with an increased counter
                    Case(instanceOf(IncrementReducer.class),
                            incCounterAction -> state.withCounter(state.getCounter() + 1)
                    ),
    
                    // This is the default branch of this switch-case. If an unknown Action was passed to the
                    // updater, we simply return the old state. This is a convention, that is not needed right
                    // now, but will help once you start to decompose your updater.
                    Case($(), state)
            );
        }
    }
    

    The Intellij hint gives me this alert Cannot resolve method 'start(com.renanliberato.app.state.AppState, <method reference>, <method reference>, javafx.stage.Stage)' and if I try to run it, it gives me this error:

    Error:(28, 16) java: no suitable method found for start(com.renanliberato.app.state.AppState,IncrementR[...]pdate,HomeView::view,javafx.stage.Stage)
        method com.netopyr.reduxfx.ReduxFX.<STATE>start(STATE,java.util.function.BiFunction<STATE,java.lang.Object,com.netopyr.reduxfx.updater.Update<STATE>>,java.util.function.Function<STATE,com.netopyr.reduxfx.vscenegraph.VNode>,javafx.stage.Stage) is not applicable
          (cannot infer type-variable(s) STATE
            (argument mismatch; bad return type in method reference
              com.renanliberato.app.state.AppState cannot be converted to com.netopyr.reduxfx.updater.Update<STATE>))
        method com.netopyr.reduxfx.ReduxFX.<STATE>start(STATE,java.util.function.BiFunction<STATE,java.lang.Object,com.netopyr.reduxfx.updater.Update<STATE>>,java.util.function.Function<STATE,com.netopyr.reduxfx.vscenegraph.VNode>,javafx.scene.Group) is not applicable
          (cannot infer type-variable(s) STATE
            (argument mismatch; bad return type in method reference
              com.renanliberato.app.state.AppState cannot be converted to com.netopyr.reduxfx.updater.Update<STATE>))
        method com.netopyr.reduxfx.ReduxFX.<STATE>start(STATE,java.util.function.BiFunction<STATE,java.lang.Object,com.netopyr.reduxfx.updater.Update<STATE>>,java.util.function.Function<STATE,com.netopyr.reduxfx.vscenegraph.VNode>,javafx.scene.layout.Pane) is not applicable
          (cannot infer type-variable(s) STATE
            (argument mismatch; bad return type in method reference
              com.renanliberato.app.state.AppState cannot be converted to com.netopyr.reduxfx.updater.Update<STATE>))
    

    In my pom.xml file I've imported this dependency, as included in the README.md:

    <dependency>
        <groupId>com.netopyr.reduxfx</groupId>
        <artifactId>reduxfx</artifactId>
        <version>0.3.1</version>
    </dependency>
    

    I'd appreciate to know if this is some misunderstanding that I've made with Bifunction or anything else, because this may be an example of problems someone who didn't know this project may run when trying to implement it.

    Will it help if I submit a gist with a more complete code example?

    opened by renanliberato 1
  • readme: add coordinates to maven artifacts

    readme: add coordinates to maven artifacts

    The README.md could have a reference to the Maven artifacts. The shields badge automatically refers to the current version. I've also added snippets of other common ways to refer to the artifacts, which require to manually update the version string on every release.

    As shields badge:

    [![Maven](https://img.shields.io/maven-central/v/com.netopyr.reduxfx/reduxfx.svg?label=com.netopyr.reduxfx)](https://search.maven.org/#search|ga|1|com.netopyr.reduxfx)
    

    Maven

    As maven coordinates table:

    | Group ID            | Artifact ID | Version |
    | :-----------------: | :---------: | :-----: |
    | com.netopyr.reduxfx | reduxfx     | 0.1.0   |
    

    | Group ID | Artifact ID | Version | | :-----------------: | :---------: | :-----: | | com.netopyr.reduxfx | reduxfx | 0.1.0 |

    For maven pom xml:

    <dependencies>
        <dependency>
            <groupId>com.netopyr.reduxfx</groupId>
            <artifactId>reduxfx</artifactId>
            <version>0.1.0</version>
        </dependency>
    </dependencies>
    

    For gradle build file:

    dependencies {
        compile "com.netopyr.reduxfx:reduxfx:0.1.0"
    }
    

    As maven repository index url:

    • http://central.maven.org/maven2/com/netopyr/reduxfx/reduxfx/
    • https://mvnrepository.com/artifact/com.netopyr.reduxfx/reduxfx
    • https://search.maven.org/#search|ga|1|com.netopyr.reduxfx
    enhancement 
    opened by hastebrot 1
  • Tabpane

    Tabpane

    implemented Builders for TabPane and Tab.

    During testing the TabPane I've found that ContextMenuBuilder takes items of type VNode while the original ContextMenu takes items of type MenuItem.

    opened by manuel-mauky 0
  • Add VNode Treeview

    Add VNode Treeview

    I've implemented a VNode version of JavaFX TreeView and TreeItem.

    To implement the TreeItem I've fixed a problem in NodeUtils in the getProperties method. This method was returning Collections.emptyMap() when the node had a type other then Node, Scene,Window or Dialog. This is the case for TreeItem in JavaFX which is not a subclass of Node. The problem was that Collections.emptyMap() doesn't support adding new items.

    Additionally, I've created an example project that uses the TreeView. The project visualizes a "Scrum" project with Sprints and Stories. For the example app I'm using a VBox with "vgrow" property for which I've created a separate PR #54. To be able to use this fix in the example app I've cherry-picked the commit to use it in this branch too.

    opened by manuel-mauky 0
  • Add splitpane to reduxfx-view

    Add splitpane to reduxfx-view

    I've added a builder for JavaFX SplitPane.

    I had a problem with the setDividerPositions method because it takes an array of double values. This caused a ClassCastException in SetterAccessor. After a short google research I think the reason is that there is some problem with var-args expansion of array arguments. I solved this by checking the type of the argument and explicitly casting it. Maybe there is a clearer solution to this?

    opened by manuel-mauky 0
  • Invalid dependency in pom

    Invalid dependency in pom

    Hi, I tried to add the reduxfx dependency to a project as described in the README, however the fontsawesome package cannot be downloaded via maven anymore.

    [ERROR] Failed to execute goal on project wallet: Could not resolve dependencies for project xxx.jar:0.0.1-SNAPSHOT: Failed to collect dependencies at com.netopyr.reduxfx:reduxfx-all:pom:0.4.1 -> com.netopyr.reduxfx:reduxfx-fontawesomefx:jar:0.4.1 -> de.jensd:fontawesomefx-commons:jar:8.15: Failed to read artifact descriptor for de.jensd:fontawesomefx-commons:jar:8.15: Could not transfer artifact de.jensd:fontawesomefx-commons:pom:8.15 from/to bintray (http://jcenter.bintray.com): Access denied to: http://jcenter.bintray.com/de/jensd/fontawesomefx-commons/8.15/fontawesomefx-commons-8.15.pom -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException

    Basically jcenter started enforcing HTTPS and therefore one gets 403 when trying to download it.

    opened by fafk 2
  • How to start asynchronous actions?

    How to start asynchronous actions?

    I need to start an action asynchronously, but I don't see how to access the dispatcher? With JS redux, it is explicitly created, but I don't see an API for that here. Is there one?

    TIA! Chris

    opened by ChrisLMerrill 0
  • ReduxFxml create function; shouldn't it take a store (v0.4.1)?

    ReduxFxml create function; shouldn't it take a store (v0.4.1)?

    Hi Guys,

    We've been using ReduxFx, and following your ReduxFxml example. in the FxmlExample.java file you have the following line (34):

    ReduxFxml<AppState> reduxFxml = ReduxFxml.create(store);

    However, in our project, pulling the latest version from Maven (v0.4.1) the create function does not seem to take a ReduxFXStore parameter, as your example code suggests? Is this a known inconsistency, or is the example outdated?

    Many thanks!

    opened by chris-jan-dudley 2
  • Scenegraph-Abstraction

    Scenegraph-Abstraction

    Try to define an abstraction of the Scenegraph to be used by the Patcher instead of manipulated the Scenegraph directly. This would make the functionality and tests much simpler.

    enhancement 
    opened by netopyr 0
Releases(0.2.0)
Owner
Michael Heinrichs
Michael Heinrichs
Reactive event streams, observable values and more for JavaFX.

ReactFX ReactFX is an exploration of (functional) reactive programming techniques for JavaFX. These techniques usually result in more concise code, le

Tomas Mikula 360 Dec 28, 2022
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
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
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
Methods in various programming languages to validate Croatian identification number called OIB

OIB validation [ENG] Methods in various programming languages to validate Croatian identification number called OIB. More info on www.oib.hr. Provjera

Domagoj 30 Nov 23, 2022
The place to come for pair programming practice problems in your language, designed for new and old developers alike.

Coding Dojo About The Coding Dojo is a project and weekly meetup hosted by Code Connector to offer opportunities for learning, mentoring, and practici

Code Connector 55 Nov 18, 2022
A demo application to learn and explore all topic of Programming in Java Course.

Kakshya RMS A simple Java lab-work for the class of 'Programming in Java' Explore the docs » View Demo · Report Bug · Request Feature Table of Content

Bikram Parajuli 16 Jun 8, 2022
A GUI-based file manager based on a Java file management and I/O framework using object-oriented programming ideas.

FileManager A GUI-based file manager based on a Java file management and I/O framework using object-oriented programming ideas. Enables folder creatio

Zongyu Wu 4 Feb 7, 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
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 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
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
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
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
MDI components for JavaFX

DesktopPaneFX DesktopPaneFX is a JavaFX version of Swing’s JDesktopPane which can be used as a container for individual "child" similar to JInternalFr

Kordamp 58 Sep 23, 2022
Efficient VirtualFlow for JavaFX

Flowless Efficient VirtualFlow for JavaFX. VirtualFlow is a layout container that lays out cells in a vertical or horizontal flow. The main feature of

null 163 Nov 24, 2022
A framework for easily creating forms for a JavaFX UI.

FormsFX Forms for business application made easy. Creating forms in Java has never been this easy! Maven To use this framework as part of your Maven b

DLSC Software & Consulting GmbH 534 Dec 30, 2022
:icecream: iOS frosty/translucent effect to JavaFX

FroXty is JavaFX library which replicates the famous iOS translucent effect with ease. Set-up FroXty can be imported into your project either by downl

Giorgio Garofalo 33 Dec 11, 2022