JavaFX TabPane 选择无法正常工作
JavaFX TabPane selection wont work properly
我有两个带控制器的 *.fxml 表单。第一个是 Window,第二个是 ProductPane。
简化的Window.fxml是:
<BorderPane prefWidth="650.0" prefHeight="450.0" fx:controller="package.WindowController">
<center>
<TabPane fx:id="tabsPane">
<tabs>
<Tab fx:id="productsTab" text="Products"/>
<Tab fx:id="warehouseTab" text="Warehouse"/>
<Tab fx:id="saleTab" text="Sale"/>
</tabs>
</TabPane>
</center>
</BorderPane>
Window.fxml 的控制器:
public class WindowController {
@FXML
private TabPane tabsPane;
@FXML
private Tab productsTab;
@FXML
void initialize() {
sout("Main Window initialization...");
tabsPane.getSelectionModel().selectedIndexProperty().addListener((e, o, n) -> {
sout("Changed to " + n);
});
tabsPane.getSelectionModel().selectedItemProperty().addListener((e, o, n) -> {
sout("New item: " + n);
// Load ProductPane content:
if(n == productsTab) {
try {
Parent p = FXMLLoader.load(getClass().getResource("productPane.fxml"));
n.setContent(p);
} catch(IOException ex) {
ex.printStackTrace();
}
}
});
sout("Select first item...");
tabsPane.getSelectionModel().selectFirst();
// This methods also don't work
// tabsPane.getSelectionModel().clearAndSelect();
// tabsPane.getSelectionModel().select(productTab);
// tabsPane.getSelectionModel().select(0);
}
}
问题是:当我在 main() 中加载 Window.fxml 并启动它时,它出现 window,第一个选项卡为空。
调试输出:
Main Window initialization...
Select first item...
但 ProductPane 未加载且侦听器未调用。如果我在 Window 中的选项卡之间切换,则会触发侦听器并正确加载产品选项卡。
有什么问题?
您向选项卡窗格的 selection 模型添加了一个 ChangeListener
,当然会在 selection 更改时收到通知。默认情况下,第一个选项卡是 selected,因此在添加更改侦听器时,第一个选项卡已经 selected。这意味着当您调用 selectFirst()
时,selection 不会改变(因为您要求 select 已经 selected 的选项卡),因此听众未收到通知。
解决方案有点难看:如果在添加侦听器时 select 编辑了产品选项卡,则只需直接加载产品选项卡内容即可。我会将该代码分解为一个单独的方法以避免重复太多:
@FXML
void initialize() {
System.out.println("Main Window initialization...");
tabsPane.getSelectionModel().selectedIndexProperty().addListener((e, o, n) -> {
System.out.println("Changed to " + n);
});
tabsPane.getSelectionModel().selectedItemProperty().addListener((e, o, n) -> {
System.out.println("New item: " + n);
// Load ProductPane content:
if(n == productsTab) {
loadProductsTab();
}
});
if (tabPane.getSelectionModel().getSelectedItem() == productsTab) {
loadProductsTab();
}
}
private void loadProductsTab() {
try {
Parent p = FXMLLoader.load(getClass().getResource("productPane.fxml"));
productsTab.setContent(p);
} catch(IOException ex) {
ex.printStackTrace();
}
}
如果您发现自己非常需要这种功能,您可能会对 ReactFX 框架感兴趣,它(我认为)具有处理此类情况的内置功能。
我有两个带控制器的 *.fxml 表单。第一个是 Window,第二个是 ProductPane。
简化的Window.fxml是:
<BorderPane prefWidth="650.0" prefHeight="450.0" fx:controller="package.WindowController">
<center>
<TabPane fx:id="tabsPane">
<tabs>
<Tab fx:id="productsTab" text="Products"/>
<Tab fx:id="warehouseTab" text="Warehouse"/>
<Tab fx:id="saleTab" text="Sale"/>
</tabs>
</TabPane>
</center>
</BorderPane>
Window.fxml 的控制器:
public class WindowController {
@FXML
private TabPane tabsPane;
@FXML
private Tab productsTab;
@FXML
void initialize() {
sout("Main Window initialization...");
tabsPane.getSelectionModel().selectedIndexProperty().addListener((e, o, n) -> {
sout("Changed to " + n);
});
tabsPane.getSelectionModel().selectedItemProperty().addListener((e, o, n) -> {
sout("New item: " + n);
// Load ProductPane content:
if(n == productsTab) {
try {
Parent p = FXMLLoader.load(getClass().getResource("productPane.fxml"));
n.setContent(p);
} catch(IOException ex) {
ex.printStackTrace();
}
}
});
sout("Select first item...");
tabsPane.getSelectionModel().selectFirst();
// This methods also don't work
// tabsPane.getSelectionModel().clearAndSelect();
// tabsPane.getSelectionModel().select(productTab);
// tabsPane.getSelectionModel().select(0);
}
}
问题是:当我在 main() 中加载 Window.fxml 并启动它时,它出现 window,第一个选项卡为空。
调试输出:
Main Window initialization...
Select first item...
但 ProductPane 未加载且侦听器未调用。如果我在 Window 中的选项卡之间切换,则会触发侦听器并正确加载产品选项卡。
有什么问题?
您向选项卡窗格的 selection 模型添加了一个 ChangeListener
,当然会在 selection 更改时收到通知。默认情况下,第一个选项卡是 selected,因此在添加更改侦听器时,第一个选项卡已经 selected。这意味着当您调用 selectFirst()
时,selection 不会改变(因为您要求 select 已经 selected 的选项卡),因此听众未收到通知。
解决方案有点难看:如果在添加侦听器时 select 编辑了产品选项卡,则只需直接加载产品选项卡内容即可。我会将该代码分解为一个单独的方法以避免重复太多:
@FXML
void initialize() {
System.out.println("Main Window initialization...");
tabsPane.getSelectionModel().selectedIndexProperty().addListener((e, o, n) -> {
System.out.println("Changed to " + n);
});
tabsPane.getSelectionModel().selectedItemProperty().addListener((e, o, n) -> {
System.out.println("New item: " + n);
// Load ProductPane content:
if(n == productsTab) {
loadProductsTab();
}
});
if (tabPane.getSelectionModel().getSelectedItem() == productsTab) {
loadProductsTab();
}
}
private void loadProductsTab() {
try {
Parent p = FXMLLoader.load(getClass().getResource("productPane.fxml"));
productsTab.setContent(p);
} catch(IOException ex) {
ex.printStackTrace();
}
}
如果您发现自己非常需要这种功能,您可能会对 ReactFX 框架感兴趣,它(我认为)具有处理此类情况的内置功能。