Susukacang
Susukacang

Reputation: 7

Label not displaying text even after change (JavaFX)

I'm working on a project and I need to display the information of a Medicine object from a ListView to another Scene. The user would select a Medicine from the ListView and press the Button to see it's details in the next Scene that would be displayed by Labels. The problem now is, I have transferred the info, and the text property of the Label has changed (observed through println and debugging), but the Label just won't display the changed text.

this is the main

package app;

import app.data.MedicineData;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import org.w3c.dom.events.Event;

import java.io.IOException;


public class Pharmachine extends Application {
    public static final double WIDTH = 480;
    public static final double HEIGHT = 720;

    @Override
    public void start(Stage stage) throws Exception{
        Parent homePage = FXMLLoader.load(getClass().getResource("homepage.fxml"));

        Scene homePageScene = newDefaultScene(homePage);

        stage.setResizable(false);
        stage.setScene(homePageScene);
        stage.setTitle("Pharmachine");
        stage.show();
    }

    @Override
    public void init(){
        MedicineData.getInstance().loadData();
    }

    public static Scene newDefaultScene(Parent parent){
        Scene scene = new Scene(parent, WIDTH, HEIGHT);
        scene.addEventHandler(MouseEvent.MOUSE_CLICKED,
                (mouseEvent) -> {
                    Node targetNode = scene.getFocusOwner();
                    if(targetNode != null && targetNode.isFocused()) {
                        if(targetNode.getParent() != null)
                            targetNode.getParent().requestFocus();
                        mouseEvent.consume();
                    }
                }
        );
        return scene;
    }

    public static void navigateTo(ActionEvent actionEvent, String filename){
        Stage mainWindow = (Stage) ((Node) actionEvent.getSource()).getScene().getWindow();
        Scene currentScene = ((Node) actionEvent.getSource()).getScene();
        try {
            currentScene.setRoot(FXMLLoader.load(Pharmachine.class.getResource(filename)));
            mainWindow.setScene(currentScene);
        } catch(IOException e){
            e.printStackTrace();
        }
    }

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

this is the fxml for the list's page

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.*?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
            fx:controller="app.ListpageController" fx:id="pageRoot"
            stylesheets="@styles/main.css">
    <left>
        <GridPane fx:id="listArea" alignment="CENTER">
            <ListView fx:id="medicineList"
                      GridPane.rowIndex="1"/>
        </GridPane>
    </left>
    <center>
        <GridPane fx:id="buttonsArea" alignment="CENTER"
                  hgap="10" vgap="10">
            <Button text="Back"
                    onAction="#displayHomePage"
                    GridPane.halignment="CENTER"/>
            <Button text="Details"
                    onAction="#displayDetailsPage"
                    GridPane.rowIndex="1"
                    GridPane.halignment="CENTER"/>
        </GridPane>
    </center>
</BorderPane>

here is the controller for the list's page

package app;

import app.data.Medicine;
import app.data.MedicineData;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.util.Callback;

import java.io.IOException;

public class ListpageController {
    @FXML
    private BorderPane pageRoot;
    @FXML
    private GridPane listArea;
    @FXML
    private GridPane buttonsArea;
    @FXML
    private ListView<Medicine> medicineList;

    @FXML public void initialize(){
        listArea.setMaxWidth(Pharmachine.WIDTH * 3/5);
        medicineList.setMinWidth(listArea.getMaxWidth());
        medicineList.setMinHeight(Pharmachine.HEIGHT);

        medicineList.setItems(MedicineData.getInstance().getMedicines());
        medicineList.setCellFactory(new Callback<>() {
            @Override
            public ListCell<Medicine> call(ListView<Medicine> medicineListView) {
                ListCell<Medicine> listCell = new ListCell<>(){
                    @Override
                    public void updateItem(Medicine medicine, boolean empty){
                        super.updateItem(medicine, empty);
                        if(!empty){
                            HBox medName = new HBox(new Label(medicine.getName()));
                            HBox.setHgrow(medName, Priority.ALWAYS);
                            HBox medPrice = new HBox(new Label(String.format("RM%.2f", medicine.getPrice())));

                            HBox medLabel = new HBox(medName, medPrice);
                            setGraphic(medLabel);
                        }
                    }
                };
                listCell.setOnMouseClicked(
                        (mouseEvent) ->  {
                            if(mouseEvent.getClickCount() == 2){
                                medicineList.getSelectionModel().clearSelection();
                            }
                        }
                );

                return listCell;
            }
        });
    }

    @FXML private void displayHomePage(ActionEvent actionEvent){
        Pharmachine.navigateTo(actionEvent, "homepage.fxml");
    }

    @FXML private void displayDetailsPage(ActionEvent actionEvent){
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("detailspage.fxml"));

        try {
            loader.load();
        } catch(IOException e){
            e.printStackTrace();
        }

        DetailspageController controller = loader.getController();
        Medicine selectedMedicine = medicineList.getSelectionModel().getSelectedItem();

        if(selectedMedicine != null) {
            controller.setInfo(selectedMedicine);
            Pharmachine.navigateTo(actionEvent, "detailspage.fxml");
        }
    }
}

this is the fxml for the next scene (just simple for now)

<?xml version="1.0" encoding="UTF-8"?>


<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.text.Text?>
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
            fx:id="pageRoot" fx:controller="app.DetailspageController"
            stylesheets="@styles/main.css">
    <center>
        <GridPane fx:id="detailsArea"
                  alignment="CENTER" hgap="10" vgap="10">
            <Label text="Details"/>
            <Text text="Name: "
                  GridPane.rowIndex="1"/>
            <Label fx:id="medNameLabel" text="~"
                   GridPane.rowIndex="1" GridPane.columnIndex="1"/>
            <Text text="Price: "
                  GridPane.rowIndex="2"/>
            <Label fx:id="medPriceLabel" text="~"
                   GridPane.rowIndex="2" GridPane.columnIndex="1"/>
        </GridPane>
    </center>
</BorderPane>

and this is the scene's controller

package app;

import app.data.Medicine;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;

import java.net.URL;
import java.util.ResourceBundle;

public class DetailspageController implements Initializable {
    private Medicine selectedMedicine;

    @FXML
    private BorderPane pageRoot;
    @FXML
    private GridPane detailsArea;
    @FXML
    private Label medNameLabel;
    @FXML
    private Label medPriceLabel;

    @Override
    public void initialize(URL url, ResourceBundle rb){

    }

    public void setInfo(Medicine medicine){
        selectedMedicine = medicine;
        medNameLabel.setText(selectedMedicine.getName());
        medPriceLabel.setText(String.format("RM%.2f", selectedMedicine.getPrice()));
        System.out.println(medNameLabel.textProperty());
        System.out.println(medNameLabel.getText());
        medNameLabel.setStyle("-fx-background-color: red;");
    }
}

The help would mean a lot. Thank you :]

Upvotes: 0

Views: 887

Answers (1)

VGR
VGR

Reputation: 44308

In your displayDetailsPage method, you load a scene from detailspage.fxml, and you update its labels by calling the setInfo method of the controller.

Then, you call Pharmachine.navigateTo, which loads detailspage.xml again and replaces the scene root with the newly loaded root. You updated the text of the labels in the first details page, but the second details page is brand new, so it doesn’t have those changes.

The second argument in the navigateTo method should be of type Parent rather than a String. navigateTo should not attempt to load any .fxml file; let that be the caller’s responsibility.

Side note: When a list has multiple attributes for each data item, you should probably use a TableView rather than a ListView.

Upvotes: 1

Related Questions