• Wir präsentieren Dir heute ein Stellenangebot für einen Frontend-Entwickler Angular / Java in Braunschweig. Hier geht es zur Jobanzeige

JavaFX Concurrency Update UI

izoards

izoards

Mitglied
Hallo,

Ich möchte ein JavaFX UI von einem Background Thread aktualisieren. Ich habe mich an folgendem Codebeispiel orientiert:
JavaFX Concurrency Example | Examples Java Code Geeks - 2021

Jedoch ist mein UI mit einer Controller Klasse und einem *.fxml - File aufgesetzt.
Ich möchte also das label über das controller objekt ansprechen. Aber genau hier, stürzt mein Programm ab.

Hier mein angepasster Code:
Update UI via controller class:
public class FxConcurrencyExample3  extends Application
{

    private Stage primaryStage;
    private MainWindowController controller = new MainWindowController();

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

    @Override
    public void start(Stage primaryStage) {

        this.primaryStage = primaryStage;



        try {
            FXMLLoader loader = new FXMLLoader(FxConcurrencyExample3.class.getResource("MainWindow.fxml"));
            AnchorPane pane = loader.load();

            primaryStage.setMinHeight(400);
            primaryStage.setMinWidth(500);

            //      MainWindowController mainWindowController = loader.getController();
            //      mainWindowController.setMain(this);

            Scene scene = new Scene(pane);

            primaryStage.setScene(scene);
            primaryStage.show();


            startTask();

        }  catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




    public void startTask()
    {
        // Create a Runnable
        Runnable task = new Runnable()
        {
            public void run()
            {
                runTask();
            }
        };

        // Run the task in a background thread
        Thread backgroundThread = new Thread(task);
        // Terminate the running thread if the application exits
        backgroundThread.setDaemon(true);
        // Start the thread
        backgroundThread.start();

    }

    public void runTask()
    {
            try
            {
                // Get the Status


                // Update the Label on the JavaFx Application Thread
                Platform.runLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        controller.ofActuelContent.setText("test");
                        System.out.println("run");
                    }
                });


                Thread.sleep(1000);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }


Die Fehlermeldung ist:

Java:
Feb 09, 2021 11:43:06 AM javafx.fxml.FXMLLoader$ValueElement processValue
WARNING: Loading FXML document with JavaFX API of version 15.0.1 by JavaFX runtime of version 8.0.202-ea
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at tutorial.FxConcurrencyExample3$2.run(FxConcurrencyExample3.java:100)
    at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$3(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)


Was mache ich falsch?
Wie sollte das Grundgerüst aussehen für mein Vorhaben?
Danke für eine Hilfe....
 
Flown

Flown

Administrator
Mitarbeiter
Du übernimmst deinen Controller nicht - daher auch nicht initialisiert - und hast deswegen auch den Controller nicht initialisiert (der gehört beim Loader hinzugefügt).

Zeile: controller.ofActuelContent.setText("test");
 
izoards

izoards

Mitglied
Wow, danke für die rasche Rückmeldung.
hm, also muss ich in der Controller Klasse die initialisation machen? Also in einem Konstruktor?
Oder wie genau muss ich den Controller initialisieren?

Sorry, befasse mich das erste Mal mit GUI und Threads...
 
kneitzel

kneitzel

Top Contributor
Also wenn man mit fxml arbeitet, dann kann man im fxml File angeben, welche Klasse der Controller ist. Und dann erzeugt der Loader den Controller und initialisiert auch Variablen und so ...

Der auskommentierte Part könnte also durchaus schon der korrekte Ansatz sein, d.h. mittels getController den Controller zu bekommen. (Setzt aber voraus, dass das im fxml korrekt gesetzt wurde)

Wenn der Thread zum Windwos gehört, dann würde ich den aber auch innerhalb des Controllers starten. Dann kann er auch deutlich leichter auf den Controller zugreifen.
 
Flown

Flown

Administrator
Mitarbeiter
Normalerweise macht man sowas:
Code:
FXMLLoader loader = FXMLLoader(....);
loader.load();
this.controller = loader.getController(); // This is where the magic happens
 
izoards

izoards

Mitglied
Das wars :) Perfekt Danke vielmals, ich habe schon x-stunden gesucht....

Also mein Ziel ist es, das GUI primär als Anzeige zu verwenden.
Der Background thread, beinhaltet dann einen watchService für zwei Ordner und wird somit "endlos" laufen... und sollte einfach verschiedene Labels im GUI anpassen.

Später sollen dann noch die zu überwachenden Ordner übers GUI gesetzt werden.

Ich hoffe ich bin mit diesem Ansatz auf dem richtigen Weg für meine geplante Applikation...

Was ich noch nicht genau verstehe, ist, wo ich den controller erstellen und initialisieren muss?
Also wenn ich z.B. später in einer WorkerThread - Klasse das gui über den controller anpassen will.
So müsste ich doch in dieser Klasse den controller instanzieren und auch dort initialisieren?

Wenn ich das jedoch machen will, kann er "loader" nicht auflösen:

Java:
public class WorkerThread extends Thread{
    

    MainWindowController controller = new MainWindowController();
    controller = loader.getController();


    public WorkerThread() {
        setDaemon(true);

    }

    @Override
    public void run() {


        while (!this.isInterrupted()) {

            // UI updaten
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    // entsprechende UI Komponente updaten
                    controller.ofActuelContent.setText("------");

                }
            });

            // Thread schlafen
            try {
                // fuer 3 Sekunden
                sleep(TimeUnit.SECONDS.toMillis(3));
            } catch (InterruptedException ex) {
                Logger.getLogger(WorkerThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        }


    }


Wie wäre hier die richtige Vorgehensweise, damit auch aus einer anderen Klasse auf die Labels zugegriffen werden kann?

Danke euch vielmals für die Hilfe :)
 
Flown

Flown

Administrator
Mitarbeiter
Ich will jetzt kein Spielverderber sein, aber ....

... es gibt FileWatcher die das für dich übernehmen können
... wenn du Fragen musst, wie du das mit dem richtigen Scoping/Threading/Initialisierung hinbekommst, dann ist UI Entwicklung noch ein wenig zu hoch und du solltest einen Schritt zurücksteigen
... Du kannst das Property ja eh auf der obersten Ebene halten (MyController controller;) und dann beim Laden eben zuweisen (this.controller = loader.getController())
... Man arbeitet in JavaFX mit Tasks und schon lange greift man keine Threads mehr selbst an (https://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm)
 
izoards

izoards

Mitglied
Dachte mir schon, dass so eine Antwort kommt.
Ich bin tatsächlich noch überhaupt nicht erfahren.
Ich habe jedoch bis jetzt die Funktion, welche im Background laufen sollte hingekriegt und Sie läuft als Windows Service schon ganz gut.
Ich habe mit WatchService gearbeitet... Ich denke das ist dieser FileWatcher? Oder gibt es noch etwas spezifischeres?

Nun muss jedoch doch ein UI hin, darum bin ich nun daran, mich hier schlau zu machen...

Denke, auch, dass ich das mit den Tasks machen sollte mit der javafx.concurrent framework, richtig?
 
izoards

izoards

Mitglied
Trotzdem danke für die Antworten, für ideen, tutorials und beispielcode, bin ich immer sehr froh darüber...
 
kneitzel

kneitzel

Top Contributor
Also generell sollte es so aussehen:
Du hast die Business-Logik mit irgendwelchen Daten unabhängig von jeder Oberfläche. Und dann wird ein Thread nur Daten anpassen im Model und sonst nichts.

Wenn Du dann eine Oberfläche erstellst, dann kümmert die sich nur um das Anzeigen und das Auslösen von Aktionen und so. Aber sie greift nur auf das Model zurück.

Das Model kann z.B. eine Art Event haben, wenn sich Daten ändern (Observer-Pattern). Da könnte dann ein Controller drauf reagieren um z.B. über runLater die Oberfläche anzupassen. Aber die eigentliche Funktionalität solltest Du erst einmal ohner Oberfläche entwickeln (und z.B. über Unit Tests testen).

Und bei der Oberflächen-Entwicklung gibt es dann diverse Pattern: MVC ist das, worauf einige Standard-Bezeichnungen schon hin deuten:Du hast das Model (Business-Logik mit Daten), die View und den Controller. Wobei ich das für Oberflächen als unpassend empfinde - da neige ich eher zum MVVMPattern (mit mvvmFX), aber das geht jetzt hier etwas zu weit. Aber ich hoffe, dass ich Dir ein paar Anregungen liefern konnte.
 
izoards

izoards

Mitglied
Besten Dank, das hilft auf jedenfall.
Also als Model meinst Du die Business logik?

Ich habe es mir eben ein bisschen weniger komplex vorgestellt:

Mein Programm läuft bereits ohne Oberfläche.

Nun habe ich mir ein Beispiel genommen und mir testweise eine kleine Oberfläche gemacht, also mit den bekannten JavaFX Struktur: main, controller und fxml.

Dort rufte ich mein eigentliches Programm auf und wollte die labels anpassen, jedoch friert das GUI ein..
Daher versuche ich nun diese ganze Geschichte mit den beiden Threads..

Ich finde es jedoch schwierig herauszufinden, wie die Verlinkung geschehen muss... Falls es hier ein Beispiel gäbe, um das ganze Grundgerüst zu erkunden, wäre das extrem hilfreich..
Ansonsten setzte ich mich an die Tutorials und werde mir deine Tipps (Observer Pattern) noch genauer ansehen..


PS: Zu beginn, bastelte ich mir einfach ein java swing gui, welches eigentlich soweit die labels anpasst, ohne Controller klasse etc. jedoch war ich mit der ganzen GUI Oberflächen Gestaltung bisschen am hadern, daher wollte ich es jetzt mit javafx und dem scene builder machen...

Macht meine Entscheidung sinn? Oder wäre java swing auch I.O. für mein anliegen?
 
kneitzel

kneitzel

Top Contributor
Also die verwendete Technologie (JavaFX, Swing, SWT, ...) tut sich nichts. Die sind vom Prinzip her relativ ähnlich. Daher ist ein Wechsel eher kontraproduktiv (Da ich davon ausgehe, dass Du einige Punkte bereits verstanden hast. Zumindest hast Du diese gelesen und die Chance ist hoch, dass Du diese dann einordnen kannst, wenn du es brauchst....).

Der Hauptunterschied ist, dass Du jetzt nicht mehr auf irgendwas selbst wartest. Der Benutzer soll machen, was er will und nur bei bestimmten Dingen (Ein Click, ein bestimmter Tastendruck, ...) wirst du kurz (!!) aktiv. Denn die Ausführung macht nur ein Thread und wenn der steht, dann steht alles.

Das ist aber ok, denn in der Regel gibt es nur kurze Dinge zu tun. Und wenn etwas länger dauern könnte: Dann gibst Du das einfach weiter und läßt machen (Du bist sozusagen Boss! Feuerwehr-Einsatz und Du bist Chef! Wenn Du anfängst selbst irgendwas zu machen, dann entgehen Dir wichtige Dinge. Daher nur kurze Dinge machen und ggf. schnell Entscheidungen treffen ....)

Ansonsten kann ich Dir nur empfehlen, uns ruhig ein paar mehr Details mitzuteilen. Ich bin sicher, dass Du hier viele gute Ideen bekommst, wie du bestimmte Dinge machen kannst. Und so entsteht dann evtl. auch schnell ein kleines Beispiel, wie es gehen könnte. Also wenn z.B. das, was derzeit bei Dir hängt, nicht zu groß ist: Poste es doch einmal.
 
izoards

izoards

Mitglied
Das ist aber ok, denn in der Regel gibt es nur kurze Dinge zu tun. Und wenn etwas länger dauern könnte: Dann gibst Du das einfach weiter und läßt machen (Du bist sozusagen Boss! Feuerwehr-Einsatz und Du bist Chef! Wenn Du anfängst selbst irgendwas zu machen, dann entgehen Dir wichtige Dinge. Daher nur kurze Dinge machen und ggf. schnell Entscheidungen treffen ....)
hmm, also in meinem Fall ist es eben ein WatchService, so wie ich ihn gemacht habe, läuft der die ganze Zeit. Also nicht nur kurz was machen und wieder warten bis der User was macht. Wie bereits geschrieben, der User interagiert eigentlich fast nie mit dem GUI, ausser er will die Pfade ändern. Sonst soll das Gui Status Meldungen, Fehlermeldungen und logs anzeigen...

Ansonsten kann ich Dir nur empfehlen, uns ruhig ein paar mehr Details mitzuteilen. Ich bin sicher, dass Du hier viele gute Ideen bekommst, wie du bestimmte Dinge machen kannst. Und so entsteht dann evtl. auch schnell ein kleines Beispiel, wie es gehen könnte. Also wenn z.B. das, was derzeit bei Dir hängt, nicht zu groß ist: Poste es doch einmal.

Sehr gerne, ich bereite mal was vor und stelle es hier rein :) Das hilft mir auf jedenfall sehr...
 
kneitzel

kneitzel

Top Contributor
So ein Service wäre dann ein eigenständiger Thread. Wie man diesen am besten implementiert müsste man sich überlegen. Die meisten Frameworks haben einen Background Worker im Angebot, der sich für sowas oft anbietet. (Bei JavaFX wäre Task wohl die Klasse die sich hier anbieten würde.)
 
izoards

izoards

Mitglied
Ich muss mich mal noch mit diesem Background Worker befassen...
Melde mich mit Code gerne, nachdem ich mich nochmals Schlau gemacht habe...
 
izoards

izoards

Mitglied
Oder vielleicht zeige ich mal, was ich vorhabe:

Das ist die Main Routine, welche das Gui startet. In der Methode mainWindow() wird am Schluss dieser Background-"Task" gestartet, welcher in einem eigenen Task (Thread) laufen sollte. MIt dieser Lösung ist jedoch mein GUI komplett eingefrohren:

Main: startet GUI und "Background-Runner":
package myPackage;

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

import java.io.IOException;
import java.nio.file.*;

public class Main extends Application {

    private Stage primaryStage;



    @Override
    public void start(Stage primaryStage) throws Exception {
        this.primaryStage = primaryStage;
        mainWindow();
    }

    public void mainWindow() {
        try {
            FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
            AnchorPane pane = loader.load();

            primaryStage.setMinHeight(400);
            primaryStage.setMinWidth(500);

            MainWindowController mainWindowController = loader.getController();
            mainWindowController.setMain(this);

            Scene scene = new Scene(pane);

            primaryStage.setScene(scene);
            primaryStage.show();

            Runner runBackground = new Runner();
            runBackground.run(mainWindowController);



        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }





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

    }
}


in meiner "Runner" Klasse, wird dann der WatchService aufgerufen:
Im Moment übergebe ich hier das mainWindowController Objekt, damit ich die Labels auf dem GUI setzen könnte(?!)
(ist vermutlich falsch? Oder wäre das denkbar, falls dieser Runner im Hintergrund auf einem neuen Thread läuft?)

Java:
package myPackage;

import java.nio.file.*;

public class Runner {




    public void run(MainWindowController controller) throws Exception {


            XML_TCP runnerApp = new XML_TCP();

            runnerApp.tryToConnect();


            WatchService watchService = FileSystems.getDefault().newWatchService();
            Path pathIn = Paths.get("C:\\xml\\In");
            Path pathOut = Paths.get("C:\\xml\\Export");

            pathIn.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
            pathOut.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);

            WatchKey key;

            // Hier müssen dann noch die Pfade abgefragt werden! Falls gleich i.o. falls nicht, neuer Watch Service!
            while ((key = watchService.take()) != null) {
                if (key.watchable().equals(pathIn)) {
                    for (WatchEvent<?> event : key.pollEvents()) {
                        runnerApp.watchEventOne(controller);
                    }
                    key.reset();
                } else if (key.watchable().equals(pathOut)) {
                    for (WatchEvent<?> event : key.pollEvents()) {
                        runnerApp.watchEventTwo();
                    }
                    key.reset();
                }

            }
        }


    }


Also das Ziel wäre, Schlussendlich in der Klasse XML_TCP, die GUI Texte anzupassen...

(Das mit den Pfade setzen per GUI überlege ich mir später dann später... wenn ich das Gründgerüst zusammen habe....


Wäre es möglich, diese Runner Klasse in einen neuen Thread (Task) zu packen?
Oder ist diese Struktur bereits nicht so bestPractice?
 
kneitzel

kneitzel

Top Contributor
Also mit
Java:
            Runner runBackground = new Runner();
            runBackground.run(mainWindowController);
erzeugst Du keinen neuen Thread.

Da solltest Du also entweder Task nutzen (der dann mit Thread gestartet werden sollte) oder einen Service. Das wird z.B. hier kurz erläutert:

Im Moment übergebe ich hier das mainWindowController Objekt, damit ich die Labels auf dem GUI setzen könnte(?!)
Also technisch ist das möglich und daher würde ich da nicht von falsch reden. Aber es ist ungeschickt, da du so unnötige Abhängigkeiten einbindest. Du kannst dies aber relativ einfach entkoppeln, daher ist dies nicht zu problematisch.
 
izoards

izoards

Mitglied
Hallo kneitzel,
Dass ich damit keinen nuene Thread starte, ist mir bewusst, das wollte ich nur andeuten, dass ich hier den thread starten möchte ;-)

Oh der Artikel über Task und Services ist super...
Habe soeben versucht diesen in mein Beispiel zu übernehmen, aber klappt nicht so richtig :-(
Meiner Meinung habe ich dasselbe "Setup" wie im Beispiel Code des Artikels.
Jedoch findet er z.B. die start Methode nicht, diese ist ebenfalls nicht ersichtlich im Code des Artikels...

Hier mein Versuch...

Main:
package myPackage;

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

import java.io.IOException;
import java.nio.file.*;

public class Main extends Application {

    private Stage primaryStage;


    @Override
    public void start(Stage primaryStage) throws Exception {
        this.primaryStage = primaryStage;
        mainWindow();

        RunnerService runner = new RunnerService(this);
        runner.start();


    }

    public void mainWindow() {
        try {
            FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
            AnchorPane pane = loader.load();

            primaryStage.setMinHeight(400);
            primaryStage.setMinWidth(500);

            MainWindowController mainWindowController = loader.getController();
            mainWindowController.setMain(this);

            Scene scene = new Scene(pane);

            primaryStage.setScene(scene);
            primaryStage.show();


      //      Runner runBackground = new Runner();
           // runBackground.run(mainWindowController);



        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }





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

    }
}

RunnerService:
package myPackage;

import javafx.concurrent.Task;

import javax.xml.ws.Service;
import java.nio.file.*;


public class RunnerService extends Service<Void> {

    private Main mainApp;

    public RunnerService(Main mainApp) {
        this.mainApp = mainApp;
    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {

            WinFTM_XML_TCP runnerApp = new WinFTM_XML_TCP();

            runnerApp.tryToConnect();


            WatchService watchService = FileSystems.getDefault().newWatchService();
            Path pathIn = Paths.get("C:\\xml\\In");
            Path pathOut = Paths.get("C:\\xml\\WinFTM_Export");

            pathIn.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
            pathOut.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);

            WatchKey key;

            // Hier müssen dann noch die Pfade abgefragt werden! Falls gleich i.o. falls nicht, neuer Watch Service!
            while ((key = watchService.take()) != null) {
                if (key.watchable().equals(pathIn)) {
                    for (WatchEvent<?> event : key.pollEvents()) {
                        runnerApp.watchEventOne(null);
                    }
                    key.reset();
                } else if (key.watchable().equals(pathOut)) {
                    for (WatchEvent<?> event : key.pollEvents()) {
                        runnerApp.watchEventTwo();
                    }
                    key.reset();
                }
                return null;
            }
            return null;
        }
    };
}
}
 
izoards

izoards

Mitglied
Also technisch ist das möglich und daher würde ich da nicht von falsch reden. Aber es ist ungeschickt, da du so unnötige Abhängigkeiten einbindest. Du kannst dies aber relativ einfach entkoppeln, daher ist dies nicht zu problematisch.

Das ding läuft :) jedoch mit dem updaten des GUI's bin ich noch am Rätseln und zwar, habe ich es nun mit der Übergabe des Controllers versucht zu machen.
Dann in der Klasse welche nun im Background-thread läuft, folgende Methode hinzugefügt:

Java:
    private void updateGui(String text, MainWindowController controller) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                controller.setOfActuelContent(text);
            }
        });
    }


Leider bleibt das Programm dann mit folgendem Fehler hängen:

Java:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at myPackage.MainWindowController.setOfActuelContent(MainWindowController.java:43)
    at myPackage.WinFTM_XML_TCP$1.run(WinFTM_XML_TCP.java:459)
    at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$3(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)


Daher meine Frage, wie kann ich das entkoppeln? Hast Du mir hier vielleicht einen Tipp?
 
kneitzel

kneitzel

Top Contributor
Kannst du den Code einmal im Detail zeigen? Wie bringst Du den MainWindowController denn da rein? Und was ist in der Methode setOfActuelContent? Speziell Zeile 43 - denn da kommt die NPE.
 
izoards

izoards

Mitglied
hmm, stimmt, ich bringe den MainWindowController da gar nicht rein...
Habe eine instanz des MainWindowsController gemacht, und übergeben, jedoch funzt das so irgendwie nicht...

Nun,
Gemäss dem Artikel muss das also über eine ObservableList gemacht werden.
Kann ich das so verstehen, dass in meinem Fall im Background Task, diese Liste mit den zu aktualisierenden Texten gefüllt wird, und ich diese dann im "gui" - thread abarbeiten muss?

Oder wie ist das ganze zu verstehen?
 
kneitzel

kneitzel

Top Contributor
Es gibt verschiedene Wege. Der Weg, das so über den Controller zu machen, kann funktionieren, nur eben musst Du die Instanz des Controllers haben. Unabhängig, wie Du die Teile genau verbindest: Du must diese irgendwie miteinander verknüpfen. Daher würde ich als erstes das generelle Problem mit dem aktuellen Ansatz lösen um dann ggf. etwas zu verändern.

Ist eine Art Event, auch ein Methodenaufruf? Oder was versteht man unter Event?
Aus meiner Sicht steht das einfach nur für eine Art Pattern, bei dem beliebige Dritte sich registrieren, informiert zu werden über irgendwelche Dinge. Und ja - unter dem Strich sind das dann einfach nur, dass eine Menge an Elementen gespeichert wird, auf denen bei Bedarf etwas aufgerufen wird. Beispiele sind die typischen Events in der GUI a.la. Methoden wie addXXXListener(XXXEvent)... Gerade mit funktionalen Interfaces kann man da einiges sehr schön machen ....
 
izoards

izoards

Mitglied
Danke für deine rasche Hilfe, so macht es ziemlich spass :)
Habe es mit deiner Hilfe nun hingebracht und zwar wie folgt:

Main:
@Override
    public void start(Stage primaryStage) throws Exception {
        this.primaryStage = primaryStage;
        mainWindow();
       
    }

    public void mainWindow() {
        try {
            FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
            AnchorPane pane = loader.load();

            primaryStage.setMinHeight(400);
            primaryStage.setMinWidth(500);

            MainWindowController mainWindowController = loader.getController();
            mainWindowController.setMain(this);

            Scene scene = new Scene(pane);

            primaryStage.setScene(scene);
            primaryStage.show();


            RunnerService runner = new RunnerService(this, mainWindowController);
            runner.start();

Danach weiter hier:


RunnerService:
public class RunnerService extends Service<Void> {

    private Main mainApp;
    private MainWindowController controller;

    public RunnerService(Main mainApp, MainWindowController controller) {
        this.mainApp = mainApp;
        this.controller = controller;

    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {


            XML_TCP runnerApp = new XML_TCP();
            runnerApp.start(controller);


                return null;
            }
            };
        }


HIer läuft dann das ganze mit WatchService etc....:
public void start(MainWindowController controller) throws Exception {

...
    ....
    ....
    ...
    updateGui("Läuft!", controller);
   
   
    ...
        ....
        ....
       
    }


private void updateGui(String text, MainWindowController controller) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                controller.setOfActuelContent(text);
            }
        });



Puh, habe das Gefühl, dass dies einfacher gehen könnte.....
Oder kann ich das so stehen lassen?

Also die updateGui Methode ist nun noch überhaupt nicht universell einsetzbar. Das funktioniert nun erst mit einem Label...
Hier muss ich nochmals überlegen, wie ich das Universell machen kann....

Aber ich wäre froh, um ein Feedback, ob ich so o.k. unterwegs bin, oder ob dies ein "no go" ist....

Danke :)
 
kneitzel

kneitzel

Top Contributor
Erst einmal schön, dass Du es soweit zum laufen bekommen hast. Das ist auf jeden Fall ein wichtiger Schritt, ehe man es dann ggf. umstrukturieren könnte.

Eine erste Sache, die ich verschieben / ändern würde:
Java:
            RunnerService runner = new RunnerService(this, mainWindowController);
            runner.start();

1. Zum einen wird der erste Parameter nicht verwendet, daher kann der weg. (Oder habe ich da etwas übersehen?)

2. Und dann würde ich das in den Controller verschieben. Dann verschwindet der Code in mainWindow, das den Service startet. (mainWindow ist ein schlechter Name für eine Methode. Da sollte immer ein Verb dabei sein. createMainWindow oder so. Und dann gehört da das Erstellen und Starten eines solchen Services schlicht nicht rein.

3. Wenn die Abhängigkeiten raus sind, dann würde ich Daten vernünftig modellieren. Die können im Service stecken und der Service verändert diese lediglich. Oder er gibt die Daten regelmäßig nach außen...

4. Dann fliegt der Controller aus dem Service raus. Der Service braucht keinen Controller. Der funktioniert ja so. Statt dessen gibt es sowas wie einen Receiver, der Daten empfängt. Das kann ein funktionales Interface sein und dann kann der Controller nach Erzeugung des Services da eine Methode entsprechend bereitstellen. (Das wäre dann z.B. die Nutzung von https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/function/Consumer.html)

Alternative zu 4: Der Controller fliegt raus und der Service hat die Daten intern und diese können von außen zugegriffen werden. Dann gibt es lediglich eine Information nach außen, dass sich die Daten verändert haben. (Also so wie oben, nur die Daten werden nicht mitgegeben beim Aufruf. Statt dessen muss sich der Controller die Daten dann aktiv holen. Dabei ist aber ggf. auf gleichzeitige Zugriffe zu achten! Daher ist die erste Variante schöner.)

Das wären so auf Anhieb die Änderungen, die ich einfließen lassen würde. Und beide Versionen von 4 sind relativ einfach, wenn man voraussetzt, dass es maximal einen Empfänger gibt. Dann braucht man nur ein Consumer<Datenklasse> target; als Instanzvariable mit Setter im Service und immer wenn eine Instanz der Datenklasse erzeugt wurde, wird target.accept(daten) aufgerufen. Im Controller gibt es eine beliebige Methode, die Datenklasse als Parameter hat und die einmalig eingetragen wird (service.setTarget(this::methodeMitBeliebigemNamen); oder wenn Methodenreferenz nicht gewünscht ist, dann halt service.setTarget(d -> methodeMitBeliebigemNamen(d)); ...)

Das einfach einmal als kurze Liste zum Abschluss des Tages ... :)
 
izoards

izoards

Mitglied
guten Morgen kneitzel,
Ich danke dir vielmals für die grosse Hilfe...
werde mich nun an die Punkte setzen, die Du mir zur Verbesserung aufgeführt hast & und moch ggf. wieder melden, ok?

Du hast recht, der Parameter (this) mainApp, wird nicht gebraucht, der ist noch so drin vom Artikel, den du mir geschickt hast...

Im artikel werden ja auch daten vom Service übergeben, stimmt es, dass deine idee hier nochmals anders ist...

Muss mich da in aller ruhe noch an deine Punke setzen :)
 
izoards

izoards

Mitglied
Hallo kneitzel,
Ich habe seit gestern noch nichts geändert, jedoch könnte es sein, dass die System.out.println - Meldungen, mit dieser Variante nicht mehr ausgegeben werden?!
Bin an einem anderen Laptop zur Zeit und hier beobachte ich nun solche Probleme.. Das Label wird hier auch nicht zuverlässig angepasst.

Könnte es gestern nur Zufall gewesen sein, dass es gar noch nicht zuverlässig läuft?
Oder was könnten die Gründe sein, dass die KonsolenMeldungen nicht mehr ausgegeben werden..
Ansonsten wird der Code abgearbeitet...
Danke für die Hilfe...
 
izoards

izoards

Mitglied
Hallo kneitzel,
Ich habe seit gestern noch nichts geändert, jedoch könnte es sein, dass die System.out.println - Meldungen, mit dieser Variante nicht mehr ausgegeben werden?!
Bin an einem anderen Laptop zur Zeit und hier beobachte ich nun solche Probleme.. Das Label wird hier auch nicht zuverlässig angepasst.

Könnte es gestern nur Zufall gewesen sein, dass es gar noch nicht zuverlässig läuft?
Oder was könnten die Gründe sein, dass die KonsolenMeldungen nicht mehr ausgegeben werden..
Ansonsten wird der Code abgearbeitet...
Danke für die Hilfe...
hat sich erübrigt...
 
izoards

izoards

Mitglied
Hallo Kneitzel,

Ich mach mich jetzt mal an die Änderung, wie ich die Daten aus meinem Service ans GUI schicke, ohne den Controller als Parameter zu übergeben.

Du hast dieses hier bereits erklärt:
Das wären so auf Anhieb die Änderungen, die ich einfließen lassen würde. Und beide Versionen von 4 sind relativ einfach, wenn man voraussetzt, dass es maximal einen Empfänger gibt. Dann braucht man nur ein Consumer<Datenklasse> target; als Instanzvariable mit Setter im Service und immer wenn eine Instanz der Datenklasse erzeugt wurde, wird target.accept(daten) aufgerufen. Im Controller gibt es eine beliebige Methode, die Datenklasse als Parameter hat und die einmalig eingetragen wird (service.setTarget(this::methodeMitBeliebigemNamen); oder wenn Methodenreferenz nicht gewünscht ist, dann halt service.setTarget(d -> methodeMitBeliebigemNamen(d)); ...)

Nun nochmals zu meinem besseren Verständnis:

Ist es richtig, dass ich in meinem Hintergrund thread (Service), eben diesen Consumer erstelle. Also so etwas:

Java:
Consumer<String> myGuiData = (String x) -> setGui(x);    //setGui(String x) ist eine Methode vom Controller(?) geht das so?

oder so:?

Java:
Consumer<String> myGuiData = mainWindowController::setGui;     //?geht das so?



Danach, würde ich sobald Daten auf dem GUI aktualisiert werden, diese wie folgt "senden":

Java:
myGuiData.accept(meineStringVariable);

Im Controller gibt es eine beliebige Methode, die Datenklasse als Parameter hat und die einmalig eingetragen wird (service.setTarget(this::methodeMitBeliebigemNamen)
Dann im Controller die Methode so(?):

Java:
public void setGui(String x) {
        label.setText(x);
}

Ich verstehe leider nicht, was das bedeutet:
...die einmalig eingetragen wird (service.setTarget(this::methodeMitBeliebigemNamen)

Auch bin ich mir noch nicht ganz im klaren, was du mit:

....und immer wenn eine Instanz der Datenklasse erzeugt wurde, wird target.accept(daten) aufgerufen.
Die Datenklasse ist in meinem Fall jetzt "myGuiData" richtig?

Danke viemals für die Hilfe...
 
Zuletzt bearbeitet:
izoards

izoards

Mitglied
Komme irgendwie nicht weiter :-(

Das wären so auf Anhieb die Änderungen, die ich einfließen lassen würde. Und beide Versionen von 4 sind relativ einfach, wenn man voraussetzt, dass es maximal einen Empfänger gibt.
Meinst Du mit Empfänger, ein "label" auf dem GUI, oder eine controller klasse?


was ich bis jetzt gemacht habe:

Im Background-Task den Consumer "eingerichtet":

Java:
Consumer<String> myGuiData = (String x) -> setGui(x); // Als Klassenvariable definiert.



myGuiData.accept("Test"));    //Sobald ein Label des Gui's angepasst werden soll,
                            //es gibt verschiedene Labels die angepasst werden müssen



private void setGui(String x) {

        System.out.println("Aktueller String vom Consumer: " + x);

    }

So und wie bringe ich das jetzt in meinen Controller?

Im Controller gibt es eine beliebige Methode, die Datenklasse als Parameter hat...

Java:
    @FXML
    public void beliebigeMethode (String x) {            //String ist meine Datenklasse
        

    }


...und die einmalig eingetragen wird (service.setTarget(this::methodeMitBeliebigemNamen); oder wenn Methodenreferenz nicht gewünscht ist, dann halt service.setTarget(d -> methodeMitBeliebigemNamen(d)); ...)

Wo wird das eingetragen? Wäre riesig dankbar, wenn mir hier jemand auf die Sprünge helfen kann...
 
izoards

izoards

Mitglied
Bin jetzt soweit, dass ich in meinem Background Task folgende setter Methode habe:

Java:
private void setGui(String x) {

        System.out.println("Aktueller String vom Consumer: " + x);
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                newController.setOfActuelContent(x);

            }
        });
    }

Ich erstelle also eine Instanz des controllers im Task und möchte dann dort, über Platform.runLater die Methode des controllers aufrufen.

So vermeide ich die Übergabe des controllers als Parameter....
Denke es wäre auch möglich, hier noch mehrere Parameter zu übergeben, so dass ich im Controller dann entscheiden kann, welches feld aktualisiert werden soll.

Leider stürzt das teil mit einer nullpointer exception ab.

Java:
  @FXML
    public void setOfActuelContent(String text) {
        System.out.println("inside setOfActuelContent: " + text);
        field1.setText(text);
    }


Java:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at myPackage.MainWindowController.setOfActuelContent(MainWindowController.java:93)
    at myPackage.WinFTM_XML_TCP$1.run(WinFTM_XML_TCP.java:502)
    at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$3(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)


Bin ich so auf dem richtigen weg? Also dass ich halt einen controller im Background task erstelle, damit ich so auf die Methoden des controllers zugreifen kann? Oder ist das nicht die richtige Umsetzung der Idee mit dem consumers?
 
kneitzel

kneitzel

Top Contributor
Ich erstelle also eine Instanz des controllers im Task
Das hört sich so nicht korrekt an. Der Controller, den Du im Task erzeugst, ist ja nicht verbunden. An den Controller kommst Du über mehrere Wege:
a) Wenn Du den Task innerhalb des Controllers erzeugst, dann hast Du den Controller in this.
b) Wenn Du mit fxml arbeitest (das @FXML deutet darauf hin), dann kannst Du entweder nach dem Laden den Controller vom FXMLLoader abfragen oder Du erzeugst den Controller und gibst diesen an den Loader. Ich hatte da Probleme mit setController, da ich im fxml auch einen controller angeben möchte. Daher arbeite ich in dem Fall mit setControllerFactory. Das wäre dann sozusagen mehr Richtung Model View Presenter Pattern. Da baut der Controller im Konstruktor auch die Stage:
Java:
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("MyWindow.fxml"));
        loader.setControllerFactory((Class<?> controllerType) -> this);
        Parent root = loader.load();

        // Setup new Window.
        Stage stage = new Stage();
        Scene scene = new Scene(root);
        stage.setTitle(title);
        stage.setScene(scene);
        stage.show();
(Alles etwas verkürzt. title ist ein Parameter für den Fenstertitel. Das Gute bei dem Ansatz: Man kann dem Controller direkt Parameter mitgeben und arbeitet nicht mit setUserObject / getUserObject. Wobei das natürlich auch alles gehen würdemit dem Abfragen des Controllers vom FXMLLoader nach dem Laden des fxml.)

Noch zu der Exception, die Du bekommst:
Die NPE dürfte kommen, da in dem Controller, den Du selbst erzeugt hast, field1 nicht gesetzt ist. Das dürfte ja vom FXMLLoader initialisiert werden und da Du eine neue Instanz erstellt hast, ist das einfach eine weitere Instanz, die mit dem Fenster nichts zu tun hat.
 
kneitzel

kneitzel

Top Contributor
Ach so ja: Aber prinzipiell ist der Ansatz so richtig - Du musst halt nur dafür sorgen, dass Du die richtige Controller Instanz in die Variable von Deinem Task bekommst.
 
looparda

looparda

Bekanntes Mitglied
Wo wird das eingetragen? Wäre riesig dankbar, wenn mir hier jemand auf die Sprünge helfen kann...
Würde es eher andersrum machen, dass dein Service einen Consumer vom Controller übergeben bekommt. Bei Änderungen wird der Consumer aufgerufen.

Java:
private final Consumer<String> changeConsumer;

public RunnerService(Consumer<String> changeConsumer) {
    this.changeConsumer = changeConsumer;
}

...

@Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                              setGui("new value"); 
                              return null;
                        }
                 };
         }    
...

private void setGui(String x) {

        System.out.println("Aktueller String vom Consumer: " + x);
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                changeConsumer.accept(x)
            }
        });
    }

Ich habe mal parallel ein Projekt aufgesetzt und das umgesetzt, was du vermutlich haben möchtest. Ich habe den Service jedoch im Controller erzeugt und binde die Properties des Service direkt an die Felder der UI (Service.html#messageProperty). Dabei sind mir folgende Fragen aufgekommen: Soll der Service immer laufen, oder nur aus einem Controller heraus gestartet werden? Teilen sich mehrere Controller einen Service? Gibt es nur eine Instanz des Service? All das beeinflusst wie (und wann) du deinen Controller und Service erstellst und wie du diese miteinander "verdrahtest", sodass diese miteinander kommunizieren können.
Der Versuch einen Controller im Service zu erstellen ist nicht zielführend. Wenn du Controller mit FXML-Files einsetzt muss man beachten, dass man diese nie per Hand via new erzeugt sondern diese durch die JavaFX Plattform erzeugt werden müssen. Hintergrund ist, dass nur dann die @FXML annotierten Felder initialisiert werden können, die Initialize-Methode des Controllers aufgerufen sowie Location und ResourceBundle gesetzt werden können.
 
izoards

izoards

Mitglied
Ach so ja: Aber prinzipiell ist der Ansatz so richtig - Du musst halt nur dafür sorgen, dass Du die richtige Controller Instanz in die Variable von Deinem Task bekommst.

Also mit dem Controller übergeben in den Background Task und dann über Platform run later funktionierts so wie ich es will. :)
Habe leider keine Zeit mehr, hier "bessere" Lösungen mehr zu entwickeln.
Schaue mir das vermutlich später nochmals in Ruhe an....

Besten Dank für alle Hilfe, ist der Hammer!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
N JavaFX Tableview nach Löschen von Element falscher Index AWT, Swing, JavaFX & SWT 4
J Exception javafx Thread -> caused by removing children while in EventHandler AWT, Swing, JavaFX & SWT 28
T JavaFX DatePicker JavaFX AWT, Swing, JavaFX & SWT 14
J ObjectOutPutStream mit Javafx GUI Elementen AWT, Swing, JavaFX & SWT 14
J Bilder in javafx Project AWT, Swing, JavaFX & SWT 11
rtm007 Videos in JavaFX einbinden AWT, Swing, JavaFX & SWT 1
M JavaFX Fenster in JavaFX öffnen Schliessen (Initialisierung) AWT, Swing, JavaFX & SWT 20
L JavaFX JavaFX AWT, Swing, JavaFX & SWT 1
C JavaFX Projekt nachträglich zu JavaFX Application machen? AWT, Swing, JavaFX & SWT 1
S JavaFX - mit Listener Veränderungen in einer TableView abhören AWT, Swing, JavaFX & SWT 3
R Können Animationen in JavaFX "verschluckt" werden? AWT, Swing, JavaFX & SWT 8
dtr84 JavaFX/OpenJFX mittels Apache Ivy einbinden (Java 11) AWT, Swing, JavaFX & SWT 18
D runnable Jar mit Javafx erstellen(Eclipse) AWT, Swing, JavaFX & SWT 10
Monokuma Blöcke erzeugen (JavaFX) AWT, Swing, JavaFX & SWT 1
P JavaFx - Progressbar - Füllen mittels mehreren Tasks AWT, Swing, JavaFX & SWT 0
Rafael.Cupari JavaFx Installer AWT, Swing, JavaFX & SWT 16
Monokuma Swing zu JavaFX AWT, Swing, JavaFX & SWT 3
C JavaFx sound abspielen AWT, Swing, JavaFX & SWT 3
C JavaFX mit CSS in Eclipse AWT, Swing, JavaFX & SWT 2
parrot JavaFX Fehler AWT, Swing, JavaFX & SWT 4
B JavaFX JavaFX Anwendung deployen (entw als runnableJAR oder exe-Datei) AWT, Swing, JavaFX & SWT 15
N JavaFX applikation auf anderen Systemen zum laufen bringen AWT, Swing, JavaFX & SWT 7
W JavaFX JavaFX - TreeView will nicht AWT, Swing, JavaFX & SWT 8
H JavaFX JavaFX - Scene Builder - BorderPane AWT, Swing, JavaFX & SWT 23
D Columns unabhängig voneinander mit Daten füllen JavaFx AWT, Swing, JavaFX & SWT 1
C JavaFX Installation unter IntelliJ IDEA AWT, Swing, JavaFX & SWT 5
J JavaFX Label aktualisieren AWT, Swing, JavaFX & SWT 18
H JavaFX JavaFX Import Fehler AWT, Swing, JavaFX & SWT 4
M JavaFX javaFX Label-Text wird nicht gesetzt AWT, Swing, JavaFX & SWT 3
T Szene wechselen JavaFX mit If in Main Class AWT, Swing, JavaFX & SWT 2
S JavaFx Zufallsfarbe beim Button-Klick AWT, Swing, JavaFX & SWT 22
M JavaFX JavaFX in mehrere Controller AWT, Swing, JavaFX & SWT 21
R javafx erste application AWT, Swing, JavaFX & SWT 12
kneitzel JavaFX - Binding & Co AWT, Swing, JavaFX & SWT 42
S Alternative JavaFX TableView AWT, Swing, JavaFX & SWT 1
B Game of Life in JavaFX AWT, Swing, JavaFX & SWT 5
B eclipse für JavaFx setuppen AWT, Swing, JavaFX & SWT 4
N JavaFX Chioceboxen verküpfen AWT, Swing, JavaFX & SWT 0
J JavaFX Controls AWT, Swing, JavaFX & SWT 4
S JavaFx AWT, Swing, JavaFX & SWT 2
T JavaFX + Mobile AWT, Swing, JavaFX & SWT 9
JavaTalksToMe JavaFx ExekutorService Problem AWT, Swing, JavaFX & SWT 2
L JavaFX Javafx Dependency-Inversion AWT, Swing, JavaFX & SWT 19
OSchriever JavaFX JavaFX auf Raspberry Pi 4 AWT, Swing, JavaFX & SWT 6
M JavaFX Tab auswählen mit JavaFX AWT, Swing, JavaFX & SWT 9
J JavaFX JavaFX Splitpane - Zugriff auf die Controller der Elemente AWT, Swing, JavaFX & SWT 8
M Java und JavaFX 13 läuft endlich AWT, Swing, JavaFX & SWT 4
N JavaFX Logging des JavaFX Application Threads mit Log4J AWT, Swing, JavaFX & SWT 3
L Java FX JavaFX Effect Attribute ausdrucken AWT, Swing, JavaFX & SWT 1
Hatsi09 JavaFx Mediaplayer seltsames Verhalten AWT, Swing, JavaFX & SWT 0
T JavaFX - Datenübergabe zwischen Scenes AWT, Swing, JavaFX & SWT 8
Zrebna JavaFX-Projekt mit Bildern funktioniert nicht - um Hilfe wird gebeten AWT, Swing, JavaFX & SWT 14
S Kann javafx.scene.layout.VBoxBuilder nicht importieren AWT, Swing, JavaFX & SWT 3
Bluedaishi JavaFX Programm start mit zwei scenen bzw Fenster AWT, Swing, JavaFX & SWT 1
S Jogl und JavaFX AWT, Swing, JavaFX & SWT 6
Bluedaishi JavaFX ProgressBar AWT, Swing, JavaFX & SWT 10
S JavaFX JavaFX TableView scrollen färbt falsche Zeilen AWT, Swing, JavaFX & SWT 1
F JavaFX JavaFX Builden: JavaFX Runtime components are missing AWT, Swing, JavaFX & SWT 0
F JavaFX wirft zufällig Exceptions AWT, Swing, JavaFX & SWT 5
M JavaFX JAVAFX TreeItem mit Tooltip versehen AWT, Swing, JavaFX & SWT 4
techM JavaFX -> CSS AWT, Swing, JavaFX & SWT 5
J JavaFx TableView mit CheckBox AWT, Swing, JavaFX & SWT 4
J JavaFX Stoppuhr mit javafx.timeline AWT, Swing, JavaFX & SWT 2
B Problem mit JavaFX AWT, Swing, JavaFX & SWT 5
O Zukunft von Swing und JavaFX ? AWT, Swing, JavaFX & SWT 3
L JavaFX auf dem PI 4 installieren AWT, Swing, JavaFX & SWT 2
L JavaFX JavaFX Forms mit Groovy starten AWT, Swing, JavaFX & SWT 1
K JavaFX CSS Border (Verschiebung verhindern) AWT, Swing, JavaFX & SWT 4
K JavaFX Element in HBOX nach rechts verschieben AWT, Swing, JavaFX & SWT 2
M error: package javafx.scene.web is not visible import javafx.scene.web.*; AWT, Swing, JavaFX & SWT 16
J import javafx.fxml* bei JavaFX 13 geht nicht mehr AWT, Swing, JavaFX & SWT 7
F Kein JavaFX mehr im Eclipse Wizard AWT, Swing, JavaFX & SWT 1
N Ausführbare Datei aus JavaFX Projekt erstellen AWT, Swing, JavaFX & SWT 22
N Array mit JavaFX Elementen AWT, Swing, JavaFX & SWT 9
S JavaFX Exception in thread "JavaFX Application Thread" AWT, Swing, JavaFX & SWT 3
W JavaFX JavaFX - Spalten auf ganze SpreadsheetView verteilen AWT, Swing, JavaFX & SWT 16
L Label im JavaFX Thread Updaten AWT, Swing, JavaFX & SWT 3
S Erwaege JavaFX Einstieg AWT, Swing, JavaFX & SWT 27
O JavaFX mini Taschenrechner! AWT, Swing, JavaFX & SWT 35
L JavaFX JavaFX, FXML und Guice? AWT, Swing, JavaFX & SWT 0
B JavaFX habe mein Problem fett markiert AWT, Swing, JavaFX & SWT 2
L Javafx Controller Klasse in Maven AWT, Swing, JavaFX & SWT 7
L JavaFX JavaFX stürtzt durch einen Server#connect Exception AWT, Swing, JavaFX & SWT 3
Shallty JavaFX MenuItem (Info) Icon ändern AWT, Swing, JavaFX & SWT 7
E Aktuelle Uhrzeit auf jeder Stage anzeigen lassen (JavaFX) AWT, Swing, JavaFX & SWT 2
temi JavaFX Problem mit IntelliJ und JavaFx 11 unter XUbuntu AWT, Swing, JavaFX & SWT 3
L Java FX Problem mit Ubuntu 18 und JavaFx AWT, Swing, JavaFX & SWT 27
L JavaFX JavaScript im Javafx Webview AWT, Swing, JavaFX & SWT 4
pkm Ich kann JavaFX nicht installieren AWT, Swing, JavaFX & SWT 4
A JavaFX Daten in eine HTML-Table mit JS schreiben AWT, Swing, JavaFX & SWT 3
L JavaFX JavaFX Diagram Editor AWT, Swing, JavaFX & SWT 3
L JavaFX JavaFX Application mit Preloader sauber runterfahren AWT, Swing, JavaFX & SWT 10
K JavaFX funktioniert nicht AWT, Swing, JavaFX & SWT 2
G JavaFX Slider in JavaFX beide Seiten beschriften AWT, Swing, JavaFX & SWT 2
D JavaFX JavaFX Tutorial AWT, Swing, JavaFX & SWT 8
Bluedaishi JavaFX JFoenix TextField KeyEvent AWT, Swing, JavaFX & SWT 2
B JavaFx TreeView mit file system AWT, Swing, JavaFX & SWT 1
Bluedaishi JavaFX Button Image aus Datenbank AWT, Swing, JavaFX & SWT 13
B JavaFx Scene Builder Problem AWT, Swing, JavaFX & SWT 2
H Feste Positionen und Größen in JavaFX AWT, Swing, JavaFX & SWT 1

Ähnliche Java Themen

Anzeige

Neue Themen


Oben