Erste Schritte JavaFX - wie von "externer" Klasse auf Methoden des Controllers zugreifen

Knoten

Mitglied
Hallo Profis!

Ich plage mich gerade mit einer grundsätzlichen Frage zur
Pogrammstruktur mit JavaFX.

Ich habe eine Oberfläche mit dem SceneBuilder (Projekt JavaFX mit FXML Application) erstellt und darin befindet sich eine "TextArea".

Nun wird das dort alles schön in 3 Dateien aufgespalten:

In der TextArea möchte ich nun verschiedene Statusmeldungen zur Anzeige
bringen.
Das ist innerhalb der Controllerklasse aus auch gar keinProblem, da dort die TextArea über
@FXML
private TextArea myTextArea;
einfach definiert ist.

Nun habe ich aber z. B. eine weitere separate Klasse "WireClass.java" , welche
eine Datenübertragung behandelt.
Von dieser Klasse aus weiß ich jedoch nicht wie ich auf die Elemente meiner GUI zugreifen kann, d.h. wie ich von dort einen Text in meine TextArea hineinschreiben kann, da ich null Plan habe, wie ich deren Existenz in der Komponente "wireClass" definiere.

Das kann doch nicht so schwer sein??? Ich blicke hier aber keine 2cm durch... (bin natürlich zu allem Überfluss auch maximaler Java Anfänger).

Kann mich jemand erleuchten?

Hier meine 4 Test-Dateien:

MyTest.java:
Java:
package mytest;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class MyTest extends Application {
  
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
      
        Scene scene = new Scene(root);
      
        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
  
}

FXMLDocument.fxml:
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="452.0" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="mytest.FXMLDocumentController">
    <children>
      <TextArea fx:id="myTextArea" layoutX="73.0" prefHeight="288.0" prefWidth="200.0" />
      <Button fx:id="myButton" layoutX="96.0" layoutY="322.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Button" />
    </children>
</AnchorPane>

FXMLDocumentController.java:
Java:
package mytest;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;


public class FXMLDocumentController implements Initializable {
   
    WireClass wireClass = new WireClass();
   
    //private Label label;
    @FXML
    private TextArea myTextArea;
   
    @FXML
    private Button myButton;
   
    public void showinfo(String inhalt) {
        myTextArea.appendText(inhalt+"\n");
    }
   
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }   

    @FXML
    private void handleButtonAction(ActionEvent event) {
        showinfo("von Button");       
        wireClass.infoout();
    }
   
}

WireClass.java:
Java:
package mytest;

public class WireClass {

    public void infoout () {

// Ich möchte von dieser Klasse auf die Methode "showinfo" im Controller zugreifen, so ähnlich wie:

        FXMLDocumentController.showinfo("von wireClass");

// aber das funktioniert so nicht, da das ja keine Instanz der ControllerKlasse ist?     
// Wie kann ich das denn schreiben?
       
    }
   
}
 
Keine Sorge: Das ist eine bei Neueinsteigern immer wieder gestellte Frage. Durch die Struktur (Main-Klasse, Controller+FXML) ensteht eine Trennung zwischen den Komponenten.
Deine Wire-Klasse wird so nicht funktionieren, weil ein statisches setzen nicht klappt (so wie du es andeutest), sondern du müsstest der Wire-Klasse die Instanz deines Controllers geben.
Deine Struktur ist noch etwas wild im Kreis und mir erschliesst sich nicht, warum du das so regeln möchtest, aber damit es klappt, musst du aus dem FXMLLoader (nach dem #load) den Controller holen.
Also: Statt statisch #load aufzurufen (unvollständiger Code):
Java:
// MAIN-KLASSE
FXMLLoader loader = new FXMLLoader(...); 
Pane root = loader.load();
FXMLDocumentController controller = loader.getController();
WireClass wire = new WireClass();
wire.setController(controller);

// Wire-Klasse
private FXMLDocumentController controller = null;
public void setController(FXMLDocumentController controller) {
    this.controller = controller;
}

public void doSthOnController() {
    if (controller == null)
        return null;
    controller.triggerMethod();
}
// ...

In etwa klar, wohin die Reise geht?
 
Tausend Dank dzim!
Das funktioniert!!! Genaus sowas habe ich gesucht.
Ich werde mich da noch eingehend damit befassen müssen, damit ich das auch restlos kapiere.
Aber so prinzipiell verstehe ich es schon.

Warum ich diese 'wilde" Struktur habe, kann ich ehrlich gesagt nicht erklären - aber für mich ist das eine logische Struktur.
Das ist jetzt nur ein erster Test.

Ich werde später nur eine GUI-Oberfläche haben in welcher ein "allgemeines" Info-Feld angelegt ist (eine TextArea).
Darin werde ich sämtliche ablaufspezifischen Aktionen anzeigen wie z.B. "Datei xy erfolgreich geladen" , "USB-Device device xy gefunden", "Daten aus Gerät xy erfolgreich ausgelesen" usw.
Ich habe alleine damit schon verschiedene Klassen wie Dateioperationen und USB-Kommunikation.
Von jeder dieser Klassen möchte ich meine Meldungen als Protokoll mit Zeitstempel auf genau dieser TextArea anzeigen.
Die zentrale Text-Ausgaberoutine werde ich im "Controller" anlegen, mit einem einfachen String als Übergabeparameter (von irgendwoher - daher meine dämliche Frage).

Vermutlich hapert es bei mir am OOP-Verständnis, da ich bislang nur Delphi- C und Assembler (alles mehr schlecht als recht) gemacht habe. Wahrscheinlich beisst sich meine "Wunsch-Struktur" mit dem Java-Konzept.
Ich bin halt kein Informatiker - aber dafür lernwillig!
Danke Meister!
 

Zurück
Oben