gpt4 book ai didi

java - JavaFX 中选项卡关闭时的双选项卡更改事件

转载 作者:行者123 更新时间:2023-11-30 07:51:37 26 4
gpt4 key购买 nike

我有以下程序:

public class MainClass extends Application {

public static void main(String[] arg) {
launch(arg);
}

@Override
public void start(Stage primaryStage) throws Exception {
TabPane tabPane = new TabPane();
tabPane.getSelectionModel().selectedItemProperty().addListener((ov, oldTab, newTab) -> {
System.out.println("Tab change: " + oldTab + "/" + newTab);
});
Tab tab = new Tab("Test tab");
tab.setOnCloseRequest((event) -> {
System.out.println("Removing tab");
event.consume();
//I need to remove tab manually
tabPane.getTabs().remove(tab);
});
System.out.println("Adding tab");
tabPane.getTabs().add(tab);
Group root = new Group(tabPane);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

}

当我运行它并单击 Tab 上的关闭图标时,程序的输出如下:

Adding tab
Tab change: null/javafx.scene.control.Tab@70b1aa69
Removing tab
Tab change: javafx.scene.control.Tab@70b1aa69/null
Tab change: null/javafx.scene.control.Tab@70b1aa69

如您所见,当我关闭选项卡时,我收到了两个 Tab change 事件,但我只需要一个。如何解决?

最佳答案

有趣的错误 - 很困惑为什么/如何删除的选项卡仍然是选定的选项卡,即使不再在选项卡列表中。

第一个问题是,选择发生的确切位置:这是在 TabHeaderSkin 安装的 mousePressedHandler 中完成的

setOnMousePressed(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent me) {
if (getTab().isDisable()) {
return;
}
if (me.getButton().equals(MouseButton.MIDDLE)) {
if (showCloseButton()) {
Tab tab = getTab();
if (behavior.canCloseTab(tab)) {
removeListeners(tab);
behavior.closeTab(tab);
}
}
} else if (me.getButton().equals(MouseButton.PRIMARY)) {
behavior.selectTab(getTab());
}
}
});

但是:为什么这个处理程序在移除选项卡后仍然处于 Activity 状态(希望它的视觉效果也是如此)?视觉部分的清理是 TabPaneSkin 的任务,它监听选项卡列表并删除 TabHeaderSkin(又名:在其内容上方显示选项卡的组件)。但由于两个原因,清理并没有立即完成:

  • 淡出动画使标题保持 Activity 状态,直到动画准备就绪,这很好
  • header 的内部清理(通过 header.removeListeners 传递消息)不完整,因为它删除了子项和监听器,但未能删除 mouseHandler - 这就是错误。

来自 TabHeaderSkin 的代码:

private void removeListeners(Tab tab) {
listener.dispose();
inner.getChildren().clear();
getChildren().clear();
// following line is missing:
setOnMousePressed(null)
}

一种绕过的方法是在选项卡上注册我们自己的监听器,并强制处理程序在删除时为 null。注意:必须在核心完成工作后通知监听器,因此要么在自定义皮肤中安装,要么在设置 tabPane 的皮肤后安装。

为了说明,我相应地修改了您的示例:

public class TabPaneRemoveSelected extends Application {

public static void main(String[] arg) {
launch(arg);
}

public static class MyTabSkin extends TabPaneSkin {

public MyTabSkin(TabPane pane) {
super(pane);
pane.getTabs().addListener(this::tabsChanged);
}

protected void tabsChanged(Change<? extends Tab> c) {
while (c.next()) {
if (c.wasRemoved()) {
// lookup all TabHeaderSkins
Set<Node> tabHeaders = getSkinnable().lookupAll(".tab");
tabHeaders.stream()
.filter(p -> p instanceof Parent)
.map(p -> (Parent) p)
.forEach(p -> {
// all children removed indicates being in the process
// of being removed
if (p.getChildrenUnmodifiable().size() == 0) {
// complete removeListeners
p.setOnMousePressed(null);
}
}
);

}
}
}

}

@Override
public void start(Stage primaryStage) throws Exception {
TabPane tabPane = new TabPane() {

@Override
protected Skin<?> createDefaultSkin() {
return new MyTabSkin(this);
}

};
tabPane.getSelectionModel().selectedItemProperty().addListener((ov, oldTab, newTab) -> {
System.out.println("Tab change: " + oldTab + "/" + newTab );
});
Tab tab = new Tab("Test tab");
Tab second = new Tab("second");
installHandler(tabPane, tab, second);
installHandler(tabPane, second);
System.out.println("Adding tab");
tabPane.getTabs().addAll(tab, second);
Group root = new Group(tabPane);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

protected void installHandler(TabPane tabPane, Tab... tab) {
for (Tab tab2 : tab) {
tab2.setOnCloseRequest((event) -> {
System.out.println("Removing tab");
event.consume();
//I need to remove tab manually
tabPane.getTabs().remove(tab2);
});

}
}

}

关于java - JavaFX 中选项卡关闭时的双选项卡更改事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46776086/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com