Truyền tham số JavaFX FXML


194

Làm cách nào tôi có thể truyền tham số cho cửa sổ phụ trong javafx? Có cách nào để giao tiếp với bộ điều khiển tương ứng?

Ví dụ: Người dùng chọn một khách hàng từ một TableViewvà một cửa sổ mới được mở, hiển thị thông tin của khách hàng.

Stage newStage = new Stage();
try 
{
    AnchorPane page = (AnchorPane) FXMLLoader.load(HectorGestion.class.getResource(fxmlResource));
    Scene scene = new Scene(page);
    newStage.setScene(scene);
    newStage.setTitle(windowTitle);
    newStage.setResizable(isResizable);
    if(showRightAway) 
    {
        newStage.show();
    }
}

newStagesẽ là cửa sổ mới. Vấn đề là, tôi không thể tìm ra cách để nói với bộ điều khiển nơi tìm thông tin của khách hàng (bằng cách chuyển id làm tham số).

Có ý kiến ​​gì không?


Kiểm tra xem điều này có hoạt động không: stackoverflow.com/questions/14370183/ cấp
Dynelight

@Alvaro: bạn đã có được giải pháp của mình chưa? bạn có thể vượt qua tham số? từ một bộ điều khiển đến tập tin điều khiển khác?
Người đàn ông Java

3
Đúng. jewnes đã đưa ra một lời giải thích cấp sách. Đó là lý do tại sao tôi chấp nhận câu trả lời của anh ấy
Alvaro

Câu trả lời:


276

Phương pháp đề xuất

Câu trả lời này liệt kê các cơ chế khác nhau để truyền tham số cho bộ điều khiển FXML.

Đối với các ứng dụng nhỏ, tôi đặc biệt khuyên bạn nên truyền tham số trực tiếp từ người gọi đến bộ điều khiển - đơn giản, dễ hiểu và không yêu cầu thêm khung.

Đối với các ứng dụng lớn hơn, phức tạp hơn, sẽ rất đáng để điều tra nếu bạn muốn sử dụng các cơ chế Dependency Injection hoặc Event Bus trong ứng dụng của mình.

Truyền tham số trực tiếp từ người gọi đến bộ điều khiển

Truyền dữ liệu tùy chỉnh cho bộ điều khiển FXML bằng cách truy xuất bộ điều khiển từ phiên bản trình tải FXML và gọi một phương thức trên bộ điều khiển để khởi tạo nó với các giá trị dữ liệu cần thiết.

Một cái gì đó giống như đoạn mã sau:

public Stage showCustomerDialog(Customer customer) {
  FXMLLoader loader = new FXMLLoader(
    getClass().getResource(
      "customerDialog.fxml"
    )
  );

  Stage stage = new Stage(StageStyle.DECORATED);
  stage.setScene(
    new Scene(
      (Pane) loader.load()
    )
  );

  CustomerDialogController controller = 
    loader.<CustomerDialogController>getController();
  controller.initData(customer);

  stage.show();

  return stage;
}

...

class CustomerDialogController {
  @FXML private Label customerName;
  void initialize() {}
  void initData(Customer customer) {
    customerName.setText(customer.getName());
  }
}

Một FXMLLoader mới được xây dựng như thể hiện trong mã mẫu tức là new FXMLLoader(location). Vị trí là một URL và bạn có thể tạo một URL như vậy từ tài nguyên FXML bằng cách:

new FXMLLoader(getClass().getResource("sample.fxml"));

Cẩn thận KHÔNG sử dụng chức năng tải tĩnh trên FXMLLoader, nếu không bạn sẽ không thể lấy bộ điều khiển từ phiên bản trình tải của mình.

Bản thân FXMLLoader không bao giờ biết bất cứ điều gì về các đối tượng miền. Bạn không trực tiếp chuyển các đối tượng miền cụ thể của ứng dụng vào hàm tạo FXMLLoader, thay vào đó bạn:

  1. Xây dựng một FXMLLoader dựa trên đánh dấu fxml tại một vị trí được chỉ định
  2. Nhận bộ điều khiển từ phiên bản FXMLLoader.
  3. Gọi các phương thức trên bộ điều khiển được truy xuất để cung cấp cho bộ điều khiển các tham chiếu đến các đối tượng miền.

Blog này (bởi một nhà văn khác) cung cấp một ví dụ thay thế, nhưng tương tự .

Đặt Bộ điều khiển trên FXMLLoader

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

FXMLLoader loader = new FXMLLoader(
    getClass().getResource(
        "customerDialog.fxml"
    )
);
loader.setController(dialogController);

Pane mainPane = (Pane) loader.load();

Bạn có thể xây dựng một bộ điều khiển mới trong mã, chuyển bất kỳ tham số nào bạn muốn từ trình gọi của bạn vào hàm tạo của bộ điều khiển. Khi bạn đã xây dựng bộ điều khiển, bạn có thể đặt nó trên một cá thể FXMLLoader trước khi bạn gọi phương thức load() cá thể .

Để đặt bộ điều khiển trên trình tải (trong JavaFX 2.x), bạn cũng không thể xác định một fx:controllerthuộc tính trong tệp fxml của mình.

Do giới hạn về fx:controllerđịnh nghĩa trong FXML, cá nhân tôi thích nhận bộ điều khiển từ FXMLLoader hơn là đặt bộ điều khiển vào FXMLLoader.

Có bộ điều khiển lấy tham số từ phương thức tĩnh bên ngoài

Phương pháp này được minh họa bằng câu trả lời của Sergey cho Javafx 2.0 How-to Application.getParameter () trong một tệp Controller.java .

Sử dụng tiêm phụ thuộc

FXMLLoader hỗ trợ các hệ thống tiêm phụ thuộc như Guice, Spring hoặc Java EE CDI bằng cách cho phép bạn đặt nhà máy điều khiển tùy chỉnh trên FXMLLoader. Điều này cung cấp một cuộc gọi lại mà bạn có thể sử dụng để tạo phiên bản điều khiển với các giá trị phụ thuộc được chèn bởi hệ thống tiêm phụ thuộc tương ứng.

Một ví dụ về ứng dụng JavaFX và phép tiêm phụ thuộc bộ điều khiển với Spring được cung cấp trong câu trả lời cho:

Một cách tiếp cận tiêm phụ thuộc thực sự tốt đẹp, sạch sẽ được minh họa bằng khung afterburner.fx với một ứng dụng hack không khí mẫu sử dụng nó. afterburner.fx dựa vào JEE6 javax.inject để thực hiện tiêm phụ thuộc.

Sử dụng xe buýt sự kiện

Greg Brown, người tạo và triển khai đặc tả FXML ban đầu, thường đề nghị xem xét sử dụng xe buýt sự kiện, chẳng hạn như Guava EventBus , để liên lạc giữa các bộ điều khiển khởi tạo FXML và logic ứng dụng khác.

EventBus là một API xuất bản / đăng ký đơn giản nhưng mạnh mẽ với các chú thích cho phép các POJO giao tiếp với nhau ở bất cứ đâu trong JVM mà không cần phải tham khảo lẫn nhau.

Hỏi đáp tiếp theo

về phương pháp đầu tiên, tại sao bạn trở lại Giai đoạn? Phương thức cũng có thể bị vô hiệu vì bạn đã đưa ra lệnh show (); ngay trước khi trở lại sân khấu; Làm thế nào để bạn lập kế hoạch sử dụng bằng cách trở lại Giai đoạn

Đây là một giải pháp chức năng cho một vấn đề. Một giai đoạn được trả về từ showCustomerDialoghàm để tham chiếu đến nó có thể được lưu trữ bởi một lớp bên ngoài có thể muốn làm gì đó, chẳng hạn như ẩn giai đoạn dựa trên một lần bấm nút trong cửa sổ chính, sau đó. Một giải pháp thay thế, hướng đối tượng có thể gói gọn chức năng và tham chiếu giai đoạn bên trong đối tượng CustomerDialog hoặc có Giai đoạn mở rộng CustomerDialog. Một ví dụ đầy đủ cho giao diện hướng đối tượng cho hộp thoại tùy chỉnh đóng gói dữ liệu FXML, bộ điều khiển và mô hình nằm ngoài phạm vi của câu trả lời này, nhưng có thể tạo một bài đăng blog đáng giá cho bất kỳ ai có xu hướng tạo một.


Thông tin bổ sung được cung cấp bởi người dùng StackOverflow có tên @dzim

Ví dụ cho Spring Boot Dependency Injection

Câu hỏi về cách thực hiện "Cách khởi động mùa xuân", đã có một cuộc thảo luận về JavaFX 2, mà tôi đã trả lời trong permalink đính kèm. Cách tiếp cận vẫn còn hiệu lực và được thử nghiệm vào tháng 3 năm 2016, trên Spring Boot v1.3.3.RELEASE: https://stackoverflow.com/a/36310391/1281217


Đôi khi, bạn có thể muốn chuyển kết quả lại cho người gọi, trong trường hợp đó bạn có thể kiểm tra câu trả lời cho câu hỏi liên quan:


Các nhà xây dựng FXMLLoader chỉ lấy URL làm tham số .. cách chính xác để khởi tạo FXMLLoader là gì?
Alvaro

1
trang web xe buýt sự kiện đã ám chỉ các tiểu bang, "Cập nhật 3/2013: EventBus đã cũ ..."
j sẽ

1
Các Khung điều khiển DataFX cung cấp một số hỗ trợ tiêm cho các bộ điều khiển FXML
Hendrik Ebbers

2
Đã thêm phần Hỏi & Đáp bổ sung để trả lời để giải quyết các câu hỏi tiếp theo của @Anarkie
jewnes

7
Đối với Godshake, có gì đơn giản để thực hiện công việc nhỏ bé này trong JavaFx không? một tính năng rất phổ biến để truyền dữ liệu trong hàm tạo và javafx yêu cầu tất cả mọi thứ cùng nhau chỉ để gửi một tên hoặc một giá trị?
Zahan Safallwa

13

Tôi nhận ra đây là một bài viết rất cũ và đã có một số câu trả lời tuyệt vời, nhưng tôi muốn thực hiện một MCVE đơn giản để trình bày một cách tiếp cận như vậy và cho phép các lập trình viên mới một cách nhanh chóng nhìn thấy khái niệm này trong hành động.

Trong ví dụ này, chúng tôi sẽ sử dụng 5 tệp:

  1. Main.java - Được sử dụng đơn giản để khởi động ứng dụng và gọi bộ điều khiển đầu tiên.
  2. Controller1.java - Bộ điều khiển cho bố cục FXML đầu tiên.
  3. Controller2.java - Bộ điều khiển cho bố cục FXML thứ hai.
  4. Layout1.fxml - Bố cục FXML cho cảnh đầu tiên.
  5. Layout2.fxml - Bố cục FXML cho cảnh thứ hai.

Tất cả các tập tin được liệt kê toàn bộ ở dưới cùng của bài viết này.

Mục tiêu: Để chứng minh việc chuyển các giá trị từ Controller1đến Controller2và ngược lại.

Luồng chương trình:

  • Cảnh đầu tiên chứa a TextField, a Buttonvà a Label. Khi Buttonnhấp vào, cửa sổ thứ hai được tải và hiển thị, bao gồm cả văn bản được nhập vào TextField.
  • Trong cảnh thứ hai, cũng có a TextField, a Buttonvà a Label. Các Labelsẽ hiển thị văn bản nhập vào TextFieldtrên sân khấu đầu tiên.
  • Khi nhập văn bản vào cảnh thứ hai TextFieldvà nhấp vào văn bản, cảnh thứ Buttonnhất Labelđược cập nhật để hiển thị văn bản đã nhập.

Đây là một minh chứng rất đơn giản và chắc chắn có thể đại diện cho một số cải tiến, nhưng sẽ làm cho khái niệm này rất rõ ràng.

Bản thân mã cũng được bình luận với một số chi tiết về những gì đang xảy ra và làm thế nào.

MẬT MÃ

Main.java:

import javafx.application.Application;
import javafx.stage.Stage;

public class Main extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        // Create the first controller, which loads Layout1.fxml within its own constructor
        Controller1 controller1 = new Controller1();

        // Show the new stage
        controller1.showStage();

    }
}

Trình điều khiển1.java:

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.io.IOException;

public class Controller1 {

    // Holds this controller's Stage
    private final Stage thisStage;

    // Define the nodes from the Layout1.fxml file. This allows them to be referenced within the controller
    @FXML
    private TextField txtToSecondController;
    @FXML
    private Button btnOpenLayout2;
    @FXML
    private Label lblFromController2;

    public Controller1() {

        // Create the new stage
        thisStage = new Stage();

        // Load the FXML file
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout1.fxml"));

            // Set this class as the controller
            loader.setController(this);

            // Load the scene
            thisStage.setScene(new Scene(loader.load()));

            // Setup the window/stage
            thisStage.setTitle("Passing Controllers Example - Layout1");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Show the stage that was loaded in the constructor
     */
    public void showStage() {
        thisStage.showAndWait();
    }

    /**
     * The initialize() method allows you set setup your scene, adding actions, configuring nodes, etc.
     */
    @FXML
    private void initialize() {

        // Add an action for the "Open Layout2" button
        btnOpenLayout2.setOnAction(event -> openLayout2());
    }

    /**
     * Performs the action of loading and showing Layout2
     */
    private void openLayout2() {

        // Create the second controller, which loads its own FXML file. We pass a reference to this controller
        // using the keyword [this]; that allows the second controller to access the methods contained in here.
        Controller2 controller2 = new Controller2(this);

        // Show the new stage/window
        controller2.showStage();

    }

    /**
     * Returns the text entered into txtToSecondController. This allows other controllers/classes to view that data.
     */
    public String getEnteredText() {
        return txtToSecondController.getText();
    }

    /**
     * Allows other controllers to set the text of this layout's Label
     */
    public void setTextFromController2(String text) {
        lblFromController2.setText(text);
    }
}

Trình điều khiển2.java:

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.io.IOException;

public class Controller2 {

    // Holds this controller's Stage
    private Stage thisStage;

    // Will hold a reference to the first controller, allowing us to access the methods found there.
    private final Controller1 controller1;

    // Add references to the controls in Layout2.fxml
    @FXML
    private Label lblFromController1;
    @FXML
    private TextField txtToFirstController;
    @FXML
    private Button btnSetLayout1Text;

    public Controller2(Controller1 controller1) {
        // We received the first controller, now let's make it usable throughout this controller.
        this.controller1 = controller1;

        // Create the new stage
        thisStage = new Stage();

        // Load the FXML file
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout2.fxml"));

            // Set this class as the controller
            loader.setController(this);

            // Load the scene
            thisStage.setScene(new Scene(loader.load()));

            // Setup the window/stage
            thisStage.setTitle("Passing Controllers Example - Layout2");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Show the stage that was loaded in the constructor
     */
    public void showStage() {
        thisStage.showAndWait();
    }

    @FXML
    private void initialize() {

        // Set the label to whatever the text entered on Layout1 is
        lblFromController1.setText(controller1.getEnteredText());

        // Set the action for the button
        btnSetLayout1Text.setOnAction(event -> setTextOnLayout1());
    }

    /**
     * Calls the "setTextFromController2()" method on the first controller to update its Label
     */
    private void setTextOnLayout1() {
        controller1.setTextFromController2(txtToFirstController.getText());
    }

}

Giao diện1.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <VBox alignment="CENTER" spacing="10.0">
        <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
        </padding>
        <Label style="-fx-font-weight: bold;" text="This is Layout1!"/>
        <HBox alignment="CENTER_LEFT" spacing="10.0">
            <Label text="Enter Text:"/>
            <TextField fx:id="txtToSecondController"/>
            <Button fx:id="btnOpenLayout2" mnemonicParsing="false" text="Open Layout2"/>
        </HBox>
        <VBox alignment="CENTER">
            <Label text="Text From Controller2:"/>
            <Label fx:id="lblFromController2" text="Nothing Yet!"/>
        </VBox>
    </VBox>
</AnchorPane>

Giao diện2.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <VBox alignment="CENTER" spacing="10.0">
        <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
        </padding>
        <Label style="-fx-font-weight: bold;" text="Welcome to Layout 2!"/>
        <VBox alignment="CENTER">
            <Label text="Text From Controller1:"/>
            <Label fx:id="lblFromController1" text="Nothing Yet!"/>
        </VBox>
        <HBox alignment="CENTER_LEFT" spacing="10.0">
            <Label text="Enter Text:"/>
            <TextField fx:id="txtToFirstController"/>
            <Button fx:id="btnSetLayout1Text" mnemonicParsing="false" text="Set Text on Layout1"/>
        </HBox>
    </VBox>
</AnchorPane>

1
Có thể đặt bộ điều khiển trong tệp FXML không? Beause xóa dòng: loader.setController(this)và thêm bộ điều khiển trong tệp FXML làm hỏng ứng dụng
Halfacht

1
Không phải nếu FXML được tải từ bên trong bộ điều khiển. Ví dụ: nếu bạn tải FXML từ lớp Chính, bạn có thể xác định bộ điều khiển trong tệp FXML và lấy tham chiếu đến nó bằng cách sử dụngloader.getController()
Zephyr

Cuối cùng tôi cũng tìm được một giải pháp, một ví dụ tuyệt vời. Tôi đã triển khai nó vào dự án của mình và bây giờ tôi đang cố gắng làm cho cả hai cửa sổ mở đồng thời và biến chúng thành phương thức đầu tiên. Thật không may, chỉ có một mở. Bất cứ ai có thể giúp đỡ với nó?
jabba

8

Lớp javafx.scene.Node có một cặp phương thức setUserData (Object) và Object getUserData ()

Mà bạn có thể sử dụng để thêm thông tin của bạn vào Nút.

Vì vậy, bạn có thể gọi page.setUserData (thông tin);

Và bộ điều khiển có thể kiểm tra, nếu thông tin được thiết lập. Ngoài ra, bạn có thể sử dụng ObjectProperty để truyền dữ liệu ngược, nếu cần.

Quan sát một tài liệu ở đây: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/int sinhtion_to_fxml.html Trước cụm từ "Trong phiên bản đầu tiên, tay cầmButtonAction () được gắn thẻ @FXML để cho phép đánh dấu được xác định trong tài liệu của bộ điều khiển để gọi nó. Trong ví dụ thứ hai, trường nút được chú thích để cho phép trình nạp đặt giá trị của nó. Phương thức khởi tạo () cũng được chú thích tương tự. "

Vì vậy, bạn cần liên kết bộ điều khiển với một nút và đặt dữ liệu người dùng thành nút.


Stage.getScene () -> Scene.getRoot () -> tìm kiếm đệ quy với Parent.getChildrenUnmodifiable (). Đây là cách rất bẩn. Nếu ai đó có thể đề nghị smth tốt hơn - đó sẽ là tuyệt vời.
Alexander Kirov

Có vẻ như Stage.getScene (). GetRoot () là cách chính xác! Cảm ơn
Alvaro

7

Dưới đây là một ví dụ để truyền tham số cho tài liệu fxml thông qua không gian tên.

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/null" xmlns:fx="http://javafx.com/fxml/1">
    <BorderPane>
        <center>
            <Label text="$labelText"/>
        </center>
    </BorderPane>
</VBox>

Xác định giá trị External Textcho biến không gian tên labelText:

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

import java.io.IOException;

public class NamespaceParameterExampleApplication extends Application {

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

    @Override
    public void start(Stage primaryStage) throws IOException {
        final FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("namespace-parameter-example.fxml"));

        fxmlLoader.getNamespace()
                  .put("labelText", "External Text");

        final Parent root = fxmlLoader.load();

        primaryStage.setTitle("Namespace Parameter Example");
        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }
}

Cần lưu ý rằng một số các phím được sử dụng trong nội bộ: ví dụ FXMLLoader.CONTROLLER_KEYWORD, FXMLLoader.LOCATION_KEY, FXMLLoader.RESOURCES_KEYvà bất kỳ chuỗi được sử dụng như giá trị cho các fx:idthuộc tính.
fabian

Cảm ơn vì điều này, cảnh khác của tôi chỉ là một thùng chứa hiển thị văn bản được hiển thị trước đó trên cảnh chính của tôi. Bây giờ tôi có thể có một fxml mà tôi có thể sử dụng lại ở nhiều nơi bằng cách khởi tạo nội dung thông qua các biến Namepace. Tôi đã không phải tạo bất kỳ phương thức mới nào hoặc thay đổi hàm tạo hoặc initalisers của mình - chỉ cần thêm biến trong FXML của tôi và thêm một dòng vào mã fxmloader của tôi trong bộ điều khiển chính.
SystemsInCode

4

Những công việc này ..

Hãy nhớ lần đầu tiên bạn in giá trị chuyển bạn sẽ nhận được null, Bạn có thể sử dụng nó sau khi các cửa sổ của bạn được tải, tương tự cho mọi thứ bạn muốn mã cho bất kỳ thành phần nào khác.

Bộ điều khiển đầu tiên

try {
    Stage st = new Stage();
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/inty360/free/form/MainOnline.fxml"));

    Parent sceneMain = loader.load();

    MainOnlineController controller = loader.<MainOnlineController>getController();
    controller.initVariable(99L);

    Scene scene = new Scene(sceneMain);
    st.setScene(scene);
    st.setMaximized(true);
    st.setTitle("My App");
    st.show();
} catch (IOException ex) {
    Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, null, ex);
}

Bộ điều khiển khác

public void initVariable(Long id_usuario){
    this.id_usuario = id_usuario;
    label_usuario_nombre.setText(id_usuario.toString());
}

1
Điều này hoạt động khi bạn chuyển tham số từ bộ điều khiển thứ nhất sang bộ điều khiển thứ hai nhưng làm thế nào để chuyển tham số từ bộ điều khiển thứ hai sang bộ điều khiển thứ nhất, ý tôi là sau khi First.fxml được tải.
Menai Ala Eddine - Aladdin

@XlintXms xem câu hỏi liên quan JavaFX FXML Tham số truyền từ Bộ điều khiển A đến B và trở lại , giải quyết câu hỏi bổ sung của bạn.
jewnes

2

Bạn phải tạo một Lớp ngữ cảnh.

public class Context {
    private final static Context instance = new Context();
    public static Context getInstance() {
        return instance;
    }

    private Connection con;
    public void setConnection(Connection con)
    {
        this.con=con;
    }
    public Connection getConnection() {
        return con;
    }

    private TabRoughController tabRough;
    public void setTabRough(TabRoughController tabRough) {
        this.tabRough=tabRough;
    }

    public TabRoughController getTabRough() {
        return tabRough;
    }
}

Bạn phải đặt phiên bản của trình điều khiển khi khởi tạo bằng

Context.getInstance().setTabRough(this);

và bạn có thể sử dụng nó từ toàn bộ ứng dụng của mình chỉ bằng cách sử dụng

TabRoughController cont=Context.getInstance().getTabRough();

Bây giờ bạn có thể truyền tham số cho bất kỳ bộ điều khiển nào từ toàn bộ ứng dụng.


Chúng tôi sử dụng phương pháp này và nó hoạt động tuyệt vời. Tôi thích rằng tôi có quyền truy cập vào dữ liệu bên trong hàm tạo hoặc trong phương thức khởi tạo và tôi không phải đặt dữ liệu trong bộ điều khiển sau khi được xây dựng
Bob

1

Có bạn có thể.
Bạn cần thêm vào bộ điều khiển đầu tiên:

YourController controller = loader.getController();     
controller.setclient(client);

Sau đó, trong cái thứ hai khai báo một máy khách, sau đó ở dưới cùng của bộ điều khiển của bạn:

public void setclien(Client c) {
    this.client = c;
}

0

Dưới đây là một ví dụ cho việc sử dụng bộ điều khiển được tiêm bởi Guice.

/**
 * Loads a FXML file and injects its controller from the given Guice {@code Provider}
 */
public abstract class GuiceFxmlLoader {

   public GuiceFxmlLoader(Stage stage, Provider<?> provider) {
      mStage = Objects.requireNonNull(stage);
      mProvider = Objects.requireNonNull(provider);
   }

   /**
    * @return the FXML file name
    */
   public abstract String getFileName();

   /**
    * Load FXML, set its controller with given {@code Provider}, and add it to {@code Stage}.
    */
   public void loadView() {
      try {
         FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource(getFileName()));
         loader.setControllerFactory(p -> mProvider.get());
         Node view = loader.load();
         setViewInStage(view);
      }
      catch (IOException ex) {
         LOGGER.error("Failed to load FXML: " + getFileName(), ex);
      }
   }

   private void setViewInStage(Node view) {
      BorderPane pane = (BorderPane)mStage.getScene().getRoot();
      pane.setCenter(view);
   }

   private static final Logger LOGGER = Logger.getLogger(GuiceFxmlLoader.class);

   private final Stage mStage;
   private final Provider<?> mProvider;
}

Dưới đây là một triển khai cụ thể của trình nạp:

public class ConcreteViewLoader extends GuiceFxmlLoader {

   @Inject
   public ConcreteViewLoader(Stage stage, Provider<MyController> provider) {
      super(stage, provider);
   }

   @Override
   public String getFileName() {
      return "my_view.fxml";
   }
}

Lưu ý ví dụ này tải chế độ xem vào trung tâm của BoarderPane là gốc của Cảnh trong Giai đoạn. Điều này không liên quan đến ví dụ (chi tiết triển khai trường hợp sử dụng cụ thể của tôi) nhưng đã quyết định để lại vì một số có thể thấy nó hữu ích.


-1

Bạn có thể quyết định sử dụng danh sách có thể quan sát công khai để lưu trữ dữ liệu công khai hoặc chỉ cần tạo phương thức setter công khai để lưu trữ dữ liệu và truy xuất từ ​​bộ điều khiển tương ứng


-3

Tại sao trả lời một câu hỏi 6 tuổi?
Một trong những khái niệm cơ bản nhất làm việc với bất kỳ ngôn ngữ lập trình nào là làm thế nào để điều hướng từ một (cửa sổ, biểu mẫu hoặc trang) sang một ngôn ngữ khác. Ngoài ra, trong khi thực hiện điều hướng này, nhà phát triển thường muốn truyền dữ liệu từ một (cửa sổ, biểu mẫu hoặc trang) và hiển thị hoặc sử dụng dữ liệu được truyền trong
khi hầu hết các câu trả lời ở đây cung cấp các ví dụ hay cho cách thực hiện điều này, chúng tôi nghĩ rằng chúng tôi sẽ khởi động nó Một hoặc hai hoặc ba
Chúng tôi đã nói ba vì chúng tôi sẽ điều hướng giữa ba (cửa sổ, biểu mẫu hoặc trang) và sử dụng khái niệm biến tĩnh để truyền dữ liệu xung quanh (cửa sổ, biểu mẫu hoặc trang)
Chúng tôi cũng sẽ bao gồm một số mã ra quyết định trong khi chúng tôi điều hướng

public class Start extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        // This is MAIN Class which runs first
        Parent root = FXMLLoader.load(getClass().getResource("start.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setResizable(false);// This sets the value for all stages
        stage.setTitle("Start Page"); 
        stage.show();
        stage.sizeToScene();
    }

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

Bộ điều khiển khởi động

public class startController implements Initializable {

@FXML Pane startPane,pageonePane;
@FXML Button btnPageOne;
@FXML TextField txtStartValue;
public Stage stage;
public static int intSETonStartController;
String strSETonStartController;

@FXML
private void toPageOne() throws IOException{

    strSETonStartController = txtStartValue.getText().trim();


        // yourString != null && yourString.trim().length() > 0
        // int L = testText.length();
        // if(L == 0){
        // System.out.println("LENGTH IS "+L);
        // return;
        // }
        /* if (testText.matches("[1-2]") && !testText.matches("^\\s*$")) 
           Second Match is regex for White Space NOT TESTED !
        */

        String testText = txtStartValue.getText().trim();
        // NOTICE IF YOU REMOVE THE * CHARACTER FROM "[1-2]*"
        // NO NEED TO CHECK LENGTH it also permited 12 or 11 as valid entry 
        // =================================================================
        if (testText.matches("[1-2]")) {
            intSETonStartController = Integer.parseInt(strSETonStartController);
        }else{
            txtStartValue.setText("Enter 1 OR 2");
            return;
        }

        System.out.println("You Entered = "+intSETonStartController);
        stage = (Stage)startPane.getScene().getWindow();// pane you are ON
        pageonePane = FXMLLoader.load(getClass().getResource("pageone.fxml"));// pane you are GOING TO
        Scene scene = new Scene(pageonePane);// pane you are GOING TO
        stage.setScene(scene);
        stage.setTitle("Page One"); 
        stage.show();
        stage.sizeToScene();
        stage.centerOnScreen();  
}

private void doGET(){
    // Why this testing ?
    // strSENTbackFROMPageoneController is null because it is set on Pageone
    // =====================================================================
    txtStartValue.setText(strSENTbackFROMPageoneController);
    if(intSETonStartController == 1){
      txtStartValue.setText(str);  
    }
    System.out.println("== doGET WAS RUN ==");
    if(txtStartValue.getText() == null){
       txtStartValue.setText("");   
    }
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    // This Method runs every time startController is LOADED
     doGET();
}    
}

Bộ điều khiển Trang Một

public class PageoneController implements Initializable {

@FXML Pane startPane,pageonePane,pagetwoPane;
@FXML Button btnOne,btnTwo;
@FXML TextField txtPageOneValue;
public static String strSENTbackFROMPageoneController;
public Stage stage;

    @FXML
private void onBTNONE() throws IOException{

        stage = (Stage)pageonePane.getScene().getWindow();// pane you are ON
        pagetwoPane = FXMLLoader.load(getClass().getResource("pagetwo.fxml"));// pane you are GOING TO
        Scene scene = new Scene(pagetwoPane);// pane you are GOING TO
        stage.setScene(scene);
        stage.setTitle("Page Two"); 
        stage.show();
        stage.sizeToScene();
        stage.centerOnScreen();
}

@FXML
private void onBTNTWO() throws IOException{
    if(intSETonStartController == 2){
        Alert alert = new Alert(AlertType.CONFIRMATION);
        alert.setTitle("Alert");
        alert.setHeaderText("YES to change Text Sent Back");
        alert.setResizable(false);
        alert.setContentText("Select YES to send 'Alert YES Pressed' Text Back\n"
                + "\nSelect CANCEL send no Text Back\r");// NOTE this is a Carriage return\r
        ButtonType buttonTypeYes = new ButtonType("YES");
        ButtonType buttonTypeCancel = new ButtonType("CANCEL", ButtonData.CANCEL_CLOSE);

        alert.getButtonTypes().setAll(buttonTypeYes, buttonTypeCancel);

        Optional<ButtonType> result = alert.showAndWait();
        if (result.get() == buttonTypeYes){
            txtPageOneValue.setText("Alert YES Pressed");
        } else {
            System.out.println("canceled");
            txtPageOneValue.setText("");
            onBack();// Optional
        }
    }
}

@FXML
private void onBack() throws IOException{

    strSENTbackFROMPageoneController = txtPageOneValue.getText();
    System.out.println("Text Returned = "+strSENTbackFROMPageoneController);
    stage = (Stage)pageonePane.getScene().getWindow();
    startPane = FXMLLoader.load(getClass().getResource("start.fxml")); 
    Scene scene = new Scene(startPane);
    stage.setScene(scene);
    stage.setTitle("Start Page"); 
    stage.show();
    stage.sizeToScene();
    stage.centerOnScreen(); 
}

private void doTEST(){
    String fromSTART = String.valueOf(intSETonStartController);
    txtPageOneValue.setText("SENT  "+fromSTART);
    if(intSETonStartController == 1){
       btnOne.setVisible(true);
       btnTwo.setVisible(false);
       System.out.println("INTEGER Value Entered = "+intSETonStartController);  
    }else{
       btnOne.setVisible(false);
       btnTwo.setVisible(true);
       System.out.println("INTEGER Value Entered = "+intSETonStartController); 
    }  
}

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

}

Trang Hai Bộ điều khiển

public class PagetwoController implements Initializable {

@FXML Pane startPane,pagetwoPane;
public Stage stage;
public static String str;

@FXML
private void toStart() throws IOException{

    str = "You ON Page Two";
    stage = (Stage)pagetwoPane.getScene().getWindow();// pane you are ON
    startPane = FXMLLoader.load(getClass().getResource("start.fxml"));// pane you are GOING TO
    Scene scene = new Scene(startPane);// pane you are GOING TO
    stage.setScene(scene);
    stage.setTitle("Start Page"); 
    stage.show();
    stage.sizeToScene();
    stage.centerOnScreen();  
}

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

}    

}

Dưới đây là tất cả các tệp FXML

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" fx:id="pagetwoPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="atwopage.PagetwoController">
   <children>
      <Button layoutX="227.0" layoutY="62.0" mnemonicParsing="false" onAction="#toStart" text="To Start Page">
         <font>
            <Font name="System Bold" size="18.0" />
         </font>
      </Button>
   </children>
</AnchorPane>

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" fx:id="startPane" prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="atwopage.startController">
   <children>
      <Label focusTraversable="false" layoutX="115.0" layoutY="47.0" text="This is the Start Pane">
         <font>
            <Font size="18.0" />
         </font>
      </Label>
      <Button fx:id="btnPageOne" focusTraversable="false" layoutX="137.0" layoutY="100.0" mnemonicParsing="false" onAction="#toPageOne" text="To Page One">
         <font>
            <Font size="18.0" />
         </font>
      </Button>
      <Label focusTraversable="false" layoutX="26.0" layoutY="150.0" text="Enter 1 OR 2">
         <font>
            <Font size="18.0" />
         </font>
      </Label>
      <TextField fx:id="txtStartValue" layoutX="137.0" layoutY="148.0" prefHeight="28.0" prefWidth="150.0" />
   </children>
</AnchorPane>

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" fx:id="pageonePane" prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="atwopage.PageoneController">
   <children>
      <Label focusTraversable="false" layoutX="111.0" layoutY="35.0" text="This is Page One Pane">
         <font>
            <Font size="18.0" />
         </font>
      </Label>
      <Button focusTraversable="false" layoutX="167.0" layoutY="97.0" mnemonicParsing="false" onAction="#onBack" text="BACK">
         <font>
            <Font size="18.0" />
         </font></Button>
      <Button fx:id="btnOne" focusTraversable="false" layoutX="19.0" layoutY="97.0" mnemonicParsing="false" onAction="#onBTNONE" text="Button One" visible="false">
         <font>
            <Font size="18.0" />
         </font>
      </Button>
      <Button fx:id="btnTwo" focusTraversable="false" layoutX="267.0" layoutY="97.0" mnemonicParsing="false" onAction="#onBTNTWO" text="Button Two">
         <font>
            <Font size="18.0" />
         </font>
      </Button>
      <Label focusTraversable="false" layoutX="19.0" layoutY="152.0" text="Send Anything BACK">
         <font>
            <Font size="18.0" />
         </font>
      </Label>
      <TextField fx:id="txtPageOneValue" layoutX="195.0" layoutY="150.0" prefHeight="28.0" prefWidth="150.0" />
   </children>
</AnchorPane>


3
Tôi xin lỗi, nhưng đăng một trăm dòng mã mà không có bất kỳ lời giải thích nào về những gì nó làm hoặc tại sao bạn làm theo cách bạn làm, không phải là một câu trả lời rất tốt. Thêm vào đó, mã bạn đã đăng rất kém tổ chức và khó theo dõi.
Zephyr

Không cần phải thô lỗ với người hỏi. Tất cả chúng ta đều ở đây để học hỏi
Zeyad
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.