考虑一个非fx的现有应用程序,我们将其称为Business
。
Business
公开了一个Model
对象,该对象又公开了一些属性。 Model
还接受这些属性的侦听器。
我的问题是有关向该应用程序中添加 JavaFx gui。 GuiApp
显然扩展了javafx.application.Application
,将需要引用Model
对象。
在寻找将非String参数传递给GuiApp
的解决方案时,我发现了几种不同的方法:
静态方法:例如,让Business
中的Model
初始化对GuiApp
的静态引用。可以使用here看到使用静态的一个示例。
JavaFx 9方法:如here所示,您可以在不扩展Application
的情况下启动JavaFx应用程序。
更改工作流程方法:更改现有工作流程以GuiApp
初始化BusinessApp
。可以here看到这种工作流程的一个示例。
还有另一种可行的方法吗?最佳实践 ?
答案 0 :(得分:0)
我将尝试演示一些在Java程序和java-fx程序之间传递引用的不同方法。
我希望它能对将来有类似需求的读者有所帮助。我也希望它可以通过其他解决方案鼓励其他答案。
发布的代码不应被视为正确的实现,而应是旨在阐明不同方法的简短代码。为此,我将介绍一个简单的监听界面:
interface Observe{ void update(int i); }
一个Java类,代表一个退出的业务应用程序:
public class JavaApp {
private Observe observer; private int counter = 0;
JavaApp(Observe observer){ //not null safe
this.observer = observer;
}
void process() {
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
observer.update(counter >=100 ? 0 : ++counter);
}
}, 1000,1000);
}
}
应该添加到现有业务应用程序中的java-fx应用程序,对其进行侦听并用作视图:
public class JavaFxApp extends Application implements Observe{
private Label label;
@Override public void start(Stage stage) {
label = new Label("waiting");
BorderPane pane = new BorderPane(label);
Scene scene = new Scene(pane, 100, 100);
stage.setScene(scene);
stage.show();
}
@Override public void update(int i) {
Platform.runLater(()-> label.setText(String.valueOf(i)));
}
}
我们如何在两个应用程序之间共享引用,在本例中为Observe
实例的引用?
方法1:将start()
方法视为应用程序的入口点(请参阅James_D answer)
如果您想将现有的Java应用程序与java-fx绑定,并使用java-fx Application
作为入口点,这将很简单明了:
public class JavaFxApp extends Application implements Observe{
private Label label;
@Override public void start(Stage stage) {
JavaApp main = new JavaApp(this);
label = new Label("waiting");
BorderPane pane = new BorderPane(label);
Scene scene = new Scene(pane, 100, 100);
stage.setScene(scene);
stage.show();
new Thread(()-> { main.process();}).start(); //launch the business process
}
@Override public void update(int i) {
Platform.runLater(()-> label.setText(String.valueOf(i)));
}
public static void main(String[] args) { launch(); }
}
方法2:使用JavaFX 9 Platform#startup
当您无法使用Application#start
方法作为应用程序的入口点时,这是我发现的最佳解决方案。
如fabians answer所示,从java-fx 9开始,您无需扩展Application
就可以启动。您所需要做的就是修改Java应用程序的main
:
public class JavaApp {
private Observe observer; private int counter = 0;
JavaApp(Observe observer){//not null safe
this.observer = observer;
}
void process() {
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override public void run() {
observer.update(counter >=100 ? 0 : ++counter);
}
}, 1000,1000);
}
public static void main(String[] args) {
JavaFxApp view = new JavaFxApp(); //initialize JavaFx application
JavaApp main = new JavaApp(view);
Platform.startup(() -> {//launch JavaFx application
Stage stage = new Stage();
try {
view.start(stage);
} catch (Exception ex) {ex.printStackTrace();}
});
main.process(); //run business process
}
}
方法3:使用静态成员
例如,在java-fx应用程序中引入一个静态getter:
public class JavaFxApp extends Application {
private static Label label = new Label("waiting");
@Override public void start(Stage stage) {
BorderPane pane = new BorderPane(label);
Scene scene = new Scene(pane, 100, 100);
stage.setScene(scene);
stage.show();
}
static Observe getObserver() {
return JavaFxApp::update;
}
private static void update(int i) {
Platform.runLater(()-> label.setText(String.valueOf(i)));
}
}
并在Java应用程序中使用它:
public class JavaApp {
private Observe observer; private int counter = 0;
JavaApp(Observe observer){//not null safe
this.observer = observer;
}
void process() {
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
observer.update(counter >=100 ? 0 : ++counter);
}
}, 1000,1000);
}
public static void main(String[] args){
new Thread(()-> Application.launch(JavaFxApp.class)).start();
Observe observer = JavaFxApp.getObserver(); //get static observer reference
JavaApp main = new JavaApp(observer);
main.process();
}
}
获取静态引用的更好方法可能是(基于this答案):
public class JavaFxApp extends Application implements Observe{
private static final CountDownLatch latch = new CountDownLatch(1);
private static Observe observer = null;
private Label label;
@Override public void init() {
observer = this;
latch.countDown();
}
@Override public void start(Stage stage){
label = new Label("waiting");
BorderPane pane = new BorderPane(label);
Scene scene = new Scene(pane, 100, 100);
stage.setScene(scene);
stage.show();
}
@Override public void update(int i) {
Platform.runLater(()-> label.setText(String.valueOf(i)));
}
static Observe getObserver() {
try {
latch.await();
} catch (InterruptedException e) { e.printStackTrace(); }
return observer;
}
}