2013-03-15 166 views
3

我有了一個TreeView控件FXML文件:的JavaFX - 包裝FXML Java類控制器

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="500.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test.MyControllerClass"> 

<TreeView fx:id="locationTreeView" layoutX="12.0" layoutY="158.0" prefHeight="193.0" prefWidth="471.0" /> 

然後我的Java類控制器需要與此樹視圖來包裝,並添加TreeItem的動態。這就是問題所在,它不會加載這些TreeItem的。這是我的控制器下面的測試代碼:

public class MyControllerClass extends Application { 

    @FXML 
    private TreeView<String> locationTreeView; 

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

     stage.initStyle(StageStyle.TRANSPARENT); 
     stage.getIcons().add(new Image(getClass().getResourceAsStream("myIcon.png"))); 

     Parent root = FXMLLoader.load(getClass().getResource("myInterface.fxml")); 

     Scene scene = new Scene(root); 
     stage.setScene(scene); 

     loadTreeItems(); 

     stage.show(); 
    } 

    // Just a simple example that still doesn't works 
    private void loadTreeItems() { 

     try { 
      TreeItem<String> root = new TreeItem<String>("Root Node"); 
      root.setExpanded(true); 
      root.getChildren().addAll(
       new TreeItem<String>("Item 1"), 
       new TreeItem<String>("Item 2"), 
       new TreeItem<String>("Item 3") 
      ); 

      locationTreeView = new TreeView<String>(root); 

     } catch (Exception exc) { 
      System.out.println("Error: " + exc.getMessage()); 
     } 
    } 

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

任何想法爲什麼它不工作?

回答

6

有幾個原因使您的應用程序不工作:

  1. 你需要使控制器和應用單獨的類。
  2. 您應該允許FXML系統注入TreeView實例,而不是創建新實例(正如Aaron在他的答案中指出的那樣)。

你有你的應用程序目前的結構會發生什麼事情的方式是:

  1. Java系統將創建MyControllerClass上啓動一個實例(並調用它的start方法)。
  2. FXMLLoader將創建另一個實例的每個myInterface.fxml加載文件時MyControllerClass
  3. FXMLLoader將創建一個新的TreeView實例,並創建新MyControllerClass實例的locationTreeView成員執行了注射FXML。
  4. FXMLLoader將嘗試在新的MyControllerClass(其中您沒有)上調用initialize方法。
  5. FXMLLoader調用上MyControllerClassstart方法。在
  6. 你原來start方法調用原始的MyControllerClass將繼續處理並創建另一個新TreeView例如它會設置MyControllerClass實例的locationTreeView成員。

我更新了你的代碼,使我上面提出的修改和現在的代碼工作。更新的code is available

從正在運行的代碼的樣本屏幕截圖是: dynamictreeview

MyApplicationClass.java

import javafx.animation.*; 
import javafx.application.Application; 
import javafx.event.*; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.*; 
import javafx.scene.image.Image; 
import javafx.scene.input.MouseEvent; 
import javafx.stage.*; 
import javafx.util.Duration; 

/** Sample application to demonstrate programming an FXML interface. */ 
public class MyApplicationClass extends Application { 
    @Override public void start(final Stage stage) throws Exception { 
    // load the scene fxml UI. 
    // grabs the UI scenegraph view from the loader. 
    // grabs the UI controller for the view from the loader. 
    final FXMLLoader loader = new FXMLLoader(getClass().getResource("myInterface.fxml")); 
    final Parent root = (Parent) loader.load(); 
    final MyControllerClass controller = loader.<MyControllerClass>getController(); 

    // continuously refresh the TreeItems. 
    // demonstrates using controller methods to manipulate the controlled UI. 
    final Timeline timeline = new Timeline(
     new KeyFrame(
     Duration.seconds(3), 
     new TreeLoadingEventHandler(controller) 
    ) 
    ); 
    timeline.setCycleCount(Timeline.INDEFINITE); 
    timeline.play(); 

    // close the app if the user clicks on anywhere on the window. 
    // just provides a simple way to kill the demo app. 
    root.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { 
     @Override public void handle(MouseEvent t) { 
     stage.hide(); 
     } 
    }); 

    // initialize the stage. 
    stage.setScene(new Scene(root)); 
    stage.initStyle(StageStyle.TRANSPARENT); 
    stage.getIcons().add(new Image(getClass().getResourceAsStream("myIcon.png"))); 
    stage.show(); 
    } 

    /** small helper class for handling tree loading events. */ 
    private class TreeLoadingEventHandler implements EventHandler<ActionEvent> { 
    private MyControllerClass controller; 
    private int idx = 0; 

    TreeLoadingEventHandler(MyControllerClass controller) { 
     this.controller = controller; 
    } 

    @Override public void handle(ActionEvent t) { 
     controller.loadTreeItems("Loaded " + idx, "Loaded " + (idx + 1), "Loaded " + (idx + 2)); 
     idx += 3; 
    } 
    } 

    // main method is only for legacy support - java 8 won't call it for a javafx application. 
    public static void main(String[] args) { launch(args); } 
} 

MyControllerClass.java

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

/** Sample controller class. */ 
public class MyControllerClass { 
    // the FXML annotation tells the loader to inject this variable before invoking initialize. 
    @FXML private TreeView<String> locationTreeView; 

    // the initialize method is automatically invoked by the FXMLLoader - it's magic 
    public void initialize() { 
    loadTreeItems("initial 1", "initial 2", "initial 3"); 
    } 

    // loads some strings into the tree in the application UI. 
    public void loadTreeItems(String... rootItems) { 
    TreeItem<String> root = new TreeItem<String>("Root Node"); 
    root.setExpanded(true); 
    for (String itemString: rootItems) { 
     root.getChildren().add(new TreeItem<String>(itemString)); 
    } 

    locationTreeView.setRoot(root); 
    } 
} 

myInterface.fxml

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

<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns:fx="http://javafx.com/fxml" fx:controller="test.MyControllerClass"> 
    <TreeView fx:id="locationTreeView" layoutX="0" layoutY="0" prefHeight="193.0" prefWidth="471.0" /> 
</AnchorPane> 
+0

非常感謝您的時間@jewelsea!很好的解釋!同時也感謝你編寫正確的方法! – Leonardo 2013-03-18 13:47:01

+0

你不需要分開類。你只需要類MyControllerClass中的'initialize'方法。 – 2014-11-24 20:08:12

+0

@Nuno將JavaFX控制器和JavaFX應用程序放在同一個類中是不好的做法,因爲它既容易混淆又容易出錯。雖然有可能讓這樣的設置起作用,但我不推薦這樣的解決方案,也不會將它發佈到公共論壇。 – jewelsea 2014-11-24 20:15:56

2

在您的loadTreeItems()函數中,您正在創建一個新的TreeView實例。這將替換FXML文件中定義的並使用不屬於場景圖的一部分的新實例附加到場景中的一個。

要將項目添加到通過FXMLLoader創建的TreeView中,您可以使用setRoot()函數。

private void loadTreeItems() { 

    try { 
     TreeItem<String> root = new TreeItem<String>("Root Node"); 
     root.setExpanded(true); 
     root.getChildren().addAll(
      new TreeItem<String>("Item 1"), 
      new TreeItem<String>("Item 2"), 
      new TreeItem<String>("Item 3") 
     ); 

     locationTreeView.setRoot(root); 

    } catch (Exception exc) { 
     System.out.println("Error: " + exc.getMessage()); 
    } 
} 
+0

感謝您的回答@Aaron。但它沒有工作。我剛剛創建了一個TreeView,沒有TreeItems。這可能是問題嗎? – Leonardo 2013-03-15 20:30:13

+0

我的意思是:在FXML文件中創建一個TreeView。 – Leonardo 2013-03-15 20:38:42

相關問題