【发布时间】:2016-03-04 20:45:54
【问题描述】:
下面是一个说明问题的小应用程序:
ButtonPanel.fxml
<ScrollPane fx:controller="ButtonPanelController">
<VBox>
<Button fx:id="myButton" text="Click Me" onAction="#buttonClickedAction" />
</VBox>
</ScrollPane>
ButtonPanelController.java
public class ButtonPanelController {
@FXML
Button myButton;
boolean isRed = false;
public void buttonClickedAction(ActionEvent event) {
if(isRed) {
myButton.setStyle("");
} else {
myButton.setStyle("-fx-background-color: red");
}
isRed = !isRed;
}
}
TestApp.java
public class TestApp extends Application {
ButtonPanelController buttonController;
@Override
public void start(Stage stage) throws Exception {
// 1st Stage
stage.setTitle("1st Stage");
stage.setWidth(200);
stage.setHeight(200);
stage.setResizable(false);
// Load FXML
FXMLLoader loader = new FXMLLoader(
ButtonPanelController.class.getResource("ButtonPanel.fxml"));
Parent root = (Parent) loader.load();
// Grab the instance of ButtonPanelController
buttonController = loader.getController();
// Show 1st Scene
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
// 2nd Stage
Stage stage2 = new Stage();
stage2.setTitle("2nd Stage");
stage2.setWidth(200);
stage2.setHeight(200);
stage2.setResizable(false);
/* Override the ControllerFactory callback to use
* the stored instance of ButtonPanelController
* instead of creating a new one.
*/
Callback<Class<?>, Object> controllerFactory = type -> {
if(type == ButtonPanelController.class) {
return buttonController;
} else {
try {
return type.newInstance();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
};
// Load FXML
FXMLLoader loader2 = new FXMLLoader(
ButtonPanelController.class.getResource("ButtonPanel.fxml"));
// Set the ControllerFactory before the load takes place
loader2.setControllerFactory(controllerFactory);
Parent root2 = (Parent) loader2.load();
// Show 2nd Scene
Scene scene2 = new Scene(root2);
stage2.setScene(scene2);
stage2.show();
}
public static void main(String[] args) {
launch(args);
}
}
基本上,我有一个 FXML 用于两个单独的场景,这两个场景可能会或可能不会同时在屏幕上处于活动状态。这方面的一个实际示例是将内容停靠到侧面板加上一个按钮,该按钮在可以拖动/调整大小/等的单独窗口中打开相同内容。
我想要实现的目标是保持视图同步(其中一个视图的更改会影响另一个视图)。
我可以通过回调将两个视图指向同一个控制器,但是我现在遇到的问题是 UI 更改仅反映在第二个场景中。两个视图都与控制器对话,但控制器只与第二个场景对话。我假设 JavaFX 的 MVC 或 IOC 实现在通过 FXMLLoader 加载控制器时以某种 1:1 的关系将控制器链接到视图。
我很清楚尝试将两个视图链接到 1 个控制器是不好的 MVC 做法,但是我想避免必须实现实际上相同的单独 FXML 和控制器。
是否可以实现我上面列出的这种同步?
如果我需要创建一个单独的控制器,确保两个 UI 同步(甚至是侧边栏移动)的最佳方式是什么?
提前致谢!
-史蒂夫
【问题讨论】:
-
对您的问题的简短回答是,MVC 应用程序中的状态不应存储在控制器中,而应存储在模型中。你遇到了麻烦,因为你似乎没有模型......如果我有时间,我会发布一个正确的答案,但这是一般要点。
-
“我假设 JavaFX 的 MVC 或 IOC 实现在通过 FXMLLoader 加载时以某种 1:1 的关系将控制器链接到视图。”你只是想多了。
ButtonPanelController定义了一个名为myButton的字段,这意味着每个ButtonPanelController实例都有一个对按钮的引用。由于您只允许一个这样的实例,因此您只有一个按钮引用。但是,您在 UI 中有两个按钮。一个引用不可能同时引用两个不同的对象。
标签: java model-view-controller javafx fxml