java MVC application - java

i'm creating an application at the moment that i want to reuse the GUI so to make it easy to reuse and change the elements I've been using the MVC design pattern but im having a few issues with it the first issue is how to implement the actual design pattern as different examples implement it in different ways. this is the code i have in my main, does this look ok.
mainView theView = new mainView();
mainModel theModel = new mainModel();
mainController theController = new mainController(theView,theModel);
theView.setVisible(true);
The second problem i have was the example set up was the controller implemented a view in the by using the following code:
controller:
this.theView.addCalculateListener(new CalculateListener());
view:
public void addCalculateListener(ActionListener listenForCalcButton){
calculateButton.addActionListener(listenForCalcButton);
}
this seems to work fine but i have problems implementing listeners in the JMenu as there added within the constructor of the view so my plan was to create the JMenu in an external class where i can put all the menu items as global variables (to clear up code) which will allow me to add the listeners in this manner, is this an OK solution or am i way off.

Related

What is good coding practice when it comes to structuring a JavaFX controller?

I am a student learning how to use JavaFX and I've got my first GUI working by using SceneBuilder and a Controller class. However, from my point of view the structure of the code in the controller looks incredibly messy and ugly because I put every event handler in the initialize() method of Controller. This makes it look like this:
#FXML
private void initialize() {
dealtHandLabel.setText("Your cards will be shown here.");
TextInputDialog userInput = new TextInputDialog();
userInput.setTitle("How many cards?");
userInput.setHeaderText("Enter how many cards you want to get.");
userInput.setContentText("No. of cards:");
//This makes it so that the button displays a hand of cards (of specified amount) when clicked
dealHand.setOnAction(event -> {
Optional<String> result = userInput.showAndWait();
if(result.isPresent()) {
int requestedAmount = Integer.parseInt(result.get());
StringBuilder sb = new StringBuilder();
cardHand = deck.dealHand(requestedAmount);
cardHand.forEach((card) -> sb.append(card.getAsString()).append(" "));
dealtHandLabel.setText(sb.toString());
}
});
//This button uses lambdas and streams to display requested information (sum, heart cards, etc.)
checkHand.setOnAction(event -> {
int cardSum = cardHand.stream().mapToInt(card -> card.getFace()).sum();
List<PlayingCard> spadeCards = cardHand.stream().filter((card) -> card.getSuit() == 'S').toList();
List<PlayingCard> heartCards = cardHand.stream().filter((card) -> card.getSuit() == 'H').toList();
List<PlayingCard> diamondCards = cardHand.stream().filter((card) -> card.getSuit() == 'D').toList();
List<PlayingCard> clubCards = cardHand.stream().filter((card) -> card.getSuit() == 'C').toList();
StringBuilder sb = new StringBuilder();
heartCards.forEach((card) -> sb.append(card.getAsString()).append(" "));
sumOfFacesField.setText(String.valueOf(cardSum));
heartCardsField.setText(sb.toString());
if(heartCards.size() >= 5 || diamondCards.size() >= 5 || spadeCards.size() >= 5 || clubCards.size() >= 5) {
flushField.setText("Yes");
}
else {
flushField.setText("No");
}
if(cardHand.stream().anyMatch((card) -> card.getAsString().equals("S12"))) {
spadesQueenField.setText("Yes");
}
else {
spadesQueenField.setText("No");
}
});
}
My lecturer does the exact same thing where he straight up puts every node handler into the initialize method, but I am not sure if this is good coding practice because it makes code harder to read from my point of view. Would it be better to put the different handlers into separate methods and connect them to the correct nodes using SceneBuilder, or is putting everything into initialize considered common coding practice among JavaFX developers?
This is an opinionated, perhaps even arbitrary decision, both approaches are OK.
There is nothing wrong with coding the event handlers in the initialize function versus referencing an event method handler from FXML.
These kinds of things are out of usually out of scope for StackOverflow, but I'll add some pointers and opinions anyway as it may help you or others regardless of StackOverflow policy.
Reference the actions in Scene Builder
Personally, I'd reference the action in Scene Builder:
Fill in a value for onAction or other events in the code panel section of Scene Builder UI for the highlighted node.
This will also add the reference in FXML, so you will have something like this, with the hashtag value for the onAction attribute:
<Button fx:id="saveButton" mnemonicParsing="false" onAction="#save" text="Save" />
Have Scene Builder generate a skeleton (View | Show Sample Skeleton). This will create a method signature to fill in, like this:
#FXML
void save(ActionEvent event) {
}
Then place the event handling code in there.
For that setup, IDEs such as Idea will do additional intelligent checks for consistency and allow element navigation between FXML and Java code, which can be nice, though that isn't really critical.
What follows is optional additional information on some important design decisions regarding JavaFX controllers.
Ignore this if it confuses you or is not relevant for your application (which is likely for a small study application).
Consider using MVC and a shared model
The more important design decision with regards to controllers is, usually, whether or not to use a shared model and MVC, MVP, or MVVM.
I'd encourage you to study that, research the acronyms, and look at the Eden coding MVC guide.
Consider using dependency injection
Also consider whether or not to use a dependency injection framework with the controllers, e.g. Spring integration (for a more complex app) or the clever eden injection pattern. You don't need to use these patterns, but they can help. Spring in particular is complex, and the integration with JavaFX is currently a bit tricky. I know both, so I would use them if the app called for it, but for others, it may not be a good combination.
Consider a business services layer
For medium to larger sized apps, in addition to having a separate model layer, try to separate the business logic out of the controller so the controller is just dealing with invoking functions on business services that manipulate the shared model and binding that model to the UI, rather than directly implementing the business logic in the controller.
This makes reusing, reasoning about, and testing the business logic easier. For smaller apps, the additional abstraction is not necessary and you can do the work in the controller.
Often such a handler will call an injected service that interacts with the shared model. If the updated data also needs to be persisted, then the injected service can also invoke a database access object or rest API client to persist the data.
Putting it all together
So to go back to the prior example, you might implement your save function in the controller like this:
public class UserController {
#FXML
TextField userName;
private UserService userService;
#Autowired
public void setUserService(UserService userService) {
userService = userService;
}
#FXML
void save(ActionEvent event) {
userService.saveUser(new User(userName.getText()));
}
}
Where the userService might reference a Spring WebFlux REST Client to persist the new user to a cloud-deployed REST service or maybe a Spring Data DAO to store the new user in a shared RDBMS database.
As noted, not all apps need this level of abstraction. Especially, the injection frameworks that are not required for small apps. And you can mix architectural styles within a given app, using shared models and services as appropriate and writing some smaller functions directly in the controller if you prefer to code that way. Just be careful if you do mix design patterns that it doesn't end up a jumbled mess :-)

MVP, JavaFx and components references

I've studied all popular GUI patterns - MVP,MVC,MVVM and finally I decided to implement MVP (Supervising Controller). So I have the following OBJECTS(!). Stage<-View<->Model. It's important Stage!=View, it is another object. Between view and model data binding. Besides I have a presenter(controller) which handles all events and works with view and model, so View<-ViewInterface<-Controller->Model.
The problem is now how to get references to labels, textAreas etc in view. Javafx allows to use #FXML annotation to inject these components to controller. However, using MVP I need these components in View, as all logic for view is in View and I don't need them in controller. The only solution I know is:
public class MyView{
private Button button;
public MyView(){
...
button=(Button) root.lookup("#myButton");
}
}
That is to get references by their ID. However I don't like it. Or I do something wrong or I understand something wrong but I think a better solution exist. Please, help me to find it.
JavaFX has been designed to work with the MVC pattern. Hence it is much easier to use MVC than MVP. In MVP Presenter is responsible for formatting the data to be displayed. In JavaFX, it is done automatically by View. Here's a quick overview of JavaFX MVC:
Model - the domain data / data structure that you work with in your application (e.g. Person, Employer, Coursework, etc)
View - the UI definition of the application and its Model. The preferred way of creating a view is via an FXML file, which is essentially the View in JavaFX MVC.
Controller - the bridge between Model and View. The code is typically isolated in XController class (where X is the name of the FXML View). The instance of Controller is automatically injected by FXMLLoader or can be done manually in case you require a custom Controller. The Controller class will have access to UI (View) elements in order to be able to manipulate different properties and also the Model, so that it can perform operations based on the UI (View) input.
To sum up, in JavaFX you don't need to have class View, the View definition should be entirely in the FXML file. All UI elements should be injected with #FXML into your Controller class. If you absolutely have to use MVP, then AWT/Swing or MVP4j - http://www.findbestopensource.com/product/mvp4j might be a better option.
For more detailed explanation please have a look at the official Oracle tutorial for JavaFX: http://docs.oracle.com/javase/8/javafx/get-started-tutorial/jfx-overview.htm
If you require help building UI using FXML: http://docs.oracle.com/javase/8/javafx/api/javafx/fxml/doc-files/introduction_to_fxml.html
This tutorial covers basics of MVC in JavaFX and how each component communicates with others: http://code.makery.ch/library/javafx-8-tutorial/part1/
As an Android developer, I always use MVP pattern in my applications. MVC compared to MVP seems so old to me, so when I started working on a new Java app, I felt a little bit lost.
Here there is my solution:
Initial steps
In fxml files create the UI, without specifying a controller, because you don't need one.
Create the Java interfaces (IView, IPresenter and so on..)
Implement the IPresenter interface in the Presenter class, as you would do normally (do http requests, query a DB..)
Now the interesting part:
Adapting your view to MVP pattern
Let's see some code:
Create your GUI (for example a Main GUI) and implement your View interface
public class MainGUI extends Application implements MainContract.View {
public static void main(String... args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
//here we will load fxml or create the ui programmatically
}
//method from view interface
#Override
public void onServerResponse(String message) throws IOException {
//update the view
}
Now the last step:
Communicating with the presenter
To do this, we first create an istance of our presenter:
private MainContract.Presenter presenter;
public MainGUI() {
presenter = new MainPresenter(this);
}
this is, of course, the MainContract.View implemented in the MainGUI class
Now we have to get a reference to the view components
private ComboBox<Double> mySimpleList;
#Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("layout_main.fxml"));
Parent root = loader.load();
mySimpleList= (ComboBox<Double>) loader.getNamespace().get("mysimplelist_id");
...
primaryStage.setScene(new Scene(root, -1, -1));
primaryStage.show();
I prefer using fxml files instead of creating the ui by code, but the logic behind is identical.
Set the items
...
mySimpleList.setItems(ValuesFactory.getMyValues());
And the listener
...
mySimpleList.valueProperty().addListener(simpleListListener);
What is simpleListListener?
A simple ChangeListener, where we finally call a presenter method
simpleListListener = (ChangeListener<Double>)
(observable, oldValue, newValue) -> presenter.doTheLogic(newValue);
This is an easy scenario, but in principle this is how we can use MVP Pattern with JavaFX. I also understand that it isn't the definitive solution, so I hope that one day there will be more docs where I can learn more about this argument!
Let me know if I wasn't clear in some part of the code

How to put DAO and GUI together with MVC

I'm creating a Java Application that represents a school. My aim is to keep the application open for new features, so I'm trying to apply some Design Patterns to it.
What I have so far is a HSQLDB connected to my program.
In the database one can store
pupils
courses
years
exams
grades
The current structure is as follows:
there are classes for each of the objects that contain the attributes + setters and getters
for each object there is a DAO that manages the CRUD operations on the DB
each DAO implements a GenericDAO interface
If i want to create a new pupil i can call:
PupilDao pupil = new PupilDao();
pupil.connectToDB();
pupil.add(new Pupil(name, age,...));
pupil.disconnectDB();
Every DAOs connectToDB() and disconnectDB() methods point to a DBuser-Classes connect() and disconnect() methods. So if I want to change the connection, there's only one place to do so.
So far, those operations work.
My questions are the:
1.) Is the current design a proper use of DAOs? I'm asking because i would rather have one
Dao for all objects because right now there's a lot of repetitive code in the DAOs. (e.g. get, update, delete...)
Now that the DB-Access works, I want to create a GUI using Swing. I have some experience doing this although not with the MVC-Pattern.
2.) As far as I understand, the DAOs + my object classes would be the Model here. Is that correct?
3.) My understanding of MVC is that in my View-Class (i.e. the GUI) I set listeners for my actions which point to different Controller-Classes implementing the ActionListener interface and in my Controller-Classes I would for example have a actionPerformed() that creates a new Pupil (using the DAO / Model - Classes). Am I on the right track here?
4.) Is it favourable to have one big Controller managing all actions over having different Controllers?
I'm asking those questions because I read/watched a lot about patterns/OO-Design and want to make sure my understanding is correct.
Furthermore I highly appreciate your thoughts on my design! What could be done more flexible or better to maintain later?
Thanks in advance for every suggestion and sorry for the somewhat long explanation!
Felix
While I still can't answer my questions for sure, I think I found a suitable way
for me and want to share the design (suggestions/answers are still appreciated!).
1) The applications entry-point is the main-application class (MVC.class). This class creates the
view using a main-controller. Here's the code:
public static void main(String[] args) {
// view is declared as class-variable
view = new View();
MainController mcontroll = new MainController(view);
view.getFrame().setVisible(true);
}
The main-controller only takes the view as parameter as its only purpose is to display the view.
As stated in my post above my aim was to display different database tables from a HSQLDB and modify them.
2) In the menubar there are entries for managing years, courses, etc. If one entry is clicked, the controller for the clicked category (e.g. years) takes control. Here is, how the controller is changed:
public void addManageYearsListener(ActionListener listener) {
mntmYears.addActionListener(listener);
}
The above method is located in the view class (i.e. the GUI class) but the main-controller implements the actionPerformed()-method. To do that, the main-controller calls the method defined in the view in his constructor like that:
public MainController(View view) {
this.view = view;
this.view.addManageCoursesListener(new ManageCourses());
this.view.addManageYearsListener(new ManageYears());
}
The corresponding class "ManageYears" is then defined as inner class:
class ManageYears implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
MVC mvc = new MVC("years");
}
}
What happens here is that when the menuitem is clicked, the main-controller "hears" the click (cause he is listening to it) and calls the main class again, although this time with a string as parameter. The constructor of the main class checks the string and sets the model and the controller that is needed. See here:
if (controller.equals("year")) {
YearDaoImpl yearDao = new YearDaoImpl();
YearController ycontroller = new YearController(view, yearDao);
}
"controller" is the string that is passed with the constructor and "yearDao" is the Data Access Object that handles the CRUD-operations which have to do with the object "year" (which is a class itself).
So now it's possible to switch controllers at runtime.
3) The year controller sets the ActionListeners for a add and remove button in his constructor (just like the main controller did for the menu item), get's the data from the database (via the yearDao) and sets the table model in the view (view has a setTableModel()-method for that) passing the returned ResultSet as parameter of the table Model class:
public void showYears() {
try {
con = yearDao.connectToDB();
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT * FROM YEARS;");
view.setTableModel(new YearTableModel(rs));
con.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
As you can see, the yearDao has a connectToDB()-method that returns a connection (the connection is actually gotten from a c3p0 connection pool) which is then used to get a ResulSet of years from the database. The setTableModel()-method is then called setting the YearTableModel - a custom class extending AbstractTableModel and passing the ResulSet as parameter.
With the explained design it is now possible to:
1.) only have one table in the GUI that is populated with different database outputs.
2.) seperate the view from the data (which is what this whole fuss is about ;-)).
3.) add new controllers or models when needed without changing a lot of code.
As mentioned at the beginning I still appreciate every suggestion or improvement!
If you made it till the end of this post, I hope you found something to use in your own program!
regards,
Felix

Thin controllers

I am getting my feet wet with javafx. This is what I am doing.
FXML Views
DI Controllers
Weld-SE Managed Services and Models
Trying to confine UI to FXML
Trying keep the Controllers thin
Problem:
While trying to code the UI, most static UI is confined inside the fxml. But there are scenarios where I find my self adding, removing, showing, hiding elements etc.
I find myself doing this inside the controller as fx lets me configure controller method in the view which it will call on a particular action / event. All this code deals with Dynamic UI building / manipulating and belongs inside the view layer. But, it ends up in controller making the controllers fat.
javafx provides javascript integration. This is one possible way to abstract that view manupulation code away. But this would add not so perfect javascript into the mix.
How would I abstract the code away in java or fxml so that I don't break the Thin Controller Paradigm ?
EDIT
#assylias
Agreed, I have thought about this and this way that java class and fxml together become a reusable widget. But then, how do I wire this into FXML. FXML doesn't understand anything but a controller. Let say I wire this view class into fxml using fx:controller and not name it controller. So I have something like this.
This view class has nothing but view manipulation code. Then I would create another controller class. But then I would expect to somehow fill the form data into this controller. This should only happen when the user has submitted the form. So in a way, I need to tell javafx somehow that UI manipulation request / event is different from actual data manipulation request / event.
Your thoughts, sorry if it was verbose. Tried to articulate it in as few words as I could.
I think the easiest solution to this is to remember that the controller specified in FXML is a view controller. It's purpose is to contain code to modify and update the view, not to contain traditional MVC controller code or business logic.
For example, in a project I'm currently working on, I'm using JavaFX with Akka Actors. The application is written in scala. The JavaFX view controllers contain any code necessary to modify the view. One screen contains a login form. When the user clicks the login button, the view controller simply creates a message containing the username and password, and sends that message to the actor responsible for doing business logic. If that actor determines there is an error then it will send a message back to the view controller, and the view controller can decide what sort of updates need to be made on the screen.
I've found that using akka actors with JavaFX greatly simplifies coding the application for at least two reasons.
Because using an actor system mandates sending messages between actors, there is a natural boundary between presentation code and business code. The messages that are passed back and forth form this natural boundary.
Using actors completely replaces the complexity of working with threads/tasks. It completely eliminates the need to code javafx.concurrent.Task's for long running processes.
How about putting your view manipulation code in Main Class ?
Main Class :
public class SampleJavaFXApp extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"SampleUI.fxml"));
Parent root = (Parent) loader.load();
Controller controller = loader.getController();
viewManipulationLogic(controller);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
// view manipulation logic
private void viewManipulationLogic(Controller controller) {
controller.getBlueButton().setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
System.out.println(" I am just about button!");
}
});
}
Controller :
public class Controller implements Initializable {
#FXML
private Button blueButton;
public Button getBlueButton() {
return blueButton;
}
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
//real data manipulation
}
}
cons : You need getters for all Nodes u want to manipulate , in controller class.

Render Play 2.0 view programmatically

Using Play 2.1.0, I have a Java controller with an action responsible to render arbitrary html views.
For example:
class HtmlClientViews extends Controller {
public static void getView(String viewName) {
return ok(/*How to render the view programmatically?*/)
}
}
And in my views I have a view named account.html.scala.
I have a route like:
GET /htmlclient/*viewName controllers.HtmlClientViews.getView(viewName)
If I make a request like /htmlclient/account.html I want to render the view named account.html.scala
I haven't tried yet to use Java reflection mechanisms for this, but would like to know what is the most effective way to achieve this.
You can do it with:
reflections, like in Play Authenticate usage sample, there it's used for selecting different view depending on detected language
If you have known number of views you can use simple switch statement in controller to return view a,b,c or d.
Also as in case no. 2 - you can use matching statement in the view to include sub-view depending on some variable.

Categories

Resources