2014-10-16 38 views
0

我正在創建一個程序,其頂部有一排按鈕,一側有一排按鈕。 頂部按鈕控制視圖,側面按鈕控制視圖中要引用的對象。JavaFX:如何使用新值更新邊界窗格的中心視圖

我的主/根視圖是一個borderpane。

重點是,當我點擊這些按鈕中的任何一個時,在我的MainController中更改一個值,然後用這些新值重新加載中心視圖。我認爲這會很簡單,寫一個方法可以改變這個值,然後根據這些值設置一個新的中心。

但是,當我測試它時,它可以顯示我已經要求它顯示的兩個值,但每次運行時都會給我一大堆紅色的錯誤代碼。

我MainViewController如下所示:

import java.io.IOException; 
import javafx.application.Application; 
import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.layout.AnchorPane; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 



public class MainViewController extends Application { 


@FXML 
private Button cabin1; 
@FXML 
private Button cabin2; 
@FXML 
private Button tab1; 
@FXML 
private Button tab2; 



@FXML 
public void setCabinOne() throws IOException { 
    cabinIndex=1; 
    setCenterView(); 
} 
@FXML 
public void setCabinTwo() throws IOException { 
    cabinIndex=2; 
    setCenterView(); 
} 

@FXML 
public void setTabOne() throws IOException { 
    tabIndex=1; 
    setCenterView(); 
} 

@FXML 
public void setTabTwo() throws IOException { 
    tabIndex=2; 
    setCenterView(); 
} 

public int getCabinIndex() { 
    return cabinIndex; 
} 

public int getTabIndex() { 
    return tabIndex; 
} 

private int tabIndex=0; 
private int cabinIndex=1; 


public Stage primaryStage; 
private BorderPane mainPane; 

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

} 

@Override 
public void start(Stage primaryStage) throws Exception { 
    this.primaryStage=primaryStage; 
    primaryStage.setTitle("Test"); 
    FXMLLoader loader = new FXMLLoader(); 
    loader.setLocation(MainViewController.class.getResource("MainView.fxml")); 
    mainPane = loader.load(); 
    setCenterView(); 
    Scene scene = new Scene(mainPane); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 

} 

public void setCenterView() throws IOException { 
    FXMLLoader loader = new FXMLLoader(); 
    loader.setLocation(MainViewController.class.getResource("TestView.fxml")); 
    AnchorPane testPane = loader.load(); 
    TestViewController tvc = loader.<TestViewController>getController(); 
    tvc.changeLabel(getCabinIndex()); 
    tvc.changeIndex(getTabIndex()); 
    mainPane.setCenter(testPane); 
} 

} 

和我TestViewController如下所示:

import javafx.fxml.FXML; 
import javafx.scene.control.Label; 


public class TestViewController { 

@FXML 
private Label cabinIndex; 
@FXML 
private Label tabIndex; 

public void initialise() { 
    this.changeLabel(0); 
    this.changeIndex(0); 

} 

public void changeLabel(int n) { 
    cabinIndex.setText("Cabin "+Integer.toString(n)); 
} 

public void changeIndex(int n) { 
    tabIndex.setText("Tab "+Integer.toString(n)); 
} 

} 

我在做什麼錯?

+0

請嘗試刪除所有混亂,並將其刪除一個較小的例子。此外,錯誤信息會非常有幫助。 – rethab 2014-10-16 14:08:20

+0

你在說什麼混亂?一旦我再次訪問我的電腦,我會發布錯誤消息。 – 2014-10-16 14:45:26

+0

歡迎來到StackOverflow。當您發佈示例時,請始終嘗試創建一個[最小完整示例](http://stackoverflow.com/help/mcve),該示例剛好足以重現此問題,而不再更多。在你的情況下,你可以完全消除'TestView.fxml'和'TestViewController',並且消除'MainViewController'中除'mainPane'和一個按鈕之外的所有內容。用'mainPane.setCenter(new Label(「Hello」))替換'setCenterPane'的實現,你仍然會看到相同的堆棧跟蹤。 (這是@rethab指的「混亂」。) – 2014-10-17 01:38:13

回答

1

您的應用程序基本上在結構上是錯誤的:您正在使用應用程序子類作爲控制器,並且這根本不起作用(至少不容易)。您需要使用與控制器不同的啓動類(Application的子類)對此進行重構。幾乎任何完整的示例都可以作爲您的模板,但Oracle tutorial是一個很好的開始。

正在發生的事情如下:

當您在MainViewController.main(...)調用Application.launch(),外匯啓動工具包之後,您的應用程序類MainViewController的實例被創建時,FX應用程序線程啓動,並且start()方法屬於在FX應用程序線程上調用MainViewController實例。

當您調用FXMLLoaderload()方法時,它將解析指定位置處的FXML文件。當它看到fx:controller屬性(我假設其爲fx:controller="MainViewController")時,它將創建指定控制器類的實例。一旦FXML被解析,任何匹配的@FXML-annotated字段(屬於該實例)將被初始化爲來自FXML文件的相應對象,然後在該實例上調用initialize()方法。

因此,請注意您實際上有兩個MainViewController實例:FXMLLoader.load()被調用的實例和FXMLLoader創建的實例。初始化由FXMLLoader創建的實例中的@FXML -annotated字段,但原始實例中的字段保持設置爲缺省值null。相反,mainPane字段在原始MainViewController實例中的start方法中初始化,但在FXMLLoader創建的實例中永遠不會初始化。所以當你按下按鈕並調用setCenterView()(我假設你的FXML是如何設置的),當mainPane仍然是null時,你最終會調用mainPane.setCenter()

你可能會強迫它像這樣工作。例如:從MainView.fxml中刪除fx:controller屬性,並調用loader.setController(this)。但是當你遠離框架使用的通常模式時,你的代碼變得很難維護和調試。我會建議遵循API所設計的設計。

+0

我真的很感激你看着這個。我現在改變了結構,以便我有一個只運行程序並啓動視圖的Main類。我現在的問題是如何能夠在Main類中使MainViewController更改值。 取值爲cabinIndex。我將它初始化爲0.當我設置中心視圖時,我要求它加載TestView.fxml,創建一個TestViewController,並要求TVC將其標籤更改爲「Cabin 0」。這工作正常。我想要做的是在MainView中單擊一個按鈕,然後讓它更改cabinIndex。我如何正確引用它? – 2014-10-17 11:29:54

+0

不要將應用程序邏輯放在主類中:只需將這些屬性('cabinindex'等)移動到控制器。 (在一個更大的應用程序中,你可能有一個封裝所有這些屬性的獨立類 - 一個模型 - 並將其引用傳遞給你的控制器,但現在我只是簡單地將它們定義在控制器中。) – 2014-10-17 11:40:33

+0

好的,所以我已將cabinIndex移至MainViewController。我的問題是現在:我想單擊MainViewController中的按鈕1,並讓它將cabinIndex更改爲1,然後使用新的cabinIndex重新加載TestView。我怎樣才能做到這一點?我在想,我應該在TestViewController中創建一個MainViewController的實例,然後能夠在那裏使用它的方法。我如何確保它始終引用當前的MainViewController? – 2014-10-17 11:46:03