即使更改后标签也不显示文本 (JavaFX)

Label not displaying text even after change (JavaFX)

我正在做一个项目,我需要显示一个 ListView 到另一个 Scene 的 Medicine 对象的信息。 用户将 select 来自 ListView 的药物,然后按 Button 以在下一个 Scene 中查看它的详细信息,这将由 Label 显示。现在的问题是,我传了信息,Label的文本属性变了(通过println和调试观察),但是Label就是不显示变了的文本。

这是主要的

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); }
}

这是列表页面的 fxml

<?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>

这是列表页面的控制器

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");
        }
    }
}

这是下一个场景的 fxml(现在很简单)

<?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>

这是场景的控制器

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;");
    }
}

帮助意义重大。谢谢:]

在您的 displayDetailsPage 方法中,您从 detailspage.fxml 加载场景,并通过调用控制器的 setInfo 方法更新其标签。

然后,您调用 Pharmachine.navigateTo,它再次加载 detailspage.xml 并用新加载的根替换场景根。您更新了第一个详细信息页面中的标签文本,但是第二个详细信息页面是全新的,因此没有这些变化。

navigateTo 方法中的第二个参数应该是 Parent 类型而不是字符串。 navigateTo 不应尝试加载任何 .fxml 文件;让那成为来电者的责任。

旁注:当列表的每个数据项都有多个属性时,您可能应该使用 TableView 而不是 ListView。