下面是一个说明问题的小应用程序:
ButtonPanel.fxml
<ScrollPane fx:controller="ButtonPanelController">
<VBox>
<Button fx:id="myButton" text="Click Me" onAction="#buttonClickedAction" />
</VBox>
</ScrollPane>
按钮PanelController。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的关系将控制器链接到视图。
我很清楚,尝试将两个视图链接到一个控制器是不好的MVC实践,但是我希望避免实现实际上完全相同的单独FXML和控制器。
有可能实现我上面列出的这种同步吗?
如果我需要创建一个单独的控制器,最好的html" target="_blank">方法是什么来确保两个用户界面同步(甚至是边栏移动)?
提前感谢!
-史蒂夫
代码不起作用的原因是FXML加载器将对FXML中具有fx:id属性的元素的引用注入控制器中具有匹配名称的字段中。因此,当您第一次加载FXML文件时,FXMLLoader将字段myButton设置为加载FXML时创建的按钮的引用。由于第二次加载FXML时使用的是完全相同的控制器实例,因此FXML加载程序现在将同一字段(在同一控制器实例中)设置为对再次加载FXML文件时创建的按钮的引用。换句话说,按钮控制器。myButton现在指的是创建的第二个按钮,而不是第一个。所以当你调用myButton时。设置样式(…)
它更新第二个按钮的样式。
基本上,您总是希望每个视图实例都有一个控制器实例。您需要的是两个控制器访问相同的共享状态。
创建一个存储数据的模型类。在MVC架构中,视图观察模型并在模型中的数据发生变化时更新。控制器对用户与视图的交互做出反应并更新模型。
(可以说,FXML为您提供了更多类似的MVP架构。这也有变体,但通常演示者会观察模型并在模型中的数据发生变化时更新视图,并更新模型以响应用户交互。)
因此,您的模型可能看起来像:
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
public class Model {
private final BooleanProperty red = new SimpleBooleanProperty();
public final BooleanProperty redProperty() {
return this.red;
}
public final boolean isRed() {
return this.redProperty().get();
}
public final void setRed(final boolean red) {
this.redProperty().set(red);
}
public void toggleRed() {
setRed(! isRed() );
}
}
您的ButtonPanel.fxml不会改变:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<ScrollPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="ButtonPanelController">
<VBox >
<Button fx:id="myButton" text="Click Me" onAction="#buttonClickedAction" />
</VBox>
</ScrollPane>
您的控制器有对模型的引用。它可以使用模型属性上的绑定或侦听器来更新UI,处理程序方法只是更新模型:
import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class ButtonPanelController {
@FXML
Button myButton;
boolean isRed = false;
private Model model ;
public ButtonPanelController(Model model) {
this.model = model ;
}
public void initialize() {
myButton.styleProperty().bind(Bindings.
when(model.redProperty()).
then("-fx-background-color: red;").
otherwise("")
);
}
public void buttonClickedAction(ActionEvent event) {
model.toggleRed();
}
}
最后,保持所有内容的同步,因为视图是同一模型的视图。换句话说,您只需创建一个模型并将其引用传递给两个控制器。由于我将模型作为控制器中的构造函数参数(这很好,因为您知道在创建实例后就有了模型),因此我们需要一个控制器工厂来创建控制器实例:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TestApp extends Application {
@Override
public void start(Stage stage) throws Exception {
// 1st Stage
stage.setTitle("1st Stage");
stage.setWidth(200);
stage.setHeight(200);
stage.setResizable(false);
// The one and only model we will use for both views and controllers:
Model model = new Model();
/* Override the ControllerFactory callback to create
* the controller using the model:
*/
Callback<Class<?>, Object> controllerFactory = type -> {
if(type == ButtonPanelController.class) {
return new ButtonPanelController(model);
} else {
try {
return type.newInstance();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
};
// Load FXML
FXMLLoader loader = new FXMLLoader(
ButtonPanelController.class.getResource("ButtonPanel.fxml"));
loader.setControllerFactory(controllerFactory);
Parent root = (Parent) loader.load();
// 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);
// 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);
}
}
93.背景 HBase 中的当前复制异步。因此,如果主集群崩溃,则从集群可能没有最新数据。如果用户想要强一致性,那么他们就无法切换到从属群集。 94.设计 请参阅 HBASE-19064 上的设计文档 95.运行和维护 Case.1 设置两个同步复制集群 在源集群和对等集群中添加同步对等体。 对于源群集: hbase> add_peer '1', CLUSTER_KEY => 'lg-hadoo
问题内容: 我正在使用SpriteKit制作游戏。我有3个viewControllers:选择级别vc,游戏vc和win vc。游戏结束后,我想显示Win vc,然后如果我按Win vc上的“确定”按钮,我想关闭Win vc和游戏vc(将两个视图控制器弹出堆栈)。但我不知道该怎么办,因为如果我打电话 Win vc(堆栈顶部)被关闭了,所以我不知道在哪里再次调用它来关闭游戏vc。有什么方法可以在不使
问题内容: 我开始使用Angular.JS。 我有许多共享同一控制器的视图。每个视图都是收集存储在控制器中的数据的步骤: itemSubmitter控制器: 这是第一个视图: 此方法可以实时更新“您的文本是:”段落。 但是,在加载下一个视图时,将重置为其默认值。如何使存储在控制器实例中的值在视图之间持久化? 问题答案: 更改路线时会布置控制器。这是个好习惯,因为您不应该依赖控制器在视图之间传送数据
在我看来,将myObject序列化为JSON和f的Spring代码将同时尝试在get()返回时访问myObject。除了返回MyObject的深度副本之外,还有什么方法可以防止这种情况发生吗?
问题内容: 因此,我有一个带有按钮的根视图控制器,当用户按下该按钮时,将显示另一个视图控制器。第二个控制器具有一个关闭选项,该选项仅返回到根视图控制器,还有一个按钮,当用户触摸它时,该按钮将关闭当前视图控制器,以便它再次返回到根视图控制器并显示另一个按钮。转到我使用的第一个控制器: 在另一个视图控制器中,我选择仅关闭的按钮,然后执行此操作。 因此,对于需要解雇并显示另一个控制器的第二个控制器,我尝
问题内容: 我没有找到有关此问题的文章,但没有一个解决我的问题。 就像我说的那样。 ViewControllerA ViewControllerB 我试图将添加为的子视图,但是它 抛出类似“ ” 的错误。 下面是代码… ViewControllerA ViewControllerB只是一个带有标签的简单屏幕。 ViewControllerB EDIT 根据用户答案的建议解决方案,ViewCon