Melewati Parameter JavaFX FXML


194

Bagaimana saya bisa meneruskan parameter ke jendela sekunder di javafx? Apakah ada cara untuk berkomunikasi dengan pengontrol yang sesuai?

Misalnya: Pengguna memilih pelanggan dari TableViewdan jendela baru dibuka, menampilkan info pelanggan.

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

newStageakan menjadi jendela baru. Masalahnya adalah, saya tidak bisa menemukan cara untuk memberitahu controller di mana mencari info pelanggan (dengan melewatkan id sebagai parameter).

Ada ide?


Periksa untuk melihat apakah ini bekerja juga: stackoverflow.com/questions/14370183/…
Dynelight

@Alvaro: apakah Anda mendapatkan solusi? dapatkah kamu memberikan parameter? dari satu pengontrol ke file pengontrol lain?
Java Man

3
Iya. jewelsea memberi penjelasan setingkat buku. Itu sebabnya saya menerima jawabannya
Alvaro

Jawaban:


276

Pendekatan yang Disarankan

Jawaban ini menyebutkan mekanisme berbeda untuk memberikan parameter ke pengontrol FXML.

Untuk aplikasi kecil, saya sangat merekomendasikan melewati parameter langsung dari pemanggil ke controller - itu sederhana, mudah dan tidak memerlukan kerangka kerja tambahan.

Untuk aplikasi yang lebih besar dan lebih rumit, ada baiknya menyelidiki jika Anda ingin menggunakan Dependency Injection atau Event Bus mekanisme dalam aplikasi Anda.

Melewati Parameter Langsung Dari Pemanggil ke Pengontrol

Berikan data khusus ke pengontrol FXML dengan mengambil pengontrol dari instance loader FXML dan memanggil metode pada pengontrol untuk menginisialisasi dengan nilai data yang diperlukan.

Sesuatu seperti kode berikut:

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

FXMLLoader baru dibuat seperti yang ditunjukkan dalam contoh kode yaitu new FXMLLoader(location). Lokasi adalah URL dan Anda dapat menghasilkan URL seperti itu dari sumber daya FXML dengan:

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

Berhati-hatilah JANGAN menggunakan fungsi beban statis pada FXMLLoader, atau Anda tidak akan bisa mendapatkan controller dari instance loader Anda.

Instance FXMLLoader sendiri tidak pernah tahu apa-apa tentang objek domain. Anda tidak secara langsung mengirimkan objek domain khusus aplikasi ke konstruktor FXMLLoader, sebagai gantinya Anda:

  1. Bangun FXMLLoader berdasarkan marka fxml di lokasi yang ditentukan
  2. Dapatkan pengontrol dari instance FXMLLoader.
  3. Aktifkan metode pada pengontrol yang diambil untuk memberikan pengontrol dengan referensi ke objek domain.

Blog ini (oleh penulis lain) memberikan alternatif, tetapi serupa, contoh .

Mengatur Pengontrol pada FXMLLoader

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

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

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

Anda dapat membuat pengontrol baru dalam kode, meneruskan parameter apa pun yang Anda inginkan dari pemanggil ke konstruktor pengontrol. Setelah Anda membuat kontroler, Anda bisa mengaturnya pada instance FXMLLoader sebelum Anda memanggil metode load() instance .

Untuk mengatur pengontrol pada loader (dalam JavaFX 2.x) Anda TIDAK BISA juga mendefinisikan fx:controlleratribut dalam file fxml Anda.

Karena batasan pada fx:controller definisi dalam FXML, saya pribadi lebih suka mendapatkan pengontrol dari FXMLLoader daripada mengatur pengontrol ke dalam FXMLLoader.

Memiliki Pengendali Mengambil Parameter dari Metode Statis Eksternal

Metode ini dicontohkan oleh jawaban Sergey untuk Javafx 2.0 How-to Application.getParameters () dalam file Controller.java .

Gunakan Injeksi Ketergantungan

FXMLLoader mendukung sistem injeksi ketergantungan seperti Guice, Spring atau Java EE CDI dengan memungkinkan Anda untuk mengatur pabrik pengontrol khusus di FXMLLoader. Ini memberikan panggilan balik yang dapat Anda gunakan untuk membuat instance controller dengan nilai-nilai dependen yang diinjeksi oleh sistem injeksi dependensi masing-masing.

Contoh aplikasi JavaFX dan injeksi ketergantungan pengontrol dengan Spring disediakan dalam jawaban untuk:

Suatu pendekatan injeksi ketergantungan yang benar-benar baik dan bersih dicontohkan oleh kerangka kerja afterburner.fx dengan contoh aplikasi air-hacks yang menggunakannya. afterburner.fx bergantung pada JEE6 javax.inject untuk melakukan injeksi ketergantungan.

Gunakan Bus Acara

Greg Brown, pembuat dan implementasi spesifikasi FXML asli, sering menyarankan untuk mempertimbangkan penggunaan bus peristiwa, seperti Guava EventBus , untuk komunikasi antara pengontrol instantiated FXML dan logika aplikasi lainnya.

EventBus adalah sederhana, tetapi kuat menerbitkan / berlangganan API dengan anotasi yang memungkinkan POJO untuk berkomunikasi satu sama lain di mana pun dalam JVM tanpa harus merujuk satu sama lain.

T&J tindak lanjut

pada metode pertama, mengapa Anda mengembalikan Stage? Metode ini dapat dibatalkan juga karena Anda sudah memberikan perintah show (); sebelum kembali panggung ;. Bagaimana Anda merencanakan penggunaan dengan mengembalikan Stage

Ini adalah solusi fungsional untuk suatu masalah. Tahap dikembalikan dari showCustomerDialogfungsi sehingga referensi ke sana dapat disimpan oleh kelas eksternal yang mungkin ingin melakukan sesuatu, seperti menyembunyikan panggung berdasarkan klik tombol di jendela utama, di lain waktu. Alternatif, solusi berorientasi objek dapat merangkum fungsionalitas dan referensi tahap di dalam objek CustomerDialog atau memiliki Tahap memperpanjang CustomerDialog. Contoh lengkap untuk antarmuka berorientasi objek ke dialog khusus yang merangkum FXML, pengontrol, dan data model berada di luar cakupan jawaban ini, tetapi dapat membuat posting blog yang bermanfaat bagi siapa pun yang cenderung membuatnya.


Informasi tambahan disediakan oleh pengguna StackOverflow bernama @dzim

Contoh untuk Injeksi Ketergantungan Boot Musim Semi

Pertanyaan tentang bagaimana melakukannya "The Spring Boot Way", ada diskusi tentang JavaFX 2, yang saya jawab di permalink terlampir. Pendekatan ini masih valid dan diuji pada Maret 2016, pada Spring Boot v1.3.3.RELEASE: https://stackoverflow.com/a/36310391/1281217


Kadang-kadang, Anda mungkin ingin meneruskan hasil kembali ke pemanggil, dalam hal ini Anda dapat memeriksa jawaban untuk pertanyaan terkait:


Konstruktor FXMLLoader hanya mengambil URL sebagai parameter .. apa cara yang benar untuk membuat Instanate FXMLLoader?
Alvaro

1
situs web bus acara disinggung menyatakan, "Pembaruan 3/2013: EventBus telah basi ..."
j akan

1
Kerangka Pengontrol DataFX menyediakan beberapa dukungan injeksi untuk pengontrol FXML
Hendrik Ebbers

2
Menambahkan bagian tanya jawab tambahan untuk menjawab pertanyaan selanjutnya dari @Anarkie
jewelsea

7
untuk godshake adakah yang sederhana untuk melakukan pekerjaan kecil ini di JavaFx? itu fitur yang sangat umum untuk melewatkan data dalam konstruktor dan javafx membutuhkan semua ini bersama-sama hanya untuk mengirim satu nama atau satu nilai?
Zahan Safallwa

13

Saya menyadari ini adalah posting yang sangat lama dan sudah memiliki beberapa jawaban yang hebat, tetapi saya ingin membuat MCVE sederhana untuk menunjukkan satu pendekatan seperti itu dan memungkinkan coders baru cara untuk cepat melihat konsep dalam tindakan.

Dalam contoh ini, kita akan menggunakan 5 file:

  1. Main.java - Cukup digunakan untuk memulai aplikasi dan memanggil pengontrol pertama.
  2. Controller1.java - Pengontrol untuk tata letak FXML pertama.
  3. Controller2.java - Pengontrol untuk tata letak FXML kedua.
  4. Layout1.fxml - Layout FXML untuk adegan pertama.
  5. Layout2.fxml - Layout FXML untuk adegan kedua.

Semua file tercantum secara keseluruhan di bagian bawah posting ini.

Tujuan: Untuk mendemonstrasikan nilai passing dariController1 ke Controller2dan sebaliknya.

Alur Program:

  • Adegan pertama berisi a TextField, a Button, dan a Label. KetikaButton diklik, jendela kedua dimuat dan ditampilkan, termasuk teks yang dimasukkan dalam TextField.
  • Dalam adegan kedua, ada juga a TextField, a Button, dan a Label. ItuLabel akan menampilkan teks yang dimasukkan dalam TextFieldpada adegan pertama.
  • Setelah memasukkan teks di adegan kedua TextFielddan mengklik nya Button, adegan pertamaLabel diperbarui untuk menampilkan teks yang dimasukkan.

Ini adalah demonstrasi yang sangat sederhana dan pasti bisa berdiri untuk perbaikan, tetapi harus membuat konsepnya sangat jelas.

Kode itu sendiri juga dikomentari dengan beberapa perincian tentang apa yang terjadi dan bagaimana caranya.

KODE

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

    }
}

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

Controller2.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());
    }

}

Layout1.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>

Layout2.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
Apakah mungkin untuk mengatur pengontrol di file FXML? Karena menghapus garis: loader.setController(this)dan menambahkan pengontrol dalam file FXML membuat crash aplikasi
Halfacht

1
Tidak jika FXML diambil dari dalam controller itu sendiri. Jika Anda memuat FXML dari kelas Utama, misalnya, Anda dapat mendefinisikan pengontrol di file FXML dan mendapatkan referensi untuk itu menggunakanloader.getController()
Zephyr

Akhirnya saya berhasil menemukan solusi, contoh yang bagus. Saya menerapkannya ke dalam proyek saya dan sekarang saya mencoba untuk membuat kedua jendela terbuka secara bersamaan dan menjadikannya modal pertama. Sayangnya hanya satu yang terbuka. Adakah yang bisa membantu?
Jabba

8

javafx.scene.Node class memiliki sepasang metode setUserData (Object) dan Object getUserData ()

Yang bisa Anda gunakan untuk menambahkan info Anda ke Node.

Jadi, Anda dapat memanggil page.setUserData (info);

Dan controller dapat memeriksa, jika info diatur. Selain itu, Anda bisa menggunakan ObjectProperty untuk mentransfer data, jika diperlukan.

Amati dokumentasi di sini: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Sebelum frasa "Dalam versi pertama, handleButtonAction () ditandai dengan @FXML untuk memungkinkan markup yang ditentukan dalam dokumen pengontrol untuk memintanya. Pada contoh kedua, bidang tombol diberi catatan untuk memungkinkan loader menetapkan nilainya. Metode initialize () juga dijelaskan. "

Jadi, Anda harus mengaitkan pengontrol dengan simpul, dan mengatur data pengguna ke simpul tersebut.


Stage.getScene () -> Scene.getRoot () -> pencarian rekursif dengan Parent.getChildrenUnmodifiable (). Ini cara yang sangat kotor. Jika seseorang bisa menyarankan pertolongan yang lebih baik - itu akan bagus.
Alexander Kirov

Tampaknya Stage.getScene (). GetRoot () adalah cara yang benar! Terima kasih
Alvaro

7

Berikut adalah contoh untuk meneruskan parameter ke dokumen fxml melalui namespace.

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

Tentukan nilai External Textuntuk variabel namespace 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();
    }
}

Perlu dicatat bahwa beberapa tombol yang digunakan secara internal: misalnya FXMLLoader.CONTROLLER_KEYWORD, FXMLLoader.LOCATION_KEY, FXMLLoader.RESOURCES_KEYdan setiap string yang digunakan sebagai nilai untuk fx:idatribut.
Fabian

Terima kasih untuk ini, adegan saya yang lain hanyalah sebuah wadah yang menunjukkan teks yang sebelumnya ditampilkan di adegan utama saya. Sekarang saya dapat memiliki satu fxml yang dapat saya gunakan kembali di banyak tempat dengan menginisialisasi konten melalui variabel Namepace. Saya tidak harus membuat metode baru atau mengubah konstruktor atau inisialisasi saya - cukup tambahkan variabel di FXML saya dan tambahkan satu baris ke dalam kode fxmloader saya di pengontrol utama.
SystemsInCode

4

Ini bekerja ..

Ingat pertama kali Anda mencetak nilai kelulusan Anda akan mendapatkan nol, Anda dapat menggunakannya setelah windows Anda dimuat, sama untuk semua yang Anda ingin kode untuk komponen lainnya.

Pengendali Pertama

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

Pengendali lain

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

1
Ini bekerja ketika Anda melewatkan parameter dari controller pertama ke kedua tetapi bagaimana untuk lulus parameter dari controller kedua ke pertama, maksud saya setelah first.fxml dimuat.
Menai Ala Eddine - Aladdin

@XlintXms lihat pertanyaan terkait JavaFX FXML Parameter yang diteruskan dari Controller A ke B dan kembali , yang menjawab pertanyaan tambahan Anda.
jewelsea

2

Anda harus membuat satu Kelas Konteks.

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

Anda hanya perlu mengatur instance controller dalam inisialisasi menggunakan

Context.getInstance().setTabRough(this);

dan Anda dapat menggunakannya dari seluruh aplikasi Anda hanya menggunakan

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

Sekarang Anda dapat melewatkan parameter ke pengontrol apa saja dari seluruh aplikasi.


Kami menggunakan pendekatan ini dan itu bekerja dengan baik. Saya suka bahwa saya memiliki akses ke data di dalam konstruktor atau dalam metode inisialisasi dan saya tidak perlu mengatur data di controller setelah dibangun
Bob

1

Ya kamu bisa.
Anda perlu menambahkan controller pertama:

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

Kemudian di yang kedua mendeklarasikan klien, kemudian di bagian bawah controller Anda:

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

0

Berikut adalah contoh untuk menggunakan pengontrol yang disuntikkan oleh 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;
}

Berikut ini adalah implementasi nyata dari loader:

public class ConcreteViewLoader extends GuiceFxmlLoader {

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

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

Perhatikan contoh ini memuat tampilan ke tengah BoarderPane yang merupakan akar dari Scene di Panggung. Ini tidak relevan dengan contoh (detail implementasi kasus penggunaan khusus saya) tetapi memutuskan untuk membiarkannya karena beberapa mungkin merasa berguna.


-1

Anda dapat memutuskan untuk menggunakan daftar yang dapat diamati publik untuk menyimpan data publik, atau hanya membuat metode setter publik untuk menyimpan data dan mengambil dari pengontrol yang sesuai


-3

Mengapa menjawab pertanyaan 6 tahun?
Salah satu konsep paling mendasar yang bekerja dengan bahasa pemrograman apa pun adalah bagaimana menavigasi dari satu (jendela, formulir atau halaman) ke yang lain. Juga saat melakukan navigasi ini pengembang sering ingin meneruskan data dari satu (jendela, formulir atau halaman) dan menampilkan atau menggunakan data yang dilewati.
Sementara sebagian besar jawaban di sini memberikan contoh yang bagus untuk contoh bagaimana melakukannya, kami pikir kami akan menaikannya torehan atau dua atau tiga
Kami mengatakan tiga karena kami akan menavigasi antara tiga (jendela, formulir atau halaman) dan menggunakan konsep variabel statis untuk meneruskan data di sekitar (jendela, formulir atau halaman)
Kami juga akan memasukkan beberapa kode pengambilan keputusan sementara kami menavigasi

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

Mulai Pengontrol

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

Pengontrol Satu Halaman

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

}

Halaman Dua Pengendali

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) {

}    

}

Di bawah ini adalah semua file 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
Maaf, tetapi memposting ratusan baris kode tanpa penjelasan tentang apa yang dilakukannya atau mengapa Anda melakukannya dengan cara yang Anda lakukan, bukanlah jawaban yang sangat baik. Plus, kode yang Anda posting sangat tidak terorganisir dan sulit untuk diikuti.
Zephyr

Tidak perlu bersikap kasar kepada orang yang bertanya. Kita semua di sini untuk belajar
Zeyad
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.