2012-11-20 20 views
6

Ich bin ziemlich neu in Java und Javafx und habe ein Problem, das ich nicht lösen konnte. Ich muss dynamisch neue benutzerdefinierte Steuerelemente zu einer Javafx-Szene hinzufügen. Außerdem brauche ich eine Interaktion zwischen dem Hauptsteuerelement und den hinzugefügten Steuerelementen. Ich habe bereits einige nützliche Informationen im Internet gefunden, konnte sie aber nicht zusammensetzen.JavaFX2 Controls dynamisch hinzufügen

So bauen ich ein kleines Beispiel zur Erläuterung:

Hauptklasse:

public class Test_TwoController extends Application { 

    @Override 
    public void start(Stage stage) throws Exception { 
     Parent root = FXMLLoader.load(getClass().getResource("Fxml1.fxml")); 
     Scene scene = new Scene(root);     
     stage.setScene(scene); 
     stage.show(); 
    }  
    public static void main(String[] args) { 
     launch(args); 
    } 
} 

Der Haupt fxml:

<AnchorPane id="fxml1_anchorpane_id" fx:id="fxml1_anchorpane" prefHeight="206.0" prefWidth="406.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test_twocontroller.Fxml1Controller"> 
    <children> 
    <HBox id="fxml1_hbox_id" fx:id="fxml1_hbox" prefHeight="200.0" prefWidth="400.0"> 
     <children> 
     <Button id="fxml1_button_id" fx:id="fxml1_button" mnemonicParsing="false" onAction="#button_action" prefHeight="200.0" prefWidth="200.0" text="Button" /> 
     </children> 
    </HBox> 
    </children> 
</AnchorPane> 

und seine Steuerung:

public class Fxml1Controller implements Initializable { 

    @FXML HBox hbox; 
    @FXML Button button; 

    @Override 
    public void initialize(URL url, ResourceBundle rb) { } 

    public void button_action(ActionEvent event) throws IOException { 
     // 1. add an instance of Fxml2 to hbox 
     // 2. change to tab2 in new Fxml2 
     // or 
     // notify Fxml2Controller to change to tab2 in Fxml2 
    } 
} 

Und jetzt die Kontrolle zu dyn amically hinzufügen:

Seine fxml:

<AnchorPane id="fxml2_anchorpane_id" fx:id="fxml2_anchorpane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test_twocontroller.Fxml2Controller"> 
    <children> 
    <TabPane id="fxml2_tabpane_id" fx:id="fxml2_tabpane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE"> 
     <tabs> 
     <Tab id="fxml2_tab1_id" fx:id="fxml2_tab1" text="tab1"> 
      <content> 
      <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" /> 
      </content> 
     </Tab> 
     <Tab id="fxml2_tab2_id" fx:id="fxml2_tab2" onSelectionChanged="#onSelectionChanged" text="tab2"> 
      <content> 
      <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" /> 
      </content> 
     </Tab> 
     </tabs> 
    </TabPane> 
    </children> 
</AnchorPane> 

und die Controler:

public class Fxml2Controller { 

    @FXML TabPane tabpane; 
    @FXML Tab tab1; 
    @FXML Tab tab2; 

    public Fxml2Controller() throws IOException { 
     Parent root = FXMLLoader.load(getClass().getResource("Fxml2.fxml")); 
     Scene scene = new Scene(root);   
     Stage stage = new Stage(); 
     stage.setScene(scene);   
    }  

    public void onSelectionChanged(Event e) throws IOException { 

     FXMLLoader loader = new FXMLLoader(); 
     // how can i get the current Fxml1 anchorpane instance? 
     AnchorPane root = (AnchorPane) loader.load(getClass().getResource("Fxml1.fxml").openStream()); 

     Button b = (Button)root.lookup("#fxml1_button_id");   
     b.setText("New Button Text"); // dont change the buttons text!!!    
} 
} 

Die Nutzung ist: Ein fxml2 sollte die hbox von fxml1 hinzugefügt werden. Nach einem Klick in fxml1 sollten sich die Tabs von fxml2 ändern. Sie können zu diesem Bild einen Blick http://s13.postimage.org/uyrmgylo7/two_controlls.png

Also meine Fragen sind:

  • wie kann ich ein oder mehrere der fxml2 Controller in die hbox von fxml1 hinzufügen?
  • Wie kann ich auf ein Steuerelement von einem anderen zugreifen oder zwischen controlls kommunizieren? Siehe Methode onSelectionChanged() in Fxml2Controller für Details.

Vielen Dank im Voraus,

solarisx

Antwort

5

Sie scheinen ziemlich viele Konzepte zusammen zu haben, gemischt, die verschieden sind. Zunächst kann ein Stage als ein Fenster auf dem Bildschirm verstanden werden. Es hat ein Scene-Objekt, das den eigentlichen SceneGraph enthält. In Ihrem Beispiel erstellen Sie eine neue Bühne und eine neue Szene, die den Inhalt Ihrer zweiten fxml-Datei füllt. Dies bedeutet, dass wenn Sie arbeiten, ein zweites Fenster erscheint, das Ihre Sachen enthält. Ich glaube nicht, dass Sie das erreichen wollen.

Darüber hinaus, wenn der FXMLLoader eine Datei liest, sucht er nach der Klasse, die als Controller angegeben ist, und erstellt eine Instanz davon über Reflektion. Dies bedeutet, dass Sie beim Aufruf der load-Methode im Konstruktor des Controllers der fxml-Datei, die Sie damit laden, eine Endlosschleife verursachen.

Das letzte, was zu verstehen ist, dass das Objekt, das load() zurückgibt, ein beliebiger Knoten ist, der wie jeder andere Knoten in den SceneGraph Ihrer Anwendung eingefügt werden kann.

So Ihr Konzept funktioniert, Sie Folgendes machen sollte:

  1. Bewegen Sie den Laden-Code, der in dem Konstruktor Ihrer zweiten Controller an die button_Action Methode Ihrer ersten Steuerung zur Zeit ist.
  2. Wirf den new-stage-new-scene-Code in der button_action weg und nimm den vom FXMLLoader zurückgegebenen Knoten und füge ihn zu den Kindern der HBox hinzu.
  3. Für Ihre zweite Frage können Sie die Controller-Instanz erhalten, wenn Sie tatsächlich eine Instanz eines FXMLLoader erstellen, anstatt die statische Methode aufzurufen, und verwenden Sie die load() Methode darin. Nach dem Aufruf von load() können Sie den Controller und das Root-Objekt der fxml-Datei über getController() und getRoot() abrufen. Sie können sie dann wie jedes beliebige Objekt in Ihrer Logik verwenden.
+0

Danke für Ihre Antwort. Mit Punkt 1. und 2. kann ich nun Fxml2's in Fxml1 hinzufügen. Aber der Zugang zu den Kontrollen ist mir immer noch nicht klar. Nach dem Hinzufügen eines Fxml2 in Fxml1 möchte ich etwas in Fxml1 ändern, wenn etwas in Fxml2 passiert. Ich habe eine onSelectionChanged-Methode im Fxml2Controller() - Code zur besseren Erklärung hinzugefügt. Ich denke, das Problem ist, dass ich die aktuelle Instanz von Fxml1 nicht bekommen habe. – solarisx

+0

Ok. Die Antwort für meine zweite Frage finden Sie in Sebastians 3. Punkt und [Zugriff auf FXML-Controller-Klasse] (http://stackoverflow.com/questions/10751271/accessing-fxml-controller-class?lq=1). Um NULL beim Zugriff auf den Controller zu vermeiden, lesen Sie [Wie kann ich auf eine Controller-Klasse in JavaFx 2.0 zugreifen?] (Http://stackoverflow.com/questions/10240471/how-can-i-access-a-controller-class-in- javafx-2-0) – solarisx