我有一个用于总体设置窗口的主窗口,其中包含一个listview
和所有设置类别。窗口的右侧有一个Anchorpane
,用于在从列表中选择每个类别时为每个类别加载单独的FXML文件。
当一个用户选择一个类别,我需要他们能够编辑右边的设置,切换到另一个类别,并作出更多的改变。然而,如果他们回到第一类,那里所做的改变会持续下去。
我的明显问题是,每次用户更改类别时,FXMLLoader
都会重新加载FXML文件和控制器,将其中的所有控件重置为它们的默认值。
研究:
我找到的唯一解决这个问题的答案是如何在不重新加载FXML文件的情况下使用javafx应用程序控制器?。它提到了对FXML控制器使用单例,但没有解决每次都重新加载FXML文件本身的问题。
如果有人能指出这类设置菜单的基本示例,我会很高兴。
基本上有三种方法可以做到这一点:
设置
),并创建它的单个实例。每次重新加载FXML文件,并将单个实例传递给控制器。将UI中的数据与模型中的数据绑定。这样,当您重新加载FXML时,它将使用相同的数据进行更新。(这是我的首选选项。)initialize()
方法从本地存储的字段或模型更新UI。重新加载FXML文件时,@FXML
-注释字段将被替换,并调用initialize()
方法,用现有数据更新新控件。(这感觉有点做作。从道义上讲,任何名为initialize()
的方法只应该执行一次。但是,这是完全可行的。)假设您有一个模型,它可能如下所示:
public class Settings {
private final UserInfo userInfo ;
private final Preferences prefs ;
private final Appearance appearance ;
public Settings(UserInfo userInfo, Preferences prefs, Appearance appearance) {
this.userInfo = userInfo ;
this.prefs = prefs ;
this.appearance = appearance ;
}
public Settings() {
this(new UserInfo(), new Preferences(), new Appearance());
}
public UserInfo getUserInfo() {
return userInfo ;
}
public Preferences getPreferences() {
return prefs ;
}
public Appearance getAppearance() {
return appearance ;
}
}
和
public class UserInfo {
private final StringProperty name = new SimpleStringProperty() ;
private final StringProperty department = new SimpleStringProperty() ;
// etc...
public StringProperty nameProperty() {
return name ;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
nameProperty().set(name);
}
// etc...
}
(对于首选项
、外观
等类似)
public class UserInfoController {
private final UserInfo userInfo ;
@FXML
private TextField name ;
@FXML
private ComboBox<String> department ;
public UserInfoController(UserInfo userInfo) {
this.userInfo = userInfo ;
}
public void initialize() {
name.textProperty().bindBidirectional(userInfo.nameProperty());
department.valueProperty().bindBidirectional(userInfo.departmentProperty());
}
}
public class MainController {
@FXML
private BorderPane root ;
@FXML
private ListView<String> selector ;
private Settings settings = new Settings() ; // or pass in from somewhere else..
public void initialize() {
selector.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if ("User Information".equals(newSelection)) {
loadScreen("UserInfo.fxml", new UserInfoController(settings.getUserInfo()));
} else if ("Preferences".equals(newSelection)) {
loadScreen("Preferences.fxml", new PreferencesController(settings.getPreferences()));
} else if ("Appearance".equals(newSelection)) {
loadScreen("Appearance.fxml", new AppearanceController(settings.getAppearance()));
} else {
root.setCenter(null);
}
}
private void loadScreen(String resource, Object controller) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(resource));
loader.setController(controller);
root.setCenter(loader.load());
} catch (IOException exc) {
exc.printStackTrace();
root.setCenter(null);
}
}
}
public class UserInfoController {
@FXML
private TextField name ;
@FXML
private ComboBox<String> department ;
private final StringProperty nameProp = new SimpleStringProperty();
private final ObjectProperty<String> departmentProp = new SimpleObjectProperty();
public StringProperty nameProperty() {
return nameProp;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
nameProperty().set(name);
}
public ObjectProperty<String> departmentProperty() {
return departmentProp ;
}
public final String getDepartment() {
return departmentProperty().get();
}
public final void setDepartment(String department) {
departmentProperty().set(department);
}
public void initialize() {
// initialize controls with data currently in properties,
// and ensure changes to controls are written back to properties:
name.textProperty().bindBidirectional(nameProp);
department.valueProperty().bindBidirectional(departmentProp);
}
}
后来呢
public class MainController {
@FXML
private BorderPane root ;
@FXML
private ListView<String> selector ;
private UserInfoController userInfoController = new UserInfoController();
private PreferencesController preferencesController = new PreferencesController();
private AppearanceController appearanceController = new AppearanceController();
public void initialize() {
// initialize controllers with data if necessary...
selector.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
selector.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if ("User Information".equals(newSelection)) {
loadScreen("UserInfo.fxml", userInfoController);
} else if ("Preferences".equals(newSelection)) {
loadScreen("Preferences.fxml", preferencesController);
} else if ("Appearance".equals(newSelection)) {
loadScreen("Appearance.fxml", appearanceController);
} else {
root.setCenter(null);
}
}
}
private void loadScreen(String resource, Object controller) {
// as before...
}
}
这是因为当FXML文件重新加载时,您不创建新的控制器,控制器中的initialize方法使用已经存在的数据更新控件。(请注意调用bindbiredicion
方法的方式。)
第三个选项可以在主控制器中实现,也可以在主fxml文件中实现。要在控制器中实现它,您基本上要做
public class MainController {
@FXML
private BorderPane root ;
@FXML
private ListView<String> selector ;
private Parent userInfo ;
private Parent prefs;
private Parent appearance;
// need controllers to get data later...
private UserInfoController userInfoController ;
private PreferencesController prefsController ;
private AppearanceController appearanceController ;
public void initialize() throws IOException {
FXMLLoader userInfoLoader = new FXMLLoader(getClass().getResource("userInfo.fxml));
userInfo = userInfoLoader.load();
userInfoController = userInfoLoader.getController();
FXMLLoader prefsLoader = new FXMLLoader(getClass().getResource("preferences.fxml));
prefs = prefsLoader.load();
prefsController = prefsLoader.getController();
FXMLLoader appearanceLoader = new FXMLLoader(getClass().getResource("appearance.fxml));
appearance = appearanceLoader.load();
appearanceController = appearanceLoader.getController();
// configure controllers with data if needed...
selector.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if ("User Information".equals(newSelection)) {
root.setCenter(userInfo);
} else if ("Preferences".equals(newSelection)) {
root.setCenter(prefs);
} else if ("Appearance".equals(newSelection)) {
root.setCenter(prefs);
} else {
root.setCenter(null);
}
}
}
}
<!-- imports etc omitted -->
<BorderPane xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.example.MainController">
<left>
<ListView fx:id="selector" />
</left>
<fx:define>
<fx:include fx:id="userInfo" source="UserInfo.fxml" >
</fx:define>
<fx:define>
<fx:include fx:id="prefs" source="Preferences.fxml" >
</fx:define>
<fx:define>
<fx:include fx:id="appearance" source="Appearance.fxml" >
</fx:define>
</BorderPane>
的FXML-injection规则是,用指定的fx:id
(例如UserInfo
)注入所包含的FMXL文件的根(例如UserInfo
),当“controller”
追加到fx:id
(例如UserInfoController
)时,将这些所包含文件的控制器(“嵌套控制器”)注入到具有给定名称的字段中。所以主控制器现在看起来像
public class MainController {
@FXML
private BorderPane root ;
@FXML
private ListView<String> selector ;
@FXML
private Parent userInfo ;
@FXML
private Parent prefs;
@FXML
private Parent appearance;
// need controllers to get data later...
@FXML
private UserInfoController userInfoController ;
@FXML
private PreferencesController prefsController ;
@FXML
private AppearanceController appearanceController ;
public void initialize() {
// configure controllers with data if needed...
selector.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if ("User Information".equals(newSelection)) {
root.setCenter(userInfo);
} else if ("Preferences".equals(newSelection)) {
root.setCenter(prefs);
} else if ("Appearance".equals(newSelection)) {
root.setCenter(prefs);
} else {
root.setCenter(null);
}
}
}
}
问题内容: 目标:实施标准的“设置” GUI窗口。类别位于 ListView左侧,而相应选项位于Pane右侧。 (请忽略具有重复类别的明显错误;仍在处理) 在此处输入图片说明 我有一个用于整体“设置”窗口的主窗口,其中包含 ListView带有所有类别的设置。窗口的右侧 具有AnchorPane, 当从列表中选择一个类别时,用于为每个类别加载单独的FXML文件。 当用户选择类别时,我需要他们能够编
我已经为一个ScreenController类(一个由每个屏幕的单个控制器类扩展的类)创建了一个解决方案,它将处理我的应用程序中的基线屏幕层次结构。 在我的类中,我使用一个函数将另一个FXML文件的内容(加载)添加到当前控制器的当前主播上。 我的问题是: 1) 加载新的FXML时,FXML使用的类(或者更确切地说,特定的控制器)是否也被实例化/加载? 2) 执行此操作时,如果新FXMl的类被实例化
问题内容: 我的.routing.ts文件中有这个 我的文件检查id参数并相应地加载数据。在路由器的早期版本中,如果我从/ page / 4转到/ page / 25,则该页面将“重新加载”并且组件将更新。 现在,当我尝试导航到/ page / X时,其中X是id,它只会第一次加载,然后url会更改,但是组件不会再次“重新加载”。 是否需要传递某些内容以强制重新加载组件并调用ngOnInit事件?
问题内容: 设法获得logstash(1.3.1)以将数据发送到elasticsearch(0.9.5)。 我的logstash conf文件设置是 数据存储在ES中的索引logstash-2013.12.xx下 但是,如果我重新启动logstash,请说第二天-将相同的数据重新加载到新索引中。即使我再次重新启动,索引中的文档计数也会加倍。 好像logstash重新读取数据,ES也在复制文档。 有
问题内容: 我正在建立一个新的由AJAX驱动的网站,其中包含不同的部分。每个部分都需要一组新的Javascript函数才能运行。我宁愿不要一开始就加载每个脚本,因为可能会有很多脚本。 有没有一种方法可以使用AJAX加载新脚本并删除旧脚本(以确保类似的变量名或函数签名不存在兼容性问题)。 谢谢 编辑 -jQuery很好,它不必是老式的Javascript 问题答案: 三件事: 1)是,您可以加载新脚
我已经创建了一个按钮数组(),我想为数组中的所有按钮添加相同的操作侦听器,而不是逐个添加它们。 想象一下,每次我点击屏幕上显示的一个按钮,它就会在数组中打印出该按钮的索引。