Export to GitHub

pennychecker-presenter - JavaFxMvpExample.wiki


GettingStarted

Details

We create a simple user management. Users can be created, edited or deleted. In addition, all users are displayed in a list.

Events

We need two events. An event when a user's data have been changed and an event to announce that a new user to be created or edited.

``` public interface EditUserEventHandler extends EventHandler { void onEditUserEvent(EditUserEvent event); }

/** * * @author Steffen Kämpke */ public final class EditUserEvent extends Event {

public final static Type<EditUserEventHandler> TYPE = new Type<EditUserEventHandler>();
private final User user;

public EditUserEvent(User user) {
    this.user = user;
}

@Override
public Type<EditUserEventHandler> getAssociatedType() {
    return TYPE;
}

@Override
protected void dispatch(EditUserEventHandler h) {
    h.onEditUserEvent(this);
}

public User getUser() {
    return user;
}

} ```

``` public interface UserChangedEventHandler extends EventHandler { void onUserChangedEvent(UserChangedEvent event); }

/** * * @author Steffen Kämpke */ public final class UserChangedEvent extends Event {

public final static Type<UserChangedEventHandler> TYPE = new Type<UserChangedEventHandler>();
private final User user;

public UserChangedEvent(User user) {
    this.user = user;
}

@Override
public Type<UserChangedEventHandler> getAssociatedType() {
    return TYPE;
}

@Override
protected void dispatch(UserChangedEventHandler h) {
    h.onUserChangedEvent(this);
}

public User getUser() {
    return user;
}

} ```

Presenter

We need a presenter for the processing of a user.

``` /** * * @author Steffen Kämpke */ public final class EditUserPresenter extends FxPresenter {

private User selectedUser;
private final UserRepository userRepository;

/**
 * 
 * @param display
 * @param eventBus
 * @param userRepository  
 */
@Inject
public EditUserPresenter(Display display, EventBus eventBus, UserRepository userRepository) {
    super(display, eventBus);
    assert null != userRepository;
    this.userRepository = userRepository;
    bind();
}

@Override
protected void onBind() {

    registerHandler(eventBus.addHandler(EditUserEvent.TYPE, new EditUserEventHandler() {

        public void onEditUserEvent(EditUserEvent event) {
            selectedUser = event.getUser();

            if (null == selectedUser) {
                display.clearForm();
            } else {
                display.setUser(selectedUser);
            }

            eventBus.fireEvent(new PresenterRevealedEvent(EditUserPresenter.this));
        }
    }));

    display.getSaveButton().addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            saveUser();
        }
    });

    display.getCancelButton().addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            display.clearForm();
            eventBus.fireEvent(new UserChangedEvent(null));
        }
    });
}

@Override
protected void onUnbind() {
}

public void refreshDisplay() {
}

public interface Display extends FxDisplay {

    Node getSaveButton();

    Node getCancelButton();

    String getFirstname();

    String getLastName();

    public void setErrorMessage(String string);

    public void clearForm();

    public void setUser(User user);

    public void setWarningMessage(String string);
}

private void saveUser() {
    assert null != display.getFirstname();
    assert null != display.getLastName();
    final String firstname = display.getFirstname();
    final String lastname = display.getLastName();

    if (firstname.isEmpty()) {
        display.setWarningMessage("Please insert the firstname.");
        return;
    }

    if (lastname.isEmpty()) {
        display.setWarningMessage("Please insert the lastname.");
        return;
    }
    final User user;

    if (null == selectedUser) {
        user = new User(firstname, lastname);
    } else {
        user = selectedUser;
        user.setFirstname(firstname);
        user.setLastname(lastname);
    }
    try {
        userRepository.save(user);
    } catch (Exception ex) {
        Logger.getLogger(EditUserPresenter.class.getName()).log(Level.SEVERE, null, ex);
        display.setErrorMessage("Could not save the user.");
        return;
    }


    selectedUser = null;
    display.clearForm();

    eventBus.fireEvent(new UserChangedEvent(user));
}

} ```

To display all users, we need a presenter.

``` /** * * @author Steffen Kämpke */ public final class AllUserPresenter extends FxPresenter {

private final List<User> users = new ArrayList<User>();
private User selectedUser;
private final UserRepository userRepository;

/**
 * 
 * @param display
 * @param eventBus
 * @param userRepository 
 */
@Inject
public AllUserPresenter(Display display, EventBus eventBus, UserRepository userRepository) {
    super(display, eventBus);
    assert null != userRepository;
    this.userRepository = userRepository;
    bind();
    fetchUsers();
}

@Override
protected void onBind() {

    display.getUserList().addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {

        public void handle(MouseEvent event) {
            int index = display.getSelectedUserIndex();
            if (index < 0) {
                return;
            }
            selectedUser = users.get(index);
            display.setSelectedUser(selectedUser);
        }
    });

    display.getUserList().addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {

        public void handle(MouseEvent event) {
            if (event.getClickCount() == 2) {
                int index = display.getSelectedUserIndex();
                if (index < 0) {
                    return;
                }
                final User selectedUser = users.get(index);
                display.setSelectedUser(selectedUser);

                eventBus.fireEvent(new EditUserEvent(selectedUser));
            }
        }
    });

    registerHandler(eventBus.addHandler(UserChangedEvent.TYPE, new UserChangedEventHandler() {

        public void onUserChangedEvent(UserChangedEvent event) {

            User user = event.getUser();

            if (null == user) {
                firePresenterRevealedEvent();
                return;
            }

            if (!users.contains(user)) {
                users.add(user);
            }

            selectedUser = user;
            display.setSelectedUser(selectedUser);
            display.setUsers(users);
            display.setSelection(users.indexOf(user));
            firePresenterRevealedEvent();
        }
    }));

    display.getAddUserButton().addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            eventBus.fireEvent(new EditUserEvent(null));
        }
    });

    display.getEditUserButton().addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            if (null == selectedUser) {
                display.setWarning("Please select a user.");
                return;
            }

            eventBus.fireEvent(new EditUserEvent(selectedUser));
        }
    });

    display.getRemoveUserButton().addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            if (null == selectedUser) {
                display.setWarning("Select a user.");
                return;
            }
            users.remove(selectedUser);
            selectedUser = null;
            display.clearSelections();
            display.setUsers(users);
            display.setSelectedUser(selectedUser);
        }
    });
}

@Override
protected void onUnbind() {
}

public void refreshDisplay() {
}

private void fetchUsers() {
    users.clear();
    final List<User> userList;
    try {
        userList = userRepository.finaAll();
    } catch (Exception ex) {
        display.setError("Could not fetch users.");
        return;
    }

    display.setUsers(userList);
    display.clearSelections();
}

public interface Display extends FxDisplay {

    Node getUserList();

    Node getAddUserButton();

    Node getEditUserButton();

    Node getRemoveUserButton();

    public int getSelectedUserIndex();

    public void setSelectedUser(User selectedUser);

    public void setUsers(List<User> users);

    public void clearSelections();

    public void setSelection(int index);

    public void setWarning(String string);

    public void setError(String string);
}

public void firePresenterRevealedEvent() {
    eventBus.fireEvent(new PresenterRevealedEvent(AllUserPresenter.this));
}

} ```

We need a container presenter. He can easily manage presenter. E.g. Views can be placed on a PresenterRevealedEvent for viewing.

``` /** * * @author Steffen Kämpke */ public class UserContainerPresenter extends FxContainerPresenter {

/**
 * 
 * @param display
 * @param eventBus
 * @param editUserPresenter
 * @param allUserPresenter 
 */
@Inject
public UserContainerPresenter(Display display, EventBus eventBus, EditUserPresenter editUserPresenter, AllUserPresenter allUserPresenter) {
    super(display, eventBus, editUserPresenter, allUserPresenter);

    assert null != editUserPresenter;
    assert null != allUserPresenter;

    display.addParent(allUserPresenter.getDisplay().asParent());
    display.addParent(editUserPresenter.getDisplay().asParent());

    showPresenter(allUserPresenter);
    bind();
}

public void refreshDisplay() {
}

public interface Display extends FxContainerDisplay {
}

} ```

Views

For each presenter, we need a view. You can also encapsulates the logic for a view into multiple presenters.

All views implement their presenter display interfaces

View for the EditUserPresenter

``` /** * * @author Steffen Kämpke */ public final class EditUserView extends Parent implements EditUserPresenter.Display {

private TextBox textBoxFirstname;
private TextBox textBoxLastname;
private Label labelFirstname;
private Label labelLastname;
private Button buttonSave;
private Button buttonCancel;
private VBox vBox;

public EditUserView() {
    initialize();
}

public Node getSaveButton() {
    return buttonSave;
}

public Node getCancelButton() {
    return buttonCancel;
}

public String getFirstname() {
    return textBoxFirstname.getText();
}

public String getLastName() {
    return textBoxLastname.getText();
}

public void setErrorMessage(String string) {
}

public void clearForm() {
    textBoxFirstname.setText("");
    textBoxLastname.setText("");
}

public void setUser(User user) {
    if (null == user) {
        textBoxFirstname.setText("");
        textBoxLastname.setText("");
    } else {
        textBoxFirstname.setText(user.getFirstname());
        textBoxLastname.setText(user.getLastname());
    }
}

public void setWarningMessage(String string) {

}

public Parent asParent() {
    return this;
}

private void initialize() {
    textBoxFirstname = new TextBox();
    textBoxLastname = new TextBox();
    labelFirstname = new Label("Firstname");
    labelLastname = new Label("Lastname");
    buttonCancel = new Button("Cancel");
    buttonSave = new Button("Save");
    vBox = new VBox(10);
    vBox.getChildren().addAll(labelFirstname, textBoxFirstname, labelLastname, textBoxLastname, buttonCancel, buttonSave);
    this.getChildren().add(vBox);
    vBox.setPrefSize(500, 500);
    vBox.setStyle("-fx-background-color: #FBFFDB");

}

} ```

View for AllUserPresenter

``` /** * * @author Steffen Kämpke */ public final class AllUserView extends Parent implements AllUserPresenter.Display {

private Label labelFirstname;
private Label textLabelFirstname;
private Label labelLastname;
private Label textLabelLastname;
private ListView<String> userListView;
private Button buttonAddUser;
private Button buttonEditUser;
private Button buttonRemoveUser;
private VBox vBox;
private HBox userFirstnameBoxH;
private HBox userLastnameBoxH;
private HBox buttonBoxH;

public AllUserView() {
    initialize();
}

public Node getUserList() {
    return userListView;
}

public Node getAddUserButton() {
    return buttonAddUser;
}

public Node getEditUserButton() {
    return buttonEditUser;
}

public Node getRemoveUserButton() {
    return buttonRemoveUser;
}

public int getSelectedUserIndex() {
    return userListView.getSelectionModel().getSelectedIndex();
}

public void setSelectedUser(User selectedUser) {
    if (null == selectedUser) {
        textLabelFirstname.setText(" - ");
        textLabelLastname.setText(" - ");
    } else {
        textLabelFirstname.setText(selectedUser.getFirstname());
        textLabelLastname.setText(selectedUser.getLastname());
    }
}

public void setUsers(List<User> users) {
    final ObservableList<String> observableList = new ObservableListWrapper<String>(new ArrayList<String>());

    for (int i = 0; i < users.size(); i++) {
        final User user = users.get(i);
        observableList.add(i, user.getFirstname() + " " + user.getLastname());
    }

    userListView.setItems(observableList);
}

public void clearSelections() {
    userListView.getSelectionModel().clearSelection();
}

public void setSelection(int index) {
    userListView.getSelectionModel().select(index);
}

public void setWarning(String string) {
}

public void setError(String string) {
}

public Parent asParent() {
    return this;
}

private void initialize() {
    labelFirstname = new Label("Firstname");
    labelLastname = new Label("Lastname");
    textLabelFirstname = new Label(" - ");
    textLabelLastname = new Label(" - ");
    userListView = new ListView<String>(new ObservableListWrapper<String>(new ArrayList<String>()));
    buttonAddUser = new Button("Add");
    buttonEditUser = new Button("Edit");
    buttonRemoveUser = new Button("Remove");
    buttonBoxH = new HBox(10);
    buttonBoxH.getChildren().addAll(buttonRemoveUser,buttonEditUser,buttonAddUser);
    userFirstnameBoxH = new HBox(5);
    userLastnameBoxH = new HBox(5);
    userFirstnameBoxH.getChildren().addAll(labelFirstname, textLabelFirstname);
    userLastnameBoxH.getChildren().addAll(labelLastname, textLabelLastname);
    vBox = new VBox(10);
    vBox.setPrefSize(500, 500);
    vBox.setStyle("-fx-background-color: #FBFFDB");
    vBox.getChildren().addAll(userFirstnameBoxH, userLastnameBoxH, userListView, buttonBoxH);
    this.getChildren().add(vBox);
}

} ```

View for the UserContainer presenter

``` /** * * @author Steffen Kämpke */ public final class UserContainerView extends Parent implements UserContainerPresenter.Display {

private StackPane stackPane;

public UserContainerView() {
    initialize();
}

public void showParent(Parent parent) {
    parent.toFront();  
    for (Node node : parent.getChildrenUnmodifiable()) {
        node.requestFocus();
    }
}

public void addParent(Parent parent) {
    stackPane.getChildren().add(parent);
}

public void removeParent(Parent parent) {
    stackPane.getChildren().remove(parent);
}

public Parent asParent() {
    return this;
}

private void initialize() {
    stackPane = new StackPane();      
    this.getChildren().add(stackPane);
}

} ```

We still need a user.

``` public final class User {

private String id;
private String firstname;
private String lastname;

public User(String firstname, String lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
}

public String getFirstname() {
    return firstname;
}

public String getLastname() {
    return lastname;
}

public void setFirstname(String firstname) {
    this.firstname = firstname;
}

public void setLastname(String lastname) {
    this.lastname = lastname;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final User other = (User) obj;
    if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
        return false;
    }
    return true;
}

@Override
public int hashCode() {
    int hash = 7;
    hash = 37 * hash + (this.id != null ? this.id.hashCode() : 0);
    return hash;
}

} ```

GUICE configuration

``` /** * * @author Steffen Kämpke */ public final class MvpModule extends AbstractModule{

@Override
protected void configure() {
    bind(EditUserPresenter.Display.class).to(EditUserView.class).in(Singleton.class);
    bind(EditUserPresenter.class).in(Singleton.class);

    bind(AllUserPresenter.Display.class).to(AllUserView.class).in(Singleton.class);
    bind(AllUserPresenter.class).in(Singleton.class);

    bind(UserContainerPresenter.Display.class).to(UserContainerView.class).in(Singleton.class);
    bind(UserContainerPresenter.class).in(Singleton.class);

    bind(EventBus.class).toProvider(EventBusProvider.class).in(Singleton.class);

    bind(UserRepository.class);
}

} ```

Main Frame

``` /** * * @author Steffen Kämpke */ public class JfxMvpExample extends Application {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    Application.launch(JfxMvpExample.class, args);
}

@Override
public void start(Stage primaryStage) {

    primaryStage.setTitle("Java Fx 2.0 Mvp Example / Steffen Kämpke");

    final Injector injector = Guice.createInjector(new MvpModule());
    final UserContainerPresenter userContainerPresenter = injector.getInstance(UserContainerPresenter.class);

    Scene scene = new Scene(userContainerPresenter.getDisplay().asParent(), 500, 500);

    primaryStage.setScene(scene);
    primaryStage.setVisible(true);               
}

} ```

Download this example

You can check out the source directly as a Netbeans project svn src

or download the application. download