JavaFX: How to populate data to TableView from different Thread(Netty) - java

I have below code. the tableview does not display record on GUI,is empty.
How I can Pass value from the ServerHandler thread to JAVAFX UI thread.
Can you please suggest?
Thanks
UPDATE
The Main class
public class Main extends Application {
private static Stage stage;
#Override
public void start(Stage primaryStage){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("mainpane.fxml"));
fxmlLoader.load();
setStage(primaryStage);
Parent root = fxmlLoader.getRoot();
Scene scene = new Scene(root,800,800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
new Thread(() -> launch(Main.class, args)).start();
new MyServer().startDownload();
}
The Controller
public class SampleController {
private ObservableList<Model> tableData = FXCollections.observableArrayList();
#FXML
private TableView<Model> table;
#FXML
private TableColumn<Model, String> firstCol;
#FXML
private TableColumn<Model, String> secondCol;
#FXML
public void initialize() {
table.setEditable(false);
firstCol.setCellValueFactory(cellData -> cellData.getValue().getName());
secondCol.setCellValueFactory(cellData -> cellData.getValue().getCurrent());
table.setItems(tableData);
}
public void addModel(ChannelFuture sendFileFeture,Model model){
table.getItems().add(Model);
System.out.println("row model= "+model.getName().get());// it works fine;
sendFileFeture.addListener(model);
}
The Server class with Netty 4
public class ServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
#Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
//some codes
Model model=new Model(file.getName(),fileLength+"");
SampleController sc=new SampleController();
sc.addModel(sendFileFeture, model);
}
The Model class with ChannelProgressiveFutureListener of Netty
public class Model implements ChannelProgressiveFutureListener{
private SimpleStringProperty name=null;
private SimpleStringProperty current=null;
public Model(String name,String current){
this.name=new SimpleStringProperty(name);
this.current=new SimpleStringProperty(current);
}
#Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) throws Exception {
System.out.println("current: "+current+",progress: "+progress); //it works fine
current.set(progress+""); // can not update the TableView
}
#Override
public void operationComplete(ChannelProgressiveFuture future) throws Exception {
}
public void setName(String name) {
this.name.set(name);
}
public SimpleStringProperty getName() {
return name;
}
public void setCurrent(String current) {
this.current.set(current);
}
public SimpleStringProperty getCurrent() {
return current;
}
UPDATE
the tableview not updating with right size,the image i loaded is 2,407,257 bytes.you can find the errors in the images below.
image1
image2
secondCol.setCellValueFactory(cellData -> cellData.getValue().getCurrent());
secondCol.setCellFactory(column -> {return new TableCell<Model, String>() {
#Override
protected void updateItem(String item, boolean empty) {
System.out.println(item); //UPDATING NOT CURRECT
super.updateItem(item, empty);
setText(empty ? "" : getItem().toString());
}
};

The UI is not displaying anything because you are populating a different table to the one you are displaying, not because of threading (though you have threading issues too, or will do once you fix the initial problem).
In your start() method, you load the FXML, which creates a TableView and its columns, and creates a controller instance. Your ServerHandler class creates a new instance of the controller, which in turn creates a new instance of TableView (it is always a mistake to initialize variables that are annotated #FXML). That TableView instance is never displayed. So when your ServerHandler populates the table, it is populating a table that is not actually part of the UI, and you don't see anything.
Move the creation of the MyServer to the start() method, and pass it the existing controller instance:
public class Main extends Application {
private Stage stage;
#Override
public void start(Stage primaryStage){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("mainpane.fxml"));
fxmlLoader.load();
setStage(primaryStage);
Parent root = fxmlLoader.getRoot();
Scene scene = new Scene(root,800,800);
primaryStage.setScene(scene);
primaryStage.show();
SampleController controller = loader.getController();
new Thread(() -> new MyServer(controller).startDownload()).start();
}
public static void main(String[] args) {
launch(args);
}
}
Your MyServer class should in turn pass the controller to the ServerHandler instance(s). Since the ServerHandler methods are being invoked on a background thread, they need to use Platform.runLater(...) to update the UI:
public class ServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
private final SampleController sc ;
public ServerHandler(SampleController sc) {
this.sc = sc ;
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
//some codes
Model model=new Model(file.getName(),fileLength+"");
Platform.runLater(() -> {
sc.addModel(sendFileFeture, model);
sc.addRowModel(sendFileFeture, rowModel);
});
}
}
Finally, don't initialize fields that are supposed to be initialized by the FXMLLoader. This will only have the effect of suppressing any NullPointerExceptions that indicate your controller-FXML bindings are not properly set up:
public class SampleController {
private ObservableList<Model> tableData = FXCollections.observableArrayList();
#FXML
private TableView<RowModel> table ;
#FXML
private TableColumn<Model, String> firstCol ;
#FXML
private TableColumn<Model, String> secondCol ;
#FXML
public void initialize() {
table.setEditable(false);
firstCol.setCellValueFactory(cellData -> cellData.getValue().getName());
secondCol.setCellValueFactory(cellData -> cellData.getValue().getProgress());
table.setItems(tableData);
}
public void addModel(ChannelFuture sendFileFeture,Model model){
table.getItems().add(model);
System.out.println("row model= "+model.getName().get());// it works fine;
sendFileFeture.addListener(rowModel);
}
}

Related

JavaFX How to put FXML Controller Instance to HashMap?

I have many FXML with different Controller and I want to access all Controller Instance in one class using static methods. The reason I am doing this because I want to change the UI of different FXML from different controller. I'm not sure if there is any better way to do it. My problem is in my SceenViews class because I don't know what datatype to use to hold FXML Controller Instance in my controllerMap variable.
Inside my Package: Main.java, ScreenViews.java, Frame.FXML, FrameController.java, Login.FXML, LoginController.java, Dashboard.FXML, DashboardController.java, Journal.FXML, and JournalController.java
Main.java
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
ScreenViews.loadFXML("Frame", "Frame.fxml");
ScreenViews.loadFXML("Login", "Login.fxml");
ScreenViews.loadFXML("Dashboard", "Dashboard.fxml");
ScreenViews.loadFXML("Journal", "Journal.fxml");
Scene scene = new Scene((Parent) ScreenViews.getView("Frame"));
scene.setFill(Color.TRANSPARENT);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
In my ScreenViews.java what datatype can I use to hold different controller instance in my controllerMap variable?
public class ScreenViews {
private static HashMap<String, Node> viewMap = new HashMap<>();
//HASHMAP FOR CONTROLLER INSTANCE
private static HashMap<String, datatype? > controllerMap = new HashMap<>();
public static void addView(String name, Node screen) {
viewMap.put(name, screen);
}
public static Node getView(String name) {
return viewMap.get(name);
}
public static void addController(String name, datatype? controller) {
controllerMap.put(name, controller);
}
public static datatype? getController(String name) {
return controllerMap.get(name);
}
public static boolean loadFXML(String name, String resource) {
try {
FXMLLoader fxLoader = new
FXMLLoader(ScreenViews.class.getResource(resource));
Parent loadedFXML = (Parent) fxLoader.load();
addView(name, loadedFXML);
addController(name, fxLoader.getController());
return true;
} catch (IOException e) {
System.out.println(e.getMessage());
return false;
}
}
}
Sample LoginController.java code
public class LoginController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
public void frameSetUI(ActionEvent event) {
ScreenViews.getController("Frame").getFramePane().getChildren().add(ScreenViews.get("Dashboard"));
}
}
Sample FrameController.java code
public class FrameController implements Initializable {
#FXML private StackPane rootPane;
#FXML private AnchorPane titleBar;
#FXML private AnchorPane framePane;
#FXML private Button toDashboard;
#FXML private AnchorPane mainPane;
public void initialize(URL url, ResourceBundle rb) {
}
public AnchorPane getFramePane(){
return framePane;
}
}

adding data into JavaFX tableview

I'm trying to push my data that I'm getting from a RethinkDB into a JavaFx TableView, however, the changes do not appear in the tableview and I can't figure out why.
I'm pretty new to JavaFx so I hope you can help me.
Here are my classes : (I didn't include my memory classes where I save the data from the DB)
RethinkDBConnect class
public class RethinkDBConnect {
public static final RethinkDB r = RethinkDB.r;
GsonConverter con = new GsonConverter();
JiraTicketBody body = new JiraTicketBody();
ViewController viewcon = new ViewController();
TicketDataProperty tickprop = new TicketDataProperty(null, null, null, null, null, null);
public void Connection(){
viewcon.list.add(newTicketDataProperty
("test","test","test","test","test","test"));
}
}
TicketDataProperty class
public class TicketDataProperty {
private final SimpleStringProperty key;
private final SimpleStringProperty prioritaet;
private final SimpleStringProperty erstellt;
private final SimpleStringProperty status;
private final SimpleStringProperty zustand;
private final SimpleStringProperty beschreibung;
public TicketDataProperty(String key, String prioritaet, String erstellt,
String status, String zustand, String beschreibung)
{
this.key = new SimpleStringProperty(key);
this.prioritaet = new SimpleStringProperty(prioritaet);
this.erstellt = new SimpleStringProperty(erstellt);
this.status = new SimpleStringProperty(status);
this.zustand = new SimpleStringProperty(zustand);
this.beschreibung = new SimpleStringProperty(beschreibung);
}
public String getKey() {
return key.get();
}
public void setKey(String value) {
key.set(value);
}
public String getPrioritaet() {
return prioritaet.get();
}
public void setPrioritaet(String value) {
prioritaet.set(value);
}
public String getErstellt() {
return erstellt.get();
}
public void setErstellt(String value) {
erstellt.set(value);
}
public String getStatus() {
return status.get();
}
public void setStatus(String value) {
status.set(value);
}
public String getZustand() {
return zustand.get();
}
public void setZustand(String value) {
zustand.set(value);
}
public String getBeschreibung() {
return beschreibung.get();
}
public void setBeschreibung(String value) {
beschreibung.set(value);
}
}
ViewController class
public class ViewController implements Initializable {
TicketDataProperty tickdat = new TicketDataProperty(null, null, null, null, null, null);
#FXML private TableView <TicketDataProperty> table;
#FXML private TableColumn <TicketDataProperty,String> key;
#FXML private TableColumn <TicketDataProperty,String> prioritaet;
#FXML private TableColumn <TicketDataProperty,String> erstellt;
#FXML private TableColumn <TicketDataProperty,String> status;
#FXML private TableColumn <TicketDataProperty,String> zustand;
#FXML private TableColumn <TicketDataProperty,String> beschreibung;
public ObservableList<TicketDataProperty> list = FXCollections.observableArrayList(
new TicketDataProperty("example","example","example","example","example","example")
);
#Override
public void initialize(URL location, ResourceBundle resources) {
key.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("key"));
prioritaet.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("prioritaet"));
erstellt.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("erstellt"));
status.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("status"));
zustand.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("zustand"));
beschreibung.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("beschreibung"));
table.setItems(list);
}
}
GsonConverter class
public class GsonConverter {
public JiraTicketBody gson(String json)
{
Gson gson = new Gson();
JiraTicketBody BodyObj = gson.fromJson(json,JiraTicketBody.class);
return BodyObj;
}
}
Main class
public class Main extends Application
{
//ViewXML
#Override
public void start(Stage primaryStage) throws IOException
{
Parent root = FXMLLoader.load(getClass().getResource("/view/ViewXML.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("Ticket System Application");
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public static void main(String[] args)
{
try {
//ViewXML
launch(args);
RethinkDBConnect obj = new RethinkDBConnect();
obj.Connection();
} catch(Exception e) {
}
}
}
There are two issues with the code you have posted.
As stated in the documentation, Application.launch() blocks until the application exits. So you don't even create the RethinkDBConnection class until the application is in the process of closing. You should consider the start() method to be the entry point to the application, and should have no code other than launch() in the main(...) method. Anything you do in a JavaFX application should be done in the start(...) or init(...) methods, or in methods invoked from there, etc.
In this case, since you don't seem to need RethinkDBConnection from outside the controller, I see no reason not to create RethinkDBConnect from the controller itself.
You need to update the list that belongs to the controller. Instead, you are creating a new object that happens to be the same class as the controller, and updating the list that belongs to that object. Obviously, that list has nothing at all to do with the table. You need to pass a reference to the actual list that is used as the backing list for the table to the RethinkDBController instance.
So your code should look like:
public class RethinkDBConnection {
// public static final RethinkDB r = RethinkDB.r;
// GsonConverter con = new GsonConverter();
// JiraTicketBody body = new JiraTicketBody();
private final ObservableList<TicketDataProperty> dataList ;
public RethinkDBConnection(ObservableList<TicketDataProperty> dataList) {
this.dataList = dataList ;
}
public void connect(){
dataList.add(new TicketDataProperty
("test","test","test","test","test","test"));
}
}
Then in the controller you can do:
public class ViewController implements Initializable {
#FXML private TableView <TicketDataProperty> table;
#FXML private TableColumn <TicketDataProperty,String> key;
#FXML private TableColumn <TicketDataProperty,String> prioritaet;
#FXML private TableColumn <TicketDataProperty,String> erstellt;
#FXML private TableColumn <TicketDataProperty,String> status;
#FXML private TableColumn <TicketDataProperty,String> zustand;
#FXML private TableColumn <TicketDataProperty,String> beschreibung;
private ObservableList<TicketDataProperty> list = FXCollections.observableArrayList(
new TicketDataProperty("example","example","example","example","example","example")
);
#Override
public void initialize(URL location, ResourceBundle resources) {
key.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("key"));
prioritaet.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("prioritaet"));
erstellt.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("erstellt"));
status.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("status"));
zustand.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("zustand"));
beschreibung.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("beschreibung"));
table.setItems(list);
RethinkDBConnection connection = new RethinkDBConnection(list);
connection.connect();
}
}
And your Main class should just be:
public class Main extends Application
{
//ViewXML
#Override
public void start(Stage primaryStage) throws IOException
{
Parent root = FXMLLoader.load(getClass().getResource("/view/ViewXML.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("Ticket System Application");
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you really do need access to your RethinkDBConnection instance outside the controller, then modify the controller as follows:
public class ViewController implements Initializable {
#FXML private TableView <TicketDataProperty> table;
#FXML private TableColumn <TicketDataProperty,String> key;
#FXML private TableColumn <TicketDataProperty,String> prioritaet;
#FXML private TableColumn <TicketDataProperty,String> erstellt;
#FXML private TableColumn <TicketDataProperty,String> status;
#FXML private TableColumn <TicketDataProperty,String> zustand;
#FXML private TableColumn <TicketDataProperty,String> beschreibung;
private ObservableList<TicketDataProperty> list = FXCollections.observableArrayList(
new TicketDataProperty("example","example","example","example","example","example")
);
#Override
public void initialize(URL location, ResourceBundle resources) {
key.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("key"));
prioritaet.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("prioritaet"));
erstellt.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("erstellt"));
status.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("status"));
zustand.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("zustand"));
beschreibung.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("beschreibung"));
table.setItems(list);
}
public ObservableList<TicketDataProperty> getDataList() {
return list ;
}
}
and use this version of Main:
public class Main extends Application
{
//ViewXML
#Override
public void start(Stage primaryStage) throws IOException
{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/ViewXML.fxml"));
Parent root = loader.load();
ViewController controller = loader.getController();
RethinkDBConnection connection = new RethinkDBConnection(controller.getDataList());
connection.connect();
Scene scene = new Scene(root);
primaryStage.setTitle("Ticket System Application");
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Note that I renamed some classes and methods to adhere to standard naming conventions.

JavaFX TableView Issues Adding Rows + Organizing Multi Controller and FXML App

I'm new to JavaFX and I've been at this code for about 8 hours now and I've become a bit delusional with the code. My two main problems are:
Can't add new items to the TableView using my popUp box display().
Feels messy and unorganized. Any tips for better communication between FXML and Controllers? (Again I'm new so it could be that I've stared too long at it)
My main class
public class Main extends Application {
public static Stage primaryStage;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage window) throws Exception {
try {
primaryStage = new Stage();
window = primaryStage;
Parent root = FXMLLoader.load(getClass().getResource("Fissto.fxml"));
Scene scene = new Scene(root);
window.setTitle("Fissto - the File Storage App!");
window.setScene(scene);
window.show();
}catch(Exception e){
e.printStackTrace();
}
// C.setLibraryStage();
}
}
My main Controller class (I have two sub ones that connect in the Fissto.fxml)
public class Controller implements Initializable{
Main main;
#FXML LibraryController libraryController = new LibraryController();
#FXML MergePageController mergePageController = new MergePageController();
private AddImageController addImageController = new AddImageController();
#FXML public void initialize(URL location, ResourceBundle resources){
System.out.println("View is now loaded!");
main = new Main();
libraryController.init(this);
mergePageController.init(this);
addImageController.init(this);
}
//Interface Initialization
public void setMergeStage() throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("Controllers/MergePage.fxml"));
Scene scene = new Scene(root);
main.primaryStage.setScene(scene);
}
public void setLibraryStage() throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("Controllers/LibraryPage.fxml"));
Scene scene = new Scene(root);
main.primaryStage.setScene(scene);
}
//Closing a window
public void closeWindow(){
main.primaryStage.close();
}
}
And finally the controller for the page that holds the TableView
public class LibraryController {
private Controller main;
//Library TableView Controllers
#FXML public TableView<Image> library;
#FXML private TableColumn<Image, String> NameColumn = new TableColumn<>();
#FXML private TableColumn<Image, ArrayList<String>> TagsColumn = new TableColumn<>();
#FXML private TableColumn<Image, String> CommentsColumn = new TableColumn<>();
#FXML private TableColumn<Image, String> FileLocationColumn = new TableColumn<>();
#FXML private TableColumn<Image, Integer> PointsColumn = new TableColumn<>();
public void init(Controller main){
System.out.println("LibraryPage Loading");
this.main = main;
addDataToColumns();
library = new TableView<>();
library.getItems().setAll(getImages());
System.out.println("LibraryPage Loaded");
}
//Initializes the column titles
private void addDataToColumns(){
NameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
TagsColumn.setCellValueFactory(new PropertyValueFactory<>("tags")); //TODO Convert to String format
CommentsColumn.setCellValueFactory(new PropertyValueFactory<>("comments"));
FileLocationColumn.setCellValueFactory(new PropertyValueFactory<>("filelocation"));
PointsColumn.setCellValueFactory(new PropertyValueFactory<>("points"));
}
//Gets all of the images
private ObservableList<Image> getImages() {
//TODO: Add where to actually get the data from
ObservableList<Image> images = FXCollections.observableArrayList();
String s = "Dog, Cat, Jumping Jack,";
ArrayList<String> list = Image.getTagOrganizer(',', s);
images.add(new Image("Test", list, "Comment", "No File Location, yet!", 10));
String k = "Calculus, Complex Numbers, Hard dude,";
ArrayList<String> list2 = Image.getTagOrganizer(',', k);
images.add(new Image("Number2", list2, "I love MathClub", "No File Location, yet!", -10));
return images;
}
This last class is the popup menu that takes in input to put in the GridPane
public class AddImageController {
private Controller main;
public void init(Controller main){
System.out.println("ImagePage Loaded");
this.main = main;
}
//Submitting an image to the library from the AddImagePage
public TextField nameInput;
public TextField tagsInput;
public TextField commentInput;
public TextField pointsInput;
public Label errorMessage;
/** TODO: Make it so that it writes to file then theoretically, the main controller should read from file every so often
* Main functionality for adding the information from the form to the database */
public void submitImage(){
if(!(nameInput.getText().trim().isEmpty()) && !(tagsInput.getText().trim().isEmpty()) && !(pointsInput.getText().trim().isEmpty())) {
if (isInt(pointsInput)) {
// System.out.print("Sent to database, *whoosh!*");
LibraryController c = new LibraryController();
ArrayList<String> s = Image.getTagOrganizer(',', tagsInput.getText());
Image image = new Image(nameInput.getText(), s, commentInput.getText(),"Location Needed", Integer.parseInt(pointsInput.getText()));
c.library.getItems().add(image);
clearInputs();
}
}else {
errorMessage.setText("Fill every field");
}
}
//Clears the input fields in the AddImagePage
public void clearInputs(){
nameInput.clear();
tagsInput.clear();
commentInput.clear();
pointsInput.clear();
errorMessage.setText("");
}
//Submission format verifiers
private boolean isInt(TextField input){
try{
int i = Integer.parseInt(input.getText());
errorMessage.setText("");
return true;
}catch (NumberFormatException e){
System.out.println("Oh no: " + input.getText() + " is not an integer");
errorMessage.setText("Points must be a number");
return false;
}
}
//Image Selection Handler
public void imageSelectionHandler(){
}
}
I understand it may be hard to read, so any feedback on how to make it easier to read in the future is much appreciated.

Pagenavigation and value passing with afterburner fx in JavaFX?

I'm using afterburner fx the DI-framework.
My problem is, that I have a "RootLayout" which is a BorderPane. On the top is a MenueBar, which works and in the center I loaded an other pane on startup. Now I want to be able to click on a button, so that the Center-Pane changes to a new View AND I want to pass a value to the new View/Controller.
My main class:
#Override
public void start(Stage primaryStage) throws Exception {
initInjector();
//BorderPane
RootView appView = new RootView();
Scene scene = new Scene(appView.getView());
primaryStage.setTitle("Personalplanung");
primaryStage.setScene(scene);
primaryStage.show();
}
Controller/Presenter of my Root
public class RootPresenter implements Initializable {
#FXML
private AnchorPane center;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
MainView view = new MainView();
center.getChildren().add(view.getView());
}
//Doesn't work because it must be static -> AnchorPane can't be static
public void putCenter(FXMLView fxmlView) {
center.getChildren().add(fxmlView.getView());
}
Presenter of the view I want to change to and pass value (e.g. selected person)
public class MainPresenter implements Initializable {
#Inject
PersonService personService;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
}
/**
* Pseudo display of all persons
* should switch here to PersoView and pass values
* gets triggerd by button click
*/
#FXML
private void handlePersonsOverview() {
personService.all().forEach(person -> {
System.out.println(person.getVorname());
});
}
All my views are empty but extend the FXMLView (is convention)
import com.airhacks.afterburner.views.FXMLView;
public class PersonView extends FXMLView{
}
If I understand your structure correctly, I think you can solve this with a ViewModel:
public class ViewModel {
private final ObjectProperty<Node> mainView = new SimpleObjectProperty(this, "mainView", null);
public ObjectProperty<Node> mainViewProperty() {
return mainView ;
}
public final Node getMainView() {
return mainView.get();
}
public final void setMainView(Node mainView) {
this.mainView.set(mainView);
}
}
Now just inject the ViewModel wherever you need it. Bind the center of the root to the view model's mainView property, and update the mainView property from your other presenters:
public class RootPresenter {
#FXML
private BorderPane root ; // I think you have this?
#FXML
private AnchorPane center ; // possibly no longer need this?
#Inject
private ViewModel viewModel ;
public void initialize() {
root.centerProperty().bind(viewModel.mainViewProperty());
MainView view = new MainView();
viewModel.setMainView(view.getView());
}
}
Now any presenter that needs to change the center of your root just needs to do:
public class SomePresenter {
#Inject
private ViewModel viewModel ;
#FXML
public void someHandlerMethod() {
SomeView someView = new SomeView();
viewModel.setMainView(someView.getView());
}
}
To pass values to the new presenter, just define the appropriate properties and methods in the presenter and invoke them when you create the new view:
public class MainPresenter {
private final ObjectProperty<Person> person = new SimpleObjectProperty<>(this, "person") ;
public ObjectProperty<Person> personProperty() {
return person ;
}
public final Person getPerson() {
return person.get();
}
public final void setPerson(Person person) {
this.person.set(person);
}
public void initialize() {
// bind to person as needed ...
// other stuff as before
}
// ...
}
and then you can do
MainView mainView = new MainView();
MainPresenter mainPresenter = (MainPresenter) mainView.getPresenter();
mainPresenter.setPerson(selectedPerson);

One of the TableColumn doesn't show the values but others work fine. JavaFX

I have a TableView with three TableColumns. There is an ObservableList named "sensorDataList " in MainApp.java that stores the objects to be shown in the TableView. With the following code, only the first TableColumn named "idColumn" doesn't show the values from the observable list, however, the other two TableColumns works fine.
MainApp.java (this has an "ObservableList" of Sensor objects (see Sensor.java). Also this class has the method named "showSensorDialog()" which loads the .fxml file that has the TableView in question. FYI, this method is invoked by a button in other controller.)
public class MainApp extends Application {
private Stage primaryStage;
private Stage sensorDialogStage;
private ObservableList<sensor> sensorDataList = FXCollections.observableArrayList();
public MainApp(){
sensorDataList.add(new sensor("testText","1 1 0.7", "0 0 1"));
}
public ObservableList<Sensor> getSensorDataList(){return sensorDataList;}
public void showSensorDialog() {
try {
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("/view/SensorDialog.fxml"));
Object object = loader.load();
sensorDialogStage = new Stage();
Scene scene = new Scene((Parent) object);
sensorDialogStage.setScene(scene);
SensorDialogController controller = loader.getController();
controller.setSensorDialogStage(sensorDialogStage);
controller.setMainApp(this); // this line connects the ObservableList to the TableView.
sensorDialogStage.showAndWait();
} catch (IOException e) {}
}
}
SensorDialogController.java
public class SensorDialogController implements Initializable {
#FXML
private TableView<Sensor> sensorTable;
#FXML
private TableColumn<Sensor, String> idColumn;
#FXML
private TableColumn<Sensor, String> locationColumn;
#FXML
private TableColumn<Sensor, String> directionColumn;
private MainApp mainApp;
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
sensorTable.setItems(mainApp.getSensorDataList()); // ObservableList and TableView gets connected.
}
#Override
public void initialize(URL url, ResourceBundle rb){
idColumn.setCellValueFactory(new PropertyValueFactory<Sensor, String>("id"));
locationColumn.setCellValueFactory(new PropertyValueFactory<Sensor, String>("location"));
directionColumn.setCellValueFactory(new PropertyValueFactory<Sensor, String>("direction"));
}
}
Sensor.java
public class Sensor{
private SimpleStringProperty id;
private SimpleStringProperty location;
private SimpleStringProperty direction;
public Sensor(String i, String loc, String dir){
this.id = new SimpleStringProperty(i);
this.location = new SimpleStringProperty(loc);
this.direction = new SimpleStringProperty(dir);
}
}

Categories