Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX accordion with multiple open panes

Is it possible to have an accordion with more then 1 open pane in JavaFX?

like image 563
sight Avatar asked Mar 13 '13 13:03

sight


People also ask

Can you use multiple panes in JavaFX?

The JavaFX SDK provides several layout panes for the easy setup and management of classic layouts such as rows, columns, stacks, tiles, and others. As a window is resized, the layout pane automatically repositions and resizes the nodes that it contains according to the properties for the nodes.

How to add TitledPane JavaFX?

In order to use a JavaFX TitledPane you must first create a TitledPane instance. Here is an example of creating a JavaFX TitledPane : Label label = new Label("The content inside the TitledPane"); TitledPane titledPane = new TitledPane("The Title", label); Notice the second line in the code example.

What is a TitledPane in JavaFX?

A TitledPane is a panel with a title that can be opened and closed. The panel in a TitledPane can be any Node such as UI controls or groups of nodes added to a layout container. It is not recommended to set the MinHeight, PrefHeight, or MaxHeight for this control.


2 Answers

No, a JavaFX 2.2 Accordion can only have one open pane at a time.

I created an enhancement request (JDK-8090554 StackedTitledPanes control) for a feature which allows you to open more than one pane in the accordion at a time, however the feature request has currently not been implemented.

In the meantime, you can construct a similar control yourself quite easily by creating multiple TitledPane instances and placing these in a 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;
}

If necessary, you can wrap the VBox containing your panes in a ScrollPane, so that the contents of all of your expanded panes can be usable if their area overflows the available area.

I created a sample solution (icons are linkware from: http://www.fasticon.com).

fishyfishy

Update

Modernized and inlined the previously externally linked example solution for a scrollable stack of TitledPanes.

Also, note that in a modern JavaFX environment the default styling is a bit different (fewer gradients in by default in things like the TitledPane content background), so it will look slightly different than the prior image in this answer, but otherwise behavior is similar.

import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class StackedPanes extends Application {
    // image license: linkware - backlink to http://www.fasticon.com
    private static final Image BLUE_FISH = new Image("http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Blue-Fish-icon.png");
    private static final Image RED_FISH = new Image("http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Red-Fish-icon.png");
    private static final Image YELLOW_FISH = new Image("http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Yellow-Fish-icon.png");
    private static final Image GREEN_FISH = new Image("http://icons.iconarchive.com/icons/fasticon/fish-toys/128/Green-Fish-icon.png");

    @Override
    public void start(Stage stage) {
        VBox stackedTitledPanes = createStackedTitledPanes();

        ScrollPane scroll = new ScrollPane(stackedTitledPanes);
        scroll.setFitToWidth(true);
        scroll.setFitToHeight(true);
        scroll.setPrefWidth(410);
        scroll.setStyle("-fx-base: cadetblue;");

        stage.setTitle("Fishy, fishy");
        Scene scene = new Scene(scroll);
        stage.setScene(scene);
        stage.show();
    }

    private VBox createStackedTitledPanes() {
        final VBox stackedTitledPanes = new VBox();
        stackedTitledPanes.getChildren().setAll(
                createTitledPane("One Fish", GREEN_FISH),
                createTitledPane("Two Fish", YELLOW_FISH, GREEN_FISH),
                createTitledPane("Red Fish", RED_FISH),
                createTitledPane("Blue Fish", BLUE_FISH)
        );
        ((TitledPane) stackedTitledPanes.getChildren().get(0)).setExpanded(true);

        return stackedTitledPanes;
    }

    public TitledPane createTitledPane(String title, Image... images) {
        FlowPane content = new FlowPane();
        for (Image image : images) {
            ImageView imageView = new ImageView(image);
            content.getChildren().add(imageView);

            FlowPane.setMargin(imageView, new Insets(10));
        }
        content.setAlignment(Pos.TOP_CENTER);

        TitledPane pane = new TitledPane(title, content);
        pane.setExpanded(false);

        return pane;
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
}
like image 193
jewelsea Avatar answered Sep 27 '22 18:09

jewelsea


Combining the best of the existing answers with a simplification, you can replicate a multiple-open accordion by creating several titled panels in a ScrollPane VBox, then binding the max-height property with a listener (to do it on the XML means that the panes would reserve space even when collapsed)

<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>

Note: You'll need to callthis method for each pane:

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);
    }
 });
like image 31
Nick Cardoso Avatar answered Sep 27 '22 18:09

Nick Cardoso