Hallo liebe Gemeinde, ich bin Recht neu auf dem Gebiet Java-FX. Ich soll ein TestTool schreiben und das mit Java FX. Ich hatte einfach losgelegt und habe das ganze nach einfachem MVC umgesetzt.Doch meine Ausbilder meinten dann beim ersten Code-Review, sie wollen das man die View einfach austauschen kann, so das man auch Swing als View Implementieren könnte.
Ich habe bisher für die View FXML benutzt.
Ich glaube das man hier das Observer Patter benutzten sollte, kann es aber nicht mit Sicherheit sagen. Die zu Beobachtende View muss doch dann im Controller angemeldet werden. In FXML muss auch ein Controller angegeben werden.Wenn ich den gleichen Controller benutzen würde , hätte ich die FXML ja wieder fest verdrahtet,oder?
Entschuldigt meine schlechte Fragestellung aber besser bekomme ich es gerade nicht beschrieben.
Dein Ausbilder ist offenbar nicht von JavaFX überzeugt. FX mit Swing austauschen... Sorry, aber das ist ein ziemlich bescheuerter Gedanke des Ausbilders. Anders herum wird das gemacht.
Zumal ist mit JavaFX und seiner, wenn man es durchzieht, strikten Trennung von deklarierter GUI (FXML) und Controller, das Prinzip des MVC und MVVM viel einfacher umzusetzen, als mit Swing (in Swing muss man sich halt selbst dran halten und die notwendige Disziplin mittbringen, in JavaFX ist es mit FXMLs eher vorausgesetzt).
Was du machen musst: Implementiere deinen spezifischen in Swing und statt des Inhalts, den du mit dem FXMLLoader in dein Stage - oder übergelagertes UI - einbindest, lädst du deine GUI in einen javafx.embed.swing.SwingNode. (Das Tutorial erklärt eigentlich alles notwendige. Beachte nur, das Swing und JavaFX auf unterschiedlichen Threads laufen - Aktualisierung an vonJavaFX-nach-Swing sind mit SwingUtilities#invokeLater durchzuführen und umgekehrt mit Platform#runLater.)
Noch mal abschliessend: Ich will nicht Swing per se schlecht machen, aber es ist eine veraltete Technologie, die man austauschen sollte. Im Dektop-Java-Bereich ist dort JavaFX der neue Platzhirsch.
JavaFX bietet als eine der wenigen Frameworks überhaupt Interoperability an, um "fremde" Frameworks zu embedden (Swing), oder in diese embedded zu werden (Swing, SWT). Wenn du vom UI-Framework agnostische APIs verwenden musst, wäre das Eclipse e4 Framework oder so wohl eine Wahl - wenn auch eine ziemlich komplexe, die hier jeden Rahmen sprengen würde. Versuche also deine Ausbilder von den Vorzügen von JavaFX zu überzeugen, oder versuche in Erfahrung zu bringen, warum sie diese reichlich Fragwürdige Anforderung stellen.
#edit: Das Observer-Pattern hatt IHMO mit dem variablen Austausch von GUI-Frameworks nichts zu tun. Eher kann man damit sich Hilfestellung für Databinding holen (in FX kannst du ja eine Komponente an eine andere Binden, um z.B. Buttons zu aktivieren, wenn Text in ein Textfeld eingegeben wurde, etc.)
Dein Ausbilder ist offenbar nicht von JavaFX überzeugt. FX mit Swing austauschen... Sorry, aber das ist ein ziemlich bescheuerter Gedanke des Ausbilders. Anders herum wird das gemacht.
Ich hab die Frage eher so verstanden, das Swing nur als Beispiel für eine andere View herhalten musste, gewünscht ist einfach nur Trennung des Codes.
Zur Frage: Teile des Controllers wird man immer auch austauschen müssen. Man sollte einfach drauf achten, dass der Teil minimal ist. zB statt einem großem mehrere kleine Controller, von denen dann einige im Idealfall 'frei' von Verbindungen zur View sind. Dann müsste man nur noch die spezifischen Controller austauschen.
Dein Ausbilder ist offenbar nicht von JavaFX überzeugt. FX mit Swing austauschen... Sorry, aber das ist ein ziemlich bescheuerter Gedanke des Ausbilders. Anders herum wird das gemacht.
Ich finde, das ist ein sehr guter Tipp vom Ausbilder, um den Code möglichst unabhängig vom GUI-Framework zu halten. Der TO hat ja nur im Konjunktiv gesprochen, kann also gut sein, dass die Swing-Umstellung nie kommt. Aber wenn er den Tipp beachtet kann man später einfacher auf den JavaFX-Nachfolger umstellen.
Na ja, falls das Model die View-Komponenten importiert, um sie über Änderungen informieren zu können, hat man ja eine Abhängigkeit. Wenn das Model nur seine registrierten Listener informiert, hat man es auf eine neutrale Schnittstelle reduziert. Insofern finde ich schon, dass es etwas damit zu tun hat.
Bleibt dabei. Ich gebe dir recht, dass man es in seinem Programm verwenden sollte (Strichwort "Zentrales Applikations-Modell"), aber das hat erst einmal nichts mit dem Austausch von Komponenten zu tun.
Ich finde, das ist ein sehr guter Tipp vom Ausbilder, um den Code möglichst unabhängig vom GUI-Framework zu halten. Der TO hat ja nur im Konjunktiv gesprochen, kann also gut sein, dass die Swing-Umstellung nie kommt. Aber wenn er den Tipp beachtet kann man später einfacher auf den JavaFX-Nachfolger umstellen.
Dann sollte man aber eben ein entsprechendes Meta-Framework verwenden. Mein Problem damit ist, dass der TO anscheinend eine reine JavaFX-Anwendung geschrieben hat und eben einen View mit FXML erstellt hat. Und dieser soll nun nach Swing umgeschrieben werden. Jetzt hat er Glück, das das von JavaFX unterstützt wird (dass immer mal wieder Fragen hier im Forum kommen, zeigt aber auch, wie intuitiv das Ganze ist...). Aber einen Frameworkwechsel, nur weil der Ausbilder im schlimmsten Fall mit dem anderen Framework nicht so gut klar kommt (ich weiss, pure Mutmassung), dass finde ich eher blöd und halst dem TO unnötig Arbeit auf, wenn der andere Ansatz schon gut funktioniert.
Übrigens kann man natürlich auch ein Stub-FXML samt Controller schreiben, dass dann den Swing-Teil macht. Dann kann man den einen View gegen den anderen immer noch mit einem einfachen laden eines anderen FXML austauschen und dass sollte es gewesen sein. Wenn aber die Anwendung nur aus einem FXML besteht, dünkt es mich aber eben nach reiner Ausbilder-Faulheit und Unwissen auf deren Seite, was man mit JavaFX so anstellen kann.
Ok. Genug gemeckert für heute. Jetzt gebe ich wieder nur sinnvolle Beiträge von mir. Vielleicht.
Ein Hauptvorteil des Observer-Patterns ist meines Erachtens, die möglichst lose Kopplung der beteiligten Komponenten zu erreichen. Und das ist doch eine wichtige Voraussetzung für Austauschbarkeit.
Wenn aber die Anwendung nur aus einem FXML besteht, dünkt es mich aber eben nach reiner Ausbilder-Faulheit und Unwissen auf deren Seite, was man mit JavaFX so anstellen kann.
Ok. Genug gemeckert für heute. Jetzt gebe ich wieder nur sinnvolle Beiträge von mir. Vielleicht.
Eigentlich will ich nicht zur sehr an deinen Mutmaßungen kritisieren, zumal ich selbst nur spekuliere, aber mir erscheint es etwas weit hergeholt, so etwas Extremes zu vermuten, anstatt einfach anzunehmen, dass es da einen unerfahrenen Auszubildenden gibt, der seine Klassen etwas überfrachtet hat und ein paar erfahrene Ausbilder, die das bemerkt haben und gegensteuern. Das ist doch viel naheliegender.
Ich finde es übrigens auch nicht wichtig, ob die mögliche Swing-Unterstützung nur als Gedankenhilfe gedacht ist oder ob sie tatsächlich programmiert werden soll. Wenn es dem Ausbildungszweck dient ist es doch nicht zu viel verlangt, etwas nur für die Mülltonne zu programmieren. Der gemeinsam genutzte Model- und Controller-Code wird trotzdem besser sein als vorher.
Ein Hauptvorteil des Observer-Patterns ist meines Erachtens, die möglichst lose Kopplung der beteiligten Komponenten zu erreichen. Und das ist doch eine wichtige Voraussetzung für Austauschbarkeit.
Das sage ich doch die Ganze Zeit: Das Pattern ist ok. Die JavaFX-Properties sind prinzipiell auch erst einmal unabhängig vom UI-Framework. Auch wenn sie unter der JavaFX-Package-Truktur eingegliedert sind. Und sie bringen das Ganze Observer-Zeug gleich mit.
Aber: Mein haltloses rumgemeckere über eine Motivation, die ich nicht kenne, zur Seite: Das Observer-Pattern hat erst einmal - ebenfalls Prinzipbedingt - nichts mit dem Austausch des GUI-Frameworks zu tun. Idealerweise schwenkt man halt um und verwendet das selbe Applikations-Model, um auf Events zu hören, wie man es schon beim jeweils anderen UI-Framework gemacht hat.
Idealerweise schwenkt man halt um und verwendet das selbe Applikations-Model, um auf Events zu hören, wie man es schon beim jeweils anderen UI-Framework gemacht hat.
Ok. Weil sich der Kram hier im Kreis dreht, mach ich mal ein Beispiel, um jegliche Diskussion zu beenden.
Nehmen wir als erstes ein Application Model - wir haben also eine einzelne, in die Controler zu injizierende Instanz pro Anwendung. Damit es "Observable" wird können wir verschiedene Frameworks oder Ansätze verwenden. Ich nutze die in JavaFX - und damit sein Java 7 Update <irgendwas> auch in Java allgmein - enthaltene Observalbe-Property-Framework. Weil es recht mächtig ist und es keine Dependencies zu 3rd-Party-Bibliotheken etc. gibt.
Was erhält man damit? Ein Model, auf das man einfach Listener anfügen kann, oder es an andere Properties binden kann. (Wenn dazu nach dem vollständigen Beispiel noch Fragen sind, kann ich die Controller-Klassen dann noch etwas erweitern, damit klar wird, wie das funktioniert.)
Als nächstes brauchen wir ein Interface, dass die Controller implementieren sollten, um auf eine generische Art das Model zu injizieren.
Dann brauchen wir den Content. Dazu hier zwei FXMLs. Einmal pures JavaFX:
HTML:
<?xml version="1.0" encoding="UTF-8"?><!--
Do not edit this file it is generated by e(fx)clipse from ../src/application/SwingInteropFXButton.fxgraph
--><?import java.lang.*?><?import javafx.scene.control.Button?><?import javafx.scene.layout.BorderPane?><BorderPanexmlns:fx="http://javafx.com/fxml"fx:id="root"fx:controller="application.SwingInteropControllerFX"><center><Buttonfx:id="button"text="FX Button"/></center></BorderPane>
Und hier der SwingNode:
HTML:
<?xml version="1.0" encoding="UTF-8"?><!--
Do not edit this file it is generated by e(fx)clipse from ../src/application/SwingInteropSwingButton.fxgraph
--><?import java.lang.*?><?import javafx.embed.swing.SwingNode?><?import javafx.scene.layout.BorderPane?><BorderPanexmlns:fx="http://javafx.com/fxml"fx:id="root"fx:controller="application.SwingInteropControllerSwing"><center><SwingNodefx:id="swingNode"/></center></BorderPane>
Damit es keine Exceptions gibt, muss das SwingInteropModel *vor* der initialize-Methode gesetzt werden. Dies wird in der Main-Klasse wie folgt gelöst (aufbauend auf dem Post *hier*):
Java:
package application;importjavafx.application.Application;importjavafx.fxml.FXMLLoader;importjavafx.scene.Parent;importjavafx.scene.Scene;importjavafx.stage.Stage;publicclassMainSwingInteropextendsApplication{privateSwingInteropModel applicationModel =newSwingInteropModel();@Overridepublicvoidstart(Stage stage)throwsException{
applicationModel.setSomeString("SwingInterop");FXMLLoader loader =newFXMLLoader();
loader.setControllerFactory(this::controllerForClass);
loader.setLocation(getClass().getResource("SwingInteropSwingButton.fxml"));Parent root = loader.load();Scene scene =newScene(root,1200,800);
stage.setScene(scene);
stage.show();}privateObjectcontrollerForClass(Class<?> clazz){try{Object controllerInstance = clazz.newInstance();if(controllerInstance instanceofSwingInteropControllerInterface){((SwingInteropControllerInterface) controllerInstance).setModel(applicationModel);}// controllerInstance#someArbitraryMethodCall if necessary// will be triggered *before* the initialize method!return controllerInstance;}catch(InstantiationException|IllegalAccessException e){
e.printStackTrace();returnnull;}}publicstaticvoidmain(String[] args){launch(args);}}
Damit erreicht man, dass das UI-Framework für einen Teil austauschbar ist, man aber das selbe Pattern für die "Observables" verwendet.
Wie gesagt: Das ist alles machbar und JavaFX gibt einem Mittel und wege, so etwas zu erreichen.
Aber: Es ist und bleibt eine eher weniger gute Idee, ein modernes, durch ein altes Framework auszutauschen. Ganz speziell, wenn die Rahmenanwendung modern ist.
Natürlich kann man argumentieren, mann müsse ja Legacy-Teile integrieren können. Muss man halt abschätzen, ob es einem Wert ist, einen Stil-Bruch innerhalb der Anwendung zu wollen. Denn es wird scwer, Swing wie JavaFX aussehen zu lassen. Andersherum sollte es einfacher sein.
#edit: Um das Beispiel zu testen, entweder mal mit dem einen FXML starten (SwingInteropSwingButton.fxml), oder mit dem anderen (bei mir heisst es SwingInteropFXButton.fxml). Man kann auch noch eine weitere Stage (JavaFX-Fenster) mit dem jeweils anderen starten. Und eventuell als Reaktion auf die Buttons das Modell manipulieren und auf die Änderungen hören.
Was das betrifft hatte ich die Vermutung (das ist jetzt mein Teil der Spekulationen), dass der TO hier eben keine ausreichende Entkopplung hat, so dass sein Model die Views kennen muß. Ich glaube, es gab gar keinen Dissens, sondern nur einen unterschiedlichen Schwerpunkt, was wir in diesem Thread mit Austauschbarkeit meinen. Bei dir scheint die Frage "Wie mache ich ein JafaFX-UI zum Swing-UI?" und bei mir "Wie entkopple ich Model und Views?" im Vordergrund zu stehen.