是否可以在JavaFX中使用带有1个以上打开窗格的手风琴?
答案 0 :(得分:33)
不,JavaFX 2.2 Accordion一次只能有一个打开的窗格。
我为一个功能创建了一个增强请求(JDK-8090554 StackedTitledPanes control),允许您一次打开手风琴中的多个窗格,但功能请求目前尚未实现。
与此同时,您可以通过创建多个TitledPane实例并将其放在VBox中来轻松构建类似的控件。
private VBox createStackedTitledPanes() {
final VBox stackedTitledPanes = new VBox();
stackedTitledPanes.getChildren().setAll(
new TitledPane("Pane 1", contentNode1),
new TitledPane("Pane 2", contentNode2),
new TitledPane("Pane 3", contentNode3)
);
((TitledPane) stackedTitledPanes.getChildren().get(0)).setExpanded(true);
return stackedTitledPanes;
}
如有必要,您可以将包含您的窗格的VBox
打包到ScrollPane中,以便所有展开的窗格的内容在其区域溢出可用区域时可以使用。
我创建了一个sample solution(图标是来自http://www.fasticon.com的链接软件)。
答案 1 :(得分:0)
我的要求略有不同
虽然在我的情况下,我无法完成全部3.并且测试2.我能够提出以下修复:
1)使用内置VBox的ScrollPane,里面有TitledWindows。 2)确保您的TitledPanes设置为 VBox.grow =“SOMETIMES”。 3)添加一个VBox作为最后一个元素并设置 VBox.vgrow =“ALWAYS” - 这会将TitledPanes推到最小尺寸。其他人都提供了Code示例,如果你想使用fxml,或者不想使用Java,那么直接使用这些元素同样适用(使用SceneBuilder生成):
<ScrollPane fitToHeight="true" fitToWidth="true" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<content>
<VBox fx:id="leftVBox" maxHeight="1.7976931348623157E308" prefHeight="200.0" prefWidth="100.0">
<children>
<TitledPane fx:id="titledPanelOne" animated="false" expanded="false" style="-fx-background-color: red;" text="Pane One" VBox.vgrow="SOMETIMES">
<content>
<ListView fx:id="listViewOne" maxHeight="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" />
</content>
</TitledPane>
<TitledPane fx:id="titledPanelTwo" animated="false" expanded="false" style="-fx-background-color: green;" text="Pane Two" VBox.vgrow="SOMETIMES">
<content>
<ListView fx:id="listViewTwo" maxHeight="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" />
</content>
</TitledPane>
<VBox prefHeight="0.0" prefWidth="0.0" VBox.vgrow="ALWAYS" />
</children>
</VBox>
</content>
</ScrollPane>
4)虽然这确实可以让您堆叠的盒子彼此独立地展开/收缩,但这并不能解决您的盒子没有正确调整其内容大小的问题(例如,如果您嵌入了列表视图如上例所示),所以当你有足够的屏幕空间时,你现在必须滚动很多。解决方案?需要一些Java。
要实现此修复,我们首先将TitledPane的maxHeightProperty()
绑定到外部VBox的heightProperty()
:
public class Controller implements Initializable {
//... controller code
@Override
public void initialize(URL location, ResourceBundle resources) {
//...
variablesViewPane.maxHeightProperty().bind(leftVBox.heightProperty());
historyViewPane.maxHeightProperty().bind(leftVBox.heightProperty());
}
}
我们绑定到每个窗格的expandedProperty()
,并动态绑定和取消绑定prefHeighProperty()
:
private static void bindExpanded(TitledPane pane, ReadOnlyDoubleProperty prop) {
pane.expandedProperty().addListener((observable, oldValue, newValue) -> {
if(newValue) {
pane.prefHeightProperty().bind(prop);
} else {
pane.prefHeightProperty().unbind();
pane.prefHeightProperty().set(0);
}
});
}
如果我们被展示,我们要求与VBox一样大,如果我们没有显示,我们要求尽可能小。以这种方式做事的好处是布局然后根据当前显示的TitledPanes的数量自动计算可用高度 - 这导致了我们想要的行为。
我在这里详细介绍:
答案 2 :(得分:0)
将现有的最佳答案与简化内容结合起来,您可以通过在ScrollPane VBox中创建几个带标题的面板,然后将max-height属性与侦听器绑定来复制多重打开的手风琴(在XML上窗格即使折叠也会保留空间)
<ScrollPane fitToHeight="true" fitToWidth="true">
<AnchorPane id="Content">
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<!-- Setting maxHeight="Infinity" to all makes them all grow as we want, but then they get spaces between, when collapsed (so we do it in code) -->
<TitledPane fx:id="pane1" animated="false" VBox.vgrow="ALWAYS" expanded="false" text="Pane 1">...</TitledPane>
<TitledPane fx:id="pane2" animated="false" VBox.vgrow="ALWAYS" maxHeight="Infinity" text="Pane 2 (starts expanded)">...</TitledPane>
<TitledPane fx:id="pane3" animated="false" VBox.vgrow="ALWAYS" expanded="false" text="Pane 3">...</TitledPane>
</VBox>
</AnchorPane>
</ScrollPane>
注意:您需要为每个窗格调用此方法:
pane1.expandedProperty().addListener((observable, oldValue, newValue) -> {
//make it fill space when expanded but not reserve space when collapsed
if (newValue) {
pane1.maxHeightProperty().set(Double.POSITIVE_INFINITY);
} else {
pane1.maxHeightProperty().set(Double.NEGATIVE_INFINITY);
}
});