Reputation:
I guess i have misunderstood a bit about the mcv pattern and fxml in javafx. I belive im on the right way now. Im still a bit confused but im used the example from @GJCode and worked a bit on it.
First at all thanks you, for you answers. It already helped me!
Theres still something i dont understand.
So the MCV pattern is basically diveded in 3 Components, right?
M : Model - Basically the logic of the code. Like a function to do a simple math addition or return a simple text.
C : Controller - Basically the core of the project. Creates a connection between the View and the Model? Basically i would manipulate view components here like setting the Text of a textfield?
V : View - Just the raw Gui, no logic. In this case the fxml?
My Project setup atm looks like this :
(Ignore the Week.java, its unnecessary atm)
My current goal is to create a JavaFX Application thats works via mcv Pattern and it should just print a text in a existing TextField(for now). The text to print will received via the Modelclass.
Main Class :
package main;
import controller.ControllerClass;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import model.InitGui;
import view.*;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/Design.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
// optionally add a stylesheet
primaryStage.setScene(scene);
// obtain controller
ControllerClass controller = loader.getController();
// set model
controller.setModel(new InitGui());
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
}
ControllerClass :
package controller;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import model.InitGui;
public class ControllerClass {
@FXML
public TextField fxWeeks;
public InitGui initGui;
public void setModel(InitGui initGui) {
this.initGui = initGui;
}
public ControllerClass () {
fxWeeks.setText(initGui.getExample());
}
}
ModelClass :
package model;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class InitGui {
public String getExample () {
return "Hello";
}
}
My ViewClass (fxml)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="450" prefWidth="450" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.controller.ControllerClass">
<MenuBar fx:id="menuBar">
<menus>
<Menu text="Datei">
<MenuItem text="Öffnen"/>
<MenuItem text="Speichern"/>
<MenuItem text="Speichern unter"/>
<SeparatorMenuItem />
<MenuItem text="Schließen"/>
</Menu>
</menus>
</MenuBar>
<children>
<TableView fx:id="fxTable" layoutX="10.0" layoutY="75.0" prefHeight="410.0" prefWidth="600.0"/>
<Label fx:id="fxLabel" layoutX="630.0" layoutY="60.0" Text="Kalenderwoche"/>
<TextField fx:id="fxWeek" layoutX="630.0" layoutY="75.0" prefWidth="95.0"/>
<Button fx:id="fxButton" layoutX="630.0" layoutY="125.0" Text="Arbeitszeit berechnen"/>
<Label fx:id="fxAlllbl" layoutX="10.0" layoutY="500.0" Text="Gesamt :"/>
<TextField fx:id="fxAllContent" layoutX="80.0" layoutY="497.0"/>
</children>
</Pane>
So as far i have understand the Main class will launch the start Methode with launch(args)
it will create the gui with the FXMLLoader,scene and setScene.
Those parts i dont really understand : ControllerClass controller = loader.getController();controller.setModel(new InitGui());
Im creating a controller object, but what is loader.getController
and what exactly would the "modelsetter" do?
I want to receive datas with the model-component and edit the view with the controller element(add a string received from model to the fxTextField via the controller).
Is my approach even right? Or do i miss something complety? Could you help me with the example im trying to achieve.
Upvotes: 2
Views: 2360
Reputation: 2109
usually Main class launch the application so try something like this:
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("fxmlFileName.fxml"));
BorderPane root = loader.load();
Scene scene = new Scene(root);
// optionally add a stylesheet
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
// obtain controller
ControllerClass controller = loader.getController();
// set model
controller.setModel(new Model());
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
this is how you can implement MCV pattern. Main class start the application, a view represented by an fxml file is connected to the controller and the class Model represent the logic of your application, so doing setModel() the controller is now linked to the logic. setModel() is just a setter method.
Controller class:
public class ControllerClass {
@FXML
private ResourceBundle resources;
@FXML
private URL location;
@FXML
private TextField textField;
@FXML
private Button button;
private Model model;
public void setModel(Model model) {
this.model = model;
}
@FXML
public void changeTextOnClick(ActionEvent event) {
String text = model.getExample();
textField.setText(text);
}
@FXML
void initialize() {
assert button != null : "fx:id=\"button\" was not injected: check
your FXML file 'fxmlFileName.fxml'.";
assert textField != null : "fx:id=\"textField\" was not injected: check
your FXML file 'fxmlFileName.fxml'.";
}
}
And your fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/9" fx:controller="it.gjcode.plusFX.TestController">
<center>
<VBox prefHeight="200.0" prefWidth="490.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="button" mnemonicParsing="false" onAction="#changeTextOnClick" text="Change Text" />
</children>
<children>
<TextField fx:id="textField" prefHeight="163.0" prefWidth="161.0" ">
<font>
<Font size="40.0" />
</font>
</TextField>
</children>
</VBox>
</center>
</BorderPane>
loader.getController simply get a controller object, in this case ControllerClass object, with the model setter your controller can access to the logic of your application, in this case doing model.getExample(). Remember that in MVC pattern logic must be as separate as possible from the controller and the view, so in this way changes on the logic will not affect the other components of your application.
Upvotes: 0