Возможно ли иметь аккордеон с более чем 1 открытой панелью в JavaFX?
Аккордеон JavaFX с несколькими открытыми стеклами
Ответ 1
Нет, JavaFX 2.2 Accordion может иметь только одну открытую область за раз.
Я создал запрос расширения (JDK-8090554 StackedTitlePanes 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, чтобы содержимое всех ваших расширенных панели могут использоваться, если их площадь переполняет доступную область.
Я создал образцовое решение (значки - это ссылки из: http://www.fasticon.com).
Ответ 2
У меня были несколько разные требования
- Аккордеон либо расширяет, либо управляет пространством вида для встроенных представлений
- Весь вид можно поместить в прокрутку.
- Каждый ящик полностью расширяется до размера всего представления, если аккордеон является фиксированным размером или он расширяется до размера содержимого, если это не фиксированный вид.
Хотя в моем случае я не смог выполнить все 3. и тест 2., я смог придумать следующее исправление:
1) Используйте ScrollPane с VBox внутри, с TitlesWindows внутри. 2) Убедитесь, что для TitledPanes установлено значение VBox.grow = "SOMETIMES" . 3) Добавьте VBox в качестве последнего элемента и установите VBox.vgrow = "ВСЕГДА" - это подталкивает TitlesPanes до минимального размера. Все остальные предоставили примеры кода, если вы хотите использовать 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, что приводит к точному поведению, которое мы хотим.
Здесь я расскажу подробнее: