Аккордеон JavaFX с несколькими открытыми стеклами - программирование
Подтвердить что ты не робот

Аккордеон JavaFX с несколькими открытыми стеклами

Возможно ли иметь аккордеон с более чем 1 открытой панелью в JavaFX?

4b9b3361

Ответ 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).

fishyfishy

Ответ 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, что приводит к точному поведению, которое мы хотим.

Здесь я расскажу подробнее:

http://sebastianaudet.com/blog/playing-with-javafx/