JavaFX TabPane 选项卡不更新位置
JavaFX TabPane tabs don't update position
我注意到在 TabPane
中添加和删除选项卡时,它无法匹配基础列表中选项卡顺序的位置。仅当至少一个选项卡因父项的宽度而完全隐藏时才会发生这种情况。下面是一些复制问题的代码:
public class TabPaneTester extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = sizeScene();
primaryStage.setMinHeight(200);
primaryStage.setWidth(475);
primaryStage.setScene(scene);
primaryStage.show();
}
private Scene sizeScene(){
TabPane tabPane = new TabPane();
tabPane.setTabMinWidth(200);
tabPane.getTabs().addAll(newTabs(3));
Scene scene = new Scene(tabPane);
scene.setOnKeyPressed(e -> tabPane.getTabs().add(1, tabPane.getTabs().remove(0)));
return scene;
}
private static Tab[] newTabs(int numTabs){
Tab[] tabs = new Tab[numTabs];
for(int i = 0; i < numTabs; i++) {
Label label = new Label("Tab Number " + (i + 1));
Tab tab = new Tab();
tab.setGraphic(label);
tabs[i] = tab;
}
return tabs;
}
public static void main(String[] args) {
launch();
}
}
当您按下一个键时,它会删除第一个标签(在索引 0 处)并将其放回索引 1 处,有效地交换前两个标签。但是,当 运行 选项卡实际上并没有在视觉上交换(即使选项卡切换器菜单 确实 切换了它们的位置)。
如果您更改屏幕宽度以包括隐藏的第三个选项卡的像素(将 475 替换为 500),它会按预期工作。关于如何解决这个问题的任何线索?
这确实是一个错误,我在 public JIRA 中找不到它的报告,现在在 https://bugs.openjdk.java.net/browse/JDK-8193495.[=26 中报告了它=]
我所有的分析都是基于TabPaneSkin
中的代码,如果你想看的话。
总结
当您删除然后添加选项卡时会出现问题 "too quickly"。删除选项卡后,将在删除过程中进行异步调用。如果您进行其他更改,例如在异步调用完成之前添加一个选项卡(或至少 "finish enough"),则更改过程会看到窗格处于无效状态。
详情
删除选项卡调用 removeTabs
,概述如下:
- 调用了各种内部清除方法。
- 然后它检查关闭是否应该是动画的。
- 如果是(
GROW
),
- 动画将对
requestLayout
方法的调用排队,该方法本身是异步调用的,
- 并且动画开始(异步)并且方法 returns.
- 如果不是 (
NONE
),
requestLayout
被立即调用,方法 returns.
窗格处于无效状态的时间是从调用 returns 到 requestLayout
returns(在另一个线程上)的时间。这个持续时间等于 requestLayout
的持续时间加上动画的持续时间(如果有的话),即 ANIMATION_SPEED = 150
[ms]。在此期间调用 addTabs
可能会导致不良影响,因为正确添加选项卡所需的数据尚未准备好。
解决方法
在调用之间添加人工暂停:
ObservableList<Tab> tabs = tabPane.getTabs();
PauseTransition p = new PauseTransition(Duration.millis(150 + 20));
scene.setOnKeyPressed(e -> {
Tab remove = tabs.remove(0);
p.setOnFinished(e2 -> tabs.add(1, remove));
p.play();
});
这是对 return 的异步调用的足够时间(不要太快地连续调用 KeyPressed
处理程序,因为删除选项卡的速度会比添加选项卡的速度快)。您可以使用
关闭移除动画
tabPane.setStyle("-fx-close-tab-animation: NONE;");
这允许您减少暂停时间。在我的机器上 15 是安全的(这里你也可以连续快速调用 KeyPressed
处理程序,因为延迟很短)。
可能的修复
tabHeaderArea
上的一些同步。
我注意到在 TabPane
中添加和删除选项卡时,它无法匹配基础列表中选项卡顺序的位置。仅当至少一个选项卡因父项的宽度而完全隐藏时才会发生这种情况。下面是一些复制问题的代码:
public class TabPaneTester extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = sizeScene();
primaryStage.setMinHeight(200);
primaryStage.setWidth(475);
primaryStage.setScene(scene);
primaryStage.show();
}
private Scene sizeScene(){
TabPane tabPane = new TabPane();
tabPane.setTabMinWidth(200);
tabPane.getTabs().addAll(newTabs(3));
Scene scene = new Scene(tabPane);
scene.setOnKeyPressed(e -> tabPane.getTabs().add(1, tabPane.getTabs().remove(0)));
return scene;
}
private static Tab[] newTabs(int numTabs){
Tab[] tabs = new Tab[numTabs];
for(int i = 0; i < numTabs; i++) {
Label label = new Label("Tab Number " + (i + 1));
Tab tab = new Tab();
tab.setGraphic(label);
tabs[i] = tab;
}
return tabs;
}
public static void main(String[] args) {
launch();
}
}
当您按下一个键时,它会删除第一个标签(在索引 0 处)并将其放回索引 1 处,有效地交换前两个标签。但是,当 运行 选项卡实际上并没有在视觉上交换(即使选项卡切换器菜单 确实 切换了它们的位置)。
如果您更改屏幕宽度以包括隐藏的第三个选项卡的像素(将 475 替换为 500),它会按预期工作。关于如何解决这个问题的任何线索?
这确实是一个错误,我在 public JIRA 中找不到它的报告,现在在 https://bugs.openjdk.java.net/browse/JDK-8193495.[=26 中报告了它=]
我所有的分析都是基于TabPaneSkin
中的代码,如果你想看的话。
总结
当您删除然后添加选项卡时会出现问题 "too quickly"。删除选项卡后,将在删除过程中进行异步调用。如果您进行其他更改,例如在异步调用完成之前添加一个选项卡(或至少 "finish enough"),则更改过程会看到窗格处于无效状态。
详情
删除选项卡调用 removeTabs
,概述如下:
- 调用了各种内部清除方法。
- 然后它检查关闭是否应该是动画的。
- 如果是(
GROW
),- 动画将对
requestLayout
方法的调用排队,该方法本身是异步调用的, - 并且动画开始(异步)并且方法 returns.
- 动画将对
- 如果不是 (
NONE
),requestLayout
被立即调用,方法 returns.
- 如果是(
窗格处于无效状态的时间是从调用 returns 到 requestLayout
returns(在另一个线程上)的时间。这个持续时间等于 requestLayout
的持续时间加上动画的持续时间(如果有的话),即 ANIMATION_SPEED = 150
[ms]。在此期间调用 addTabs
可能会导致不良影响,因为正确添加选项卡所需的数据尚未准备好。
解决方法
在调用之间添加人工暂停:
ObservableList<Tab> tabs = tabPane.getTabs();
PauseTransition p = new PauseTransition(Duration.millis(150 + 20));
scene.setOnKeyPressed(e -> {
Tab remove = tabs.remove(0);
p.setOnFinished(e2 -> tabs.add(1, remove));
p.play();
});
这是对 return 的异步调用的足够时间(不要太快地连续调用 KeyPressed
处理程序,因为删除选项卡的速度会比添加选项卡的速度快)。您可以使用
tabPane.setStyle("-fx-close-tab-animation: NONE;");
这允许您减少暂停时间。在我的机器上 15 是安全的(这里你也可以连续快速调用 KeyPressed
处理程序,因为延迟很短)。
可能的修复
tabHeaderArea
上的一些同步。