java - 如何在javafx的子场景中获取元素的值

标签 java javafx

包含subScene的新任务场景的控制器:

public class newTaskController {




static private DBHandler dbHandler = new DBHandler();
static private Connection connection;

static {
    try {
        connection = dbHandler.getDBConnection();
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
}

static private JdbcPreparedStatement preparedStatement;


private final ObservableList<String> proxies =
        FXCollections.observableArrayList();


FXMLLoader supremeWebsiteLoader = new FXMLLoader(getClass().getResource("Resources/supremeWebsite.fxml"));
Parent supremeWebsitePane = supremeWebsiteLoader.load();

FXMLLoader advancedSupremeWebsiteLoader = new FXMLLoader(getClass().getResource("Resources/advancedSupremeWebsite.fxml"));
Parent advancedSupremeWebsitePane = advancedSupremeWebsiteLoader.load();

FXMLLoader palaceWebsiteLoader = new FXMLLoader(getClass().getResource("Resources/palaceWebsite.fxml"));
Parent palaceWebsitePane = palaceWebsiteLoader.load();


@FXML
private SubScene subScene;

@FXML
private ComboBox<String> website;

@FXML
private ComboBox<String> profile;

@FXML
private ComboBox<String> proxyList;


@FXML
void getAdvanced(ActionEvent event) {
    String website_value = website.getValue();
    if (website_value.equals("Supreme")) {


        subScene.setRoot(advancedSupremeWebsitePane);

    }
    if (website_value.equals("Palace")) {

        //    subScene.setRoot(advancedPalaceWebsitePane);
        // does not yet exist

    } else {


    }
}

@FXML
void getGeneral(ActionEvent event) {
    String website_value = (String) website.getValue();
    if (website_value.equals("Supreme")) {


        subScene.setRoot(supremeWebsitePane);

    }
    if (website_value.equals("Palace")) {


        subScene.setRoot(palaceWebsitePane);

    }
}

public newTaskController() throws IOException {
}


@FXML
void cancel(ActionEvent event) {
    Stage primaryStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
    primaryStage.close();

}

@FXML
void save(ActionEvent event) {


}

@FXML
void saveAndExit(ActionEvent event) {


}

@FXML
void updateWebsiteSelection(ActionEvent event) {
    String website_value = website.getValue();
    if (website_value.equals("Supreme")) {

        subScene.setRoot(supremeWebsitePane);



    }
    if (website_value.equals("Palace")) {

        subScene.setRoot(palaceWebsitePane);

    }

}

@FXML
void initialize() throws SQLException {


    profile.getSelectionModel().clearSelection();
    profile.getItems().clear();
    ProfileList.updateProfilesList();
    profile.setItems(ProfileList.getProfiles());
    profile.getSelectionModel().select(0);


    proxies.add("localhost");
    proxyList.setItems(proxies);

    website.getSelectionModel().select("Supreme");

    subScene.setRoot(supremeWebsitePane);
    proxyList.getSelectionModel().select(0);


}


}

Image shows newTask scene which has a blank subScene

启动应用程序时,subScene可以显示代表不同字段的两个fxml文档中的任何一个,供用户输入数据,例如:

newTask scene with subScene populated

该窗口上的保存按钮位于newTask场景上,但是当我单击“保存”时,newTask控制器需要从其他2个控制器(supremeGeneralController和supremeAdvancedController)中获取数据,然后保存到数据库中,但是,我遇到了冲突的问题静态和非静态方法。

我对Java不太熟悉,因此不胜感激

最佳答案

关键解决方案要素

不要使用SubScene,仅当您需要在场景中包含另一个具有不同属性的场景时(例如,您的场景具有2D控件并且您要包括3D深度排序的SubScene),才需要使用SubScene。 。您不会遇到这种情况,因此不需要SubScene。

提供的解决方案使用称为nested controllers的技术。

在父fxml文件中,包括子fxml文件:

<Pane>
  <fx:include source="group-editor.fxml" fx:id="groupEditor"/>
  <fx:include source="person-editor.fxml" fx:id="personEditor"/>
</Pane>


在父控制器中,为子控制器和子场景图的根节点(由@FXML值标识)提供fx:id引用。加载父控制器时,FXMLLoader将自动填充这些值。

@FXML
private VBox groupEditor;
@FXML
private GroupEditorController groupEditorController;
@FXML
private VBox personEditor;
@FXML
private PersonEditorController personEditorController;


根据应用程序状态或用户选择,让父控制器一次仅显示一个孩子。

groupEditor.setVisible(false);
groupEditorControl.selectedProperty().addListener((observable, wasSelected, isSelected) -> {
    groupEditor.setVisible(isSelected);
    personEditor.setVisible(!isSelected);
});


在每个子控制器中,定义允许您设置父控制器的设置器,并在父控制器的initialize函数中调用这些设置器。

groupEditorController.setDepartmentController(this);
personEditorController.setDepartmentController(this);


现在,您已经完成了操作,子控制器的initialize()功能可以同时使用为子控制器定义的元素和为父控制器定义的任何元素:

saveButton.setOnAction(event ->
        db.savePerson(
                departmentController.getDepartmentName(),
                firstName.getText(),
                lastName.getText()
        )
);


最少的应用示例

我将根据您陈述的现有FXML结构和模拟数据库,尝试提供提供答案所需的最少代码,即使这样的答案并非对所有应用程序(可能包括您的应用程序)都是最佳的。

即使使用最少的应用程序,您的要求也很复杂,因此在不同的文件和类中需要一些代码。

嵌套控制器的示例解决方案

对于该示例,它假设您正在编辑有关部门的信息。您可以设置部门名称。您可以通过不同的形式将与部门关联的人员或组保存到部门数据库中。

该解决方案基于james-d's nested controller example,但对此进行了简化,并对其进行了重大修改,以使其与您要解决的特定问题的描述更加匹配。

为了更好地了解解决方案的方法,请阅读nested controllers上的fxml文档部分,该部分应使您对解决方案的工作原理有所了解。

所有代码都在名为controllers的程序包中。

数据库.java

模拟数据库。

package controllers;

public class Database {
    private static Database instance = new Database();

    public static Database getInstance() {
        return instance;
    }

    public void savePerson(String department, String firstName, String lastName) {
        System.out.println("Saved person " + firstName + " " + lastName + " into department " + department);
    }

    public void saveGroup(String department, String groupName, String description) {
        System.out.println("Saved group " + groupName + " with description " + description + " into department " + department);
    }
}


DepartmentEditorApp.java

主要应用类别

package controllers;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class DepartmentEditorApp extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        Scene scene = new Scene(
                FXMLLoader.load(
                        getClass().getResource(
                                "department-editor.fxml"
                        )
                )
        );

        stage.setScene(scene);
        stage.show();
    }

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


部门编辑器

主应用程序布局,包括其他fxml文件,用于编辑组或人员。

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="controllers.DepartmentController" spacing="10">
    <padding>
      <Insets topRightBottomLeft="10" />
    </padding>
    <HBox spacing="10">
      <Label text="Department:"/>
      <TextField fx:id="departmentName" text="Engineering"/>
    </HBox>
    <RadioButton text="Group Editor" fx:id="groupEditorControl"/>
    <Pane>
      <fx:include source="person-editor.fxml" fx:id="personEditor"/>
      <fx:include source="group-editor.fxml" fx:id="groupEditor"/>
    </Pane>
</VBox>


DepartmentController.java

控制主应用程序的显示。

package controllers;

import javafx.fxml.FXML;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;

public class DepartmentController {
    @FXML
    private TextField departmentName;
    @FXML
    private RadioButton groupEditorControl;
    @FXML
    private VBox groupEditor;
    @FXML
    private GroupEditorController groupEditorController;
    @FXML
    private VBox personEditor;
    @FXML
    private PersonEditorController personEditorController;

    public void initialize() {
        groupEditor.setVisible(false);
        groupEditorControl.selectedProperty().addListener((observable, wasSelected, isSelected) -> {
            groupEditor.setVisible(isSelected);
            personEditor.setVisible(!isSelected);
        });

        groupEditorController.setDepartmentController(this);
        personEditorController.setDepartmentController(this);
    }

    public String getDepartmentName() {
        return departmentName.getText();
    }
}


人员编辑器

子数据输入表单。

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

<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>

<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="controllers.PersonEditorController" spacing="10">
  <Label text="Person Editor"/>
  <GridPane>
    <Label text="First Name:">
      <GridPane.columnIndex>0</GridPane.columnIndex>
      <GridPane.rowIndex>0</GridPane.rowIndex>
    </Label>
    <Label text="Last Name:">
      <GridPane.columnIndex>0</GridPane.columnIndex>
      <GridPane.rowIndex>1</GridPane.rowIndex>
    </Label>
    <TextField fx:id="firstName" text="Kevin">
      <GridPane.columnIndex>1</GridPane.columnIndex>
      <GridPane.rowIndex>0</GridPane.rowIndex>
    </TextField>
    <TextField fx:id="lastName" text="Anderson">
      <GridPane.columnIndex>1</GridPane.columnIndex>
      <GridPane.rowIndex>1</GridPane.rowIndex>
    </TextField>
  </GridPane>
  <Button text="Save" fx:id="saveButton"/>
</VBox>


PersonEditorController.java

子窗体的控制器。

package controllers;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;

public class PersonEditorController {
    private Database db = Database.getInstance();
    private DepartmentController departmentController;

    @FXML
    public Button saveButton;
    @FXML
    private TextField firstName;
    @FXML
    private TextField lastName;

    public void initialize() {
        saveButton.setOnAction(event ->
                db.savePerson(
                        departmentController.getDepartmentName(),
                        firstName.getText(),
                        lastName.getText()
                )
        );
    }

    public void setDepartmentController(DepartmentController departmentController) {
        this.departmentController = departmentController;
    }
}


组编辑器.fxml

另一个子数据输入表单。

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

<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>

<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="controllers.GroupEditorController" spacing="10">
  <Label text="Group Editor"/>
  <GridPane >
    <Label text="Group Name:">
      <GridPane.columnIndex>0</GridPane.columnIndex>
      <GridPane.rowIndex>0</GridPane.rowIndex>
    </Label>
    <Label text="Group Description:">
      <GridPane.columnIndex>0</GridPane.columnIndex>
      <GridPane.rowIndex>1</GridPane.rowIndex>
    </Label>
    <TextField fx:id="groupName" text="Hardware">
      <GridPane.columnIndex>1</GridPane.columnIndex>
      <GridPane.rowIndex>0</GridPane.rowIndex>
    </TextField>
    <TextField fx:id="groupDescription" text="Nuts and Bolts">
      <GridPane.columnIndex>1</GridPane.columnIndex>
      <GridPane.rowIndex>1</GridPane.rowIndex>
    </TextField>
  </GridPane>
  <Button text="Save" fx:id="saveButton"/>
</VBox>


GroupEditorController.java

子项输入表单的另一个控制器。

package controllers;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;

public class GroupEditorController {
    private Database db = Database.getInstance();
    private DepartmentController departmentController;

    @FXML
    private Button saveButton;
    @FXML
    private TextField groupName;
    @FXML
    private TextField groupDescription;

    public void initialize() {
        saveButton.setOnAction(event ->
                db.saveGroup(
                        departmentController.getDepartmentName(),
                        groupName.getText(),
                        groupDescription.getText()
                )
        );
    }

    public void setDepartmentController(DepartmentController departmentController) {
        this.departmentController = departmentController;
    }
}


备择方案

除了这里展示的嵌套控制器方法外,还有其他方法可以完成。例如,请参见Loading new fxml in the same scene的答案,它只是根据需要替换了主控制器框架中的窗格,而不是嵌套的包含隐藏和显示的窗格,如下所示。

推荐:为您的应用程序提供更强大的体系结构

您应该做的是为您的应用程序和代码提供更通用的体系结构,以适合那些体系结构。这种改进的体系结构的示例元素可以是带有mvvmDAO accessor pattern。如果是我,我还将向您的控制器中引入模型对象和服务的Spring注入,并使用Spring Data进行数据存储。但是,描述这样的体系结构以及如何将其应用于解决您的问题超出了StackOverflow答案的范围。另外,请谨慎尝试应用您可能难以理解和使用的更复杂的架构,框架和库。

关于java - 如何在javafx的子场景中获取元素的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59536811/

相关文章:

java - 执行环境JRE选择什么

java - 如何使用 Spring Boot 查询和检索约 100 个客户数据库的结果?

java - 正确地将 Jest 添加到 Java Play 2.5.x

java - 如何通过 URL 使用 setbackground 属性

java - 如何在 JavaFX 中将 ObjectProperty<String> 转换为 StringProperty?

java - 将 JavaFX WebView 调整为文档正文所需的最小大小

Java - 从对象获取具有公共(public)父类(super class)的字段列表

java - 有没有办法将我所有重复的 VBox 重新组织到自定义 JavaFX 标签中?

java - ListView 样式化所选元素的文本填充 - JavaFX 8 MAGIC 或 BUG?

java - 使 JavaFX 应用程序非静态