如何将参数传递给javafx中的辅助窗口?有没有办法与相应的控制器通信?
例如:
用户从TableView
中选择一个客户,并打开一个新窗口,显示客户的信息。
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();
}
}
newStage
将是新窗口。问题是,我找不到告诉控制器在哪里查找客户信息的方法(通过将id作为参数传递)。
有什么想法吗?
答案 0 :(得分:8)
javafx.scene.Node类有一对方法 setUserData来(对象) 和 对象getUserData()
您可以使用它将您的信息添加到节点。
因此,您可以调用page.setUserData(info);
如果设置了信息,控制器可以检查。此外,如果需要,您可以使用ObjectProperty进行后向数据传输。
在此处观察文档: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html 在短语“在第一个版本中,handleButtonAction()被标记为@FXML以允许在控制器文档中定义的标记来调用它。在第二个示例中,按钮字段被注释以允许加载器设置其值。 initialize()方法同样注释。“
因此,您需要将控制器与节点相关联,并将用户数据设置为节点。
答案 1 :(得分:8)
我意识到这是一篇非常古老的文章,并且已经有了一些不错的答案, 但是我想做一个简单的MCVE来演示一种这样的方法,并允许新的编码人员快速查看实际的概念。
在此示例中,我们将使用5个文件:
所有文件均完整列在本文的底部。
目标:演示从Controller1
到Controller2
的传递值,反之亦然。
程序流程:
TextField
,一个Button
和一个Label
。单击Button
时,将加载并显示第二个窗口,包括在TextField
中输入的文本。TextField
,一个Button
和一个Label
。 Label
将在第一个场景中显示在TextField
中输入的文本。TextField
中输入文本并单击其Button
之后,第一个场景的Label
被更新以显示输入的文本。这是一个非常简单的演示,可以肯定会进行一些改进,但是应该使概念非常清楚。
还对代码本身进行了注释,其中包含正在发生的事情以及如何发生的细节。
代码
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>
答案 2 :(得分:7)
以下是通过命名空间将参数传递给fxml文档的示例。
Service
为名称空间变量<?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>
定义值External Text
:
labelText
答案 3 :(得分:2)
这个工作..
请记住,第一次打印传递值时,您将获得null, 您可以在加载Windows后使用它,对于您要为任何其他组件编码的所有内容都是如此。
第一控制器
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);
}
另一个控制器
public void initVariable(Long id_usuario){
this.id_usuario = id_usuario;
label_usuario_nombre.setText(id_usuario.toString());
}
答案 4 :(得分:1)
您必须创建一个上下文类。
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;
}
}
您必须使用
在初始化中设置控制器的实例Context.getInstance().setTabRough(this);
您可以使用
在整个应用程序中使用它TabRoughController cont=Context.getInstance().getTabRough();
现在您可以将参数传递给整个应用程序中的任何控制器。
答案 5 :(得分:0)
以下是使用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;
}
这是加载器的具体实现:
public class ConcreteViewLoader extends GuiceFxmlLoader {
@Inject
public ConcreteViewLoader(Stage stage, Provider<MyController> provider) {
super(stage, provider);
}
@Override
public String getFileName() {
return "my_view.fxml";
}
}
请注意,此示例将视图加载到BoarderPane的中心,该BoarderPane是舞台中场景的根。这与示例(我的具体用例的实现细节)无关,但决定将其保留,因为有些人可能觉得它很有用。
答案 6 :(得分:0)
是的,您需要添加第一个控制器
YourController controller = loader.getController();
controller.setclient(client);
然后在第二个中声明一个客户端,然后在控制器的底部:
public void setclien(Client c) {
this.client = c;
}
答案 7 :(得分:0)
我有一个简单得多的方法,使用initialize方法创建类的实例。我连续几天搜索了互联网,直到找到这种非常简单的方法。
声明您的类的实例:
//设置用于主类实例的变量
private static FXMLController instance;
声明您的课程,如下所示:
public class FXMLController implements Initializable {
在您的类中设置一个方法,如下所示:
public void mainController() {
instance = this;
}
然后在initialize方法中调用该方法:
@Override // this method is ran when first showing the main window
public void initialize(URL location, ResourceBundle resources) {
// initialize the instance of this class so it can be shared across controllers
mainController();
}
答案 8 :(得分:-1)
您可以决定使用公共可观察列表来存储公共数据,或者只创建一个公共setter方法来存储数据并从相应的控制器中检索
答案 9 :(得分:-2)
为什么要回答一个6岁的问题?
与任何编程语言一起使用的最基本的概念之一是如何从一种(窗口,窗体或页面)导航到另一种。同样,在进行这种导航时,开发人员经常想从一个(窗口,表单或页面)传递数据并显示或使用传递的数据
虽然这里的大多数答案都提供了出色的范例,说明了如何完成此操作,但我们认为我们可以将其提高一两个等级
之所以说三个,是因为我们将在三个(窗口,窗体或页面)之间导航,并使用静态变量的概念在(窗口,窗体或页面)周围传递数据
在导航时,我们还将包含一些决策代码
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);
}
}
启动控制器
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();
}
}
第一页控制器
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();
}
}
第二页控制器
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) {
}
}
下面是所有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>