2016-10-07 75 views
0

我正在構建一個JavaFX應用程序,並且想要訪問在JavaFX UI中作爲參數傳遞的值。出於某種原因,我無法在除基本方法launchForm之外的所有方法中訪問這些值。這是我的代碼的樣子。在JavaFX方法中使用參數

public class FormBuilder extends Application { 

    /* 
    * (non-Javadoc) 
    * @see javafx.application.Application#start(javafx.stage.Stage) 
    * Scene scene 
    *  Group root 
    *   BorderPane borderPane 
    *    TabPane tabPane 
    *     Tab stocksTab 
    *      BorderPane stockTabBorderPane 
    *       GridPane gridPane 
    *   
    */ 

    private Stocks stockData = new Stocks(); 
    private int size; 

    @Override 
    public void start(Stage stage) throws Exception { 
     stage.setTitle("Stock Manager"); 
     Group root = new Group(); 
     Scene scene = new Scene(root, 1024, 800, Color.WHITE); 

     TabPane tabPane = new TabPane(); 
     BorderPane borderPane = new BorderPane(); 
     BorderPane stockTabBorderPane = new BorderPane(); 

     Tab stocksTab = new Tab("Stocks"); 

     stockTabBorderPane.setTop(this.addHBox()); 
     stockTabBorderPane.setCenter(this.createGridPane()); 

     stocksTab.setContent(stockTabBorderPane); 
     tabPane.getTabs().add(stocksTab); 

     borderPane.setCenter(tabPane); 

     borderPane.prefHeightProperty().bind(scene.heightProperty()); 
     borderPane.prefWidthProperty().bind(scene.widthProperty()); 

     root.getChildren().add(borderPane); 


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


    } 

    private HBox addHBox() { 
     HBox hbox = new HBox(); 
     hbox.setPadding(new Insets(15, 12, 15, 12)); 
     hbox.setSpacing(10); 
     hbox.setStyle("-fx-background-color: #336699;"); 

     Button buttonCurrent = new Button("Current"); 
     buttonCurrent.setPrefSize(100, 20); 

     Button buttonProjected = new Button("Projected"); 
     buttonProjected.setPrefSize(100, 20); 
     hbox.getChildren().addAll(buttonCurrent, buttonProjected); 

     return hbox; 
    } 

    private GridPane createGridPane() { 

     GridPane gridPane = new GridPane(); 

     gridPane.setLayoutX(39); 
     gridPane.setLayoutY(131.0); 
     gridPane.setAlignment(Pos.TOP_CENTER); 
     gridPane.setVgap(5.0); 
     gridPane.setHgap(10.0); 

     gridPane.add(new Label("Active"), 1,1); 
     gridPane.add(new Label("Stock"), 2, 1); 
     gridPane.add(new Label("Symbol"), 3, 1); 
     gridPane.add(new Label("LPP"), 4, 1); 
     gridPane.add(new Label("LPP"), 5, 1); 
     gridPane.add(new Label("HPP"), 6, 1); 
     gridPane.add(new Label("LTP"), 7, 1); 

     System.out.println(this.size); 
     for(int v=2;v < this.stockData.getStocks().size()+2; v++) { 
      gridPane.add(new CheckBox(), 1, v); 
      gridPane.add(new Label("Amazon"), 2, v); 
      gridPane.add(new TextField(), 3,v); 
      gridPane.add(new TextField(), 4,v); 
      gridPane.add(new TextField(), 5,v); 
      gridPane.add(new TextField(), 6,v); 
      gridPane.add(new TextField(), 7,v); 

     } 

     return gridPane; 
    } 

    public void launchForm(Stocks stockData) { 
     this.stockData = stockData; 
     this.size = stockData.getStocks().size(); 
     System.out.println(stockData.getStocks().size()); 
     System.out.println(stockData.getStocks().get(0).getSector()); 
     launch(); 
    } 
} 

現在的問題是,當我嘗試和createGridPane方法中的stockData對象下訪問任何值,該值是不可用的。

實例是

this.stockData.getStocks().size()給出的0在createGridPane方法的值。但它在launchForm方法中的值爲2。

同樣有像

this.stockData.getStocks().get(0).getSector() 

返回在launchForm方法的值"Retail"其它值。但是當我嘗試在同一個類中以不同的方法訪問它時,出現異常。

有人可以幫我嗎?

+0

你從哪裏調用'launchForm'?你爲什麼要從該方法中調用'launch()'? ['launch()'](http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#launch-java.lang.String...-)啓動應用程序:當然,應用程序已經開始了。我認爲你必須從根本上誤解了JavaFX的生命週期:請參閱['Application' docs](http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html) –

+0

我想你可能需要在此問題中包含更多信息,以瞭解您正在做什麼以及如何構建應用程序。 –

回答

0

在JavaFX中,您應該基本上將Application的子類,特別是其start()方法作爲應用程序的入口點。應用程序生命週期在Application Javadocs中描述,但簡而言之,JavaFX啓動過程是通過調用靜態的Application.launch(...)方法之一或(使用Oracle JDK)啓動JVM並指定Application子類作爲主類來啓動的(甚至如果它沒有main方法)。

推出接着過程:

  1. 開始了JavaFX工具
  2. 創建Application
  3. 調用了Applicationinit()的新實例(默認的實現是一個空操作)
  4. 啓動FX應用程序線程
  5. Application子類調用start(),exec在FX應用程序線程上使用它。

儘管在不同的線程上被調用,start()保證不會被調用,直到init()已完成。

從您發佈的代碼中,您必須在其他地方實例化FormBuilder類,並在該實例上調用launchForm(...)。如果您從那裏調用launch(),則會創建第二個實例並在其上調用start(),如上所述。所以當然你在調用launchForm(...)的實例上設置的字段將不會在調用start(...)的實例上設置。

你應該重構你的代碼,這樣無論是FormBuilder是入口點的應用程序,或者使FormBuilder不是一個Application子類,並創建一個新的入口點實例化並使用它。看起來你有一些加載數據的後臺工作:這應該是一個單獨的類,它不應該是入口點。因此,第一個重構會是什麼樣子:

// class that reads data and encapsulates it as a Stocks object 

public class StockDataAccessor { 

    // ... 

    public Stocks getStocks() { 
     // ... 
    } 

} 

然後FormBuilder樣子:

public class FormBuilder extends Application { 

    /* 
    * (non-Javadoc) 
    * @see javafx.application.Application#start(javafx.stage.Stage) 
    * Scene scene 
    *  Group root 
    *   BorderPane borderPane 
    *    TabPane tabPane 
    *     Tab stocksTab 
    *      BorderPane stockTabBorderPane 
    *       GridPane gridPane 
    *   
    */ 

    private Stocks stockData ; 
    private int size; 

    @Override 
    public void start(Stage stage) throws Exception { 

     StockDataAccessor stockDataAccessor = new StockDataAccessor(); 
     stockData = stockDataAccessor.getStocks(); 

     stage.setTitle("Stock Manager"); 
     Group root = new Group(); 
     Scene scene = new Scene(root, 1024, 800, Color.WHITE); 

     TabPane tabPane = new TabPane(); 
     BorderPane borderPane = new BorderPane(); 
     BorderPane stockTabBorderPane = new BorderPane(); 

     Tab stocksTab = new Tab("Stocks"); 

     stockTabBorderPane.setTop(this.addHBox()); 
     stockTabBorderPane.setCenter(this.createGridPane()); 

     stocksTab.setContent(stockTabBorderPane); 
     tabPane.getTabs().add(stocksTab); 

     borderPane.setCenter(tabPane); 

     borderPane.prefHeightProperty().bind(scene.heightProperty()); 
     borderPane.prefWidthProperty().bind(scene.widthProperty()); 

     root.getChildren().add(borderPane); 


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


    } 

    private HBox addHBox() { 
     HBox hbox = new HBox(); 
     hbox.setPadding(new Insets(15, 12, 15, 12)); 
     hbox.setSpacing(10); 
     hbox.setStyle("-fx-background-color: #336699;"); 

     Button buttonCurrent = new Button("Current"); 
     buttonCurrent.setPrefSize(100, 20); 

     Button buttonProjected = new Button("Projected"); 
     buttonProjected.setPrefSize(100, 20); 
     hbox.getChildren().addAll(buttonCurrent, buttonProjected); 

     return hbox; 
    } 

    private GridPane createGridPane() { 

     GridPane gridPane = new GridPane(); 

     gridPane.setLayoutX(39); 
     gridPane.setLayoutY(131.0); 
     gridPane.setAlignment(Pos.TOP_CENTER); 
     gridPane.setVgap(5.0); 
     gridPane.setHgap(10.0); 

     gridPane.add(new Label("Active"), 1,1); 
     gridPane.add(new Label("Stock"), 2, 1); 
     gridPane.add(new Label("Symbol"), 3, 1); 
     gridPane.add(new Label("LPP"), 4, 1); 
     gridPane.add(new Label("LPP"), 5, 1); 
     gridPane.add(new Label("HPP"), 6, 1); 
     gridPane.add(new Label("LTP"), 7, 1); 

     System.out.println(this.size); 
     for(int v=2;v < this.stockData.getStocks().size()+2; v++) { 
      gridPane.add(new CheckBox(), 1, v); 
      gridPane.add(new Label("Amazon"), 2, v); 
      gridPane.add(new TextField(), 3,v); 
      gridPane.add(new TextField(), 4,v); 
      gridPane.add(new TextField(), 5,v); 
      gridPane.add(new TextField(), 6,v); 
      gridPane.add(new TextField(), 7,v); 

     } 

     return gridPane; 
    } 

    // for non-JavaFX aware environments (like your IDE...) 
    public static void main(String[] args) { 
     launch(args); 
    } 
} 

然後啓動FormBuilder作爲主類會做你的需要。


如果你想要素的應用入口點出FormBuilder類的完全的替代重構(這是非常相似的)看起來像:

public class FormBuilder { 

    /* 
    * (non-Javadoc) 
    * @see javafx.application.Application#start(javafx.stage.Stage) 
    * Scene scene 
    *  Group root 
    *   BorderPane borderPane 
    *    TabPane tabPane 
    *     Tab stocksTab 
    *      BorderPane stockTabBorderPane 
    *       GridPane gridPane 
    *   
    */ 

    private Stocks stockData ; 
    private int size; 

    private Group root ; 

    public FormBuilder() { 

     StockDataAccessor stockDataAccessor = new StockDataAccessor(); 
     stockData = stockDataAccessor.getStocks(); 

     root = new Group(); 

     TabPane tabPane = new TabPane(); 
     BorderPane borderPane = new BorderPane(); 
     BorderPane stockTabBorderPane = new BorderPane(); 

     Tab stocksTab = new Tab("Stocks"); 

     stockTabBorderPane.setTop(this.addHBox()); 
     stockTabBorderPane.setCenter(this.createGridPane()); 

     stocksTab.setContent(stockTabBorderPane); 
     tabPane.getTabs().add(stocksTab); 

     borderPane.setCenter(tabPane); 

     borderPane.prefHeightProperty().bind(scene.heightProperty()); 
     borderPane.prefWidthProperty().bind(scene.widthProperty()); 

     root.getChildren().add(borderPane); 



    } 

    public Parent getView() { 
     return root ; 
    } 

    private HBox addHBox() { 
     HBox hbox = new HBox(); 
     hbox.setPadding(new Insets(15, 12, 15, 12)); 
     hbox.setSpacing(10); 
     hbox.setStyle("-fx-background-color: #336699;"); 

     Button buttonCurrent = new Button("Current"); 
     buttonCurrent.setPrefSize(100, 20); 

     Button buttonProjected = new Button("Projected"); 
     buttonProjected.setPrefSize(100, 20); 
     hbox.getChildren().addAll(buttonCurrent, buttonProjected); 

     return hbox; 
    } 

    private GridPane createGridPane() { 

     GridPane gridPane = new GridPane(); 

     gridPane.setLayoutX(39); 
     gridPane.setLayoutY(131.0); 
     gridPane.setAlignment(Pos.TOP_CENTER); 
     gridPane.setVgap(5.0); 
     gridPane.setHgap(10.0); 

     gridPane.add(new Label("Active"), 1,1); 
     gridPane.add(new Label("Stock"), 2, 1); 
     gridPane.add(new Label("Symbol"), 3, 1); 
     gridPane.add(new Label("LPP"), 4, 1); 
     gridPane.add(new Label("LPP"), 5, 1); 
     gridPane.add(new Label("HPP"), 6, 1); 
     gridPane.add(new Label("LTP"), 7, 1); 

     System.out.println(this.size); 
     for(int v=2;v < this.stockData.getStocks().size()+2; v++) { 
      gridPane.add(new CheckBox(), 1, v); 
      gridPane.add(new Label("Amazon"), 2, v); 
      gridPane.add(new TextField(), 3,v); 
      gridPane.add(new TextField(), 4,v); 
      gridPane.add(new TextField(), 5,v); 
      gridPane.add(new TextField(), 6,v); 
      gridPane.add(new TextField(), 7,v); 

     } 

     return gridPane; 
    } 

} 

,然後創建一個切入點:

public class StockApp extends Application { 

    @Override 
    public void start(Stage stage) { 
     FormBuilder formBuilder = new FormBuilder(); 
     Scene scene = new Scene(formBuilder.getView(), 1024, 800, Color.WHITE); 
     stage.setTitle("Stock Manager"); 
     stage.setScene(scene); 
     stage.show(); 
    } 

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

這有助於我解決了這個問題。謝謝。 – ngnear

1

您正在調用launchForm實例方法中的Application.launch,並期望它使用此方法調用的實例作爲應用程序類。

但是,JavaFX啓動不能這樣工作。

如果Application.launch被調用,該方法是從由launch方法本身產生的時候,它是用來與initstart這個新的實例類的實例。

解決這一問題將是,如果你能創造的Stocks最簡單的方式initstart(可能通過一些字符串作爲參數傳遞給launch)。否則,您需要一些其他方式與Application子類的新創建的實例進行通信,例如, static成員...

+0

它看起來應該不是'Application'子類,並且應該是'Stage'子類(或者應該有一個'Stage'的引用)。然後用'show()'替換'launch()'。 –

+0

@James_D:如果OP達到了在新實例上調用'start'方法的點,則平臺尚未啓動,並且任何顯示「Stage」的嘗試都將不可避免地失敗...... – fabian

+0

的確如此。但這似乎是生命週期在這裏都是錯誤的。很明顯,在調用'launchForm'之前正在執行一些其他代碼。在這之前真的不應該有任何事情;所有的啓動代碼應該在'init()'或'start()'中,除非是在非常特殊的情況下。 (這與你在倒數第二段所說的相似。)所以「其他代碼」應該是Application類的子類,而這個類應該是別的。我想我的意思是這裏比OP發佈的代碼更多的結構問題。 –