Внутренние фреймы в JavaFX

Я нашел этот пример внутренних фреймов

http://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html

Можно ли сделать такие же внутренние фреймы в JavaFX?


person Peter Penzov    schedule 16.07.2013    source источник
comment
Взгляните на jfxtras.org, у них очень хорошая реализация внутреннего окна. У них есть демо, где вы можете их протестировать.   -  person Antonio J.    schedule 16.07.2013
comment
Я попытался открыть демо-приложение, но безуспешно. Кажется, что JVM 7_25 64 не может запустить эти примеры.   -  person Peter Penzov    schedule 16.07.2013
comment
У меня возникает соблазн сказать, конечно, не о невозможности запуска ... поскольку речь идет о JavaFX и, скорее всего, совместим только с JavaFX 8 (т.е. частью Java 8, включая зависимость от лямбда-выражений и др.)   -  person Terje Dahl    schedule 01.10.2016


Ответы (2)


В JFXtras есть элемент управления Window, где вы можете добавлять контент и управлять внутренним поведением окна.

Сначала вам нужно будет добавить в путь к классам библиотеку jfxtras. У них есть некоторые инструкции, где вы можете получить библиотеку. Если вы используете maven, просто нужно добавить:

<dependency>
    <groupId>org.jfxtras</groupId>
    <artifactId>jfxtras-labs</artifactId>
    <version>2.2-r5</version>
</dependency>

Или загрузите библиотеку и поместите ее в путь к классам вашего проекта, что угодно.

Сейчас выкладываю образец демо окна с небольшим отличием, позволяющим генерировать несколько окон.

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import jfxtras.labs.scene.control.window.CloseIcon;
import jfxtras.labs.scene.control.window.MinimizeIcon;
    import jfxtras.labs.scene.control.window.Window;


public class WindowTests extends Application {
private static int counter = 1;

private void init(Stage primaryStage) {
    final Group root = new Group();

    Button button = new Button("Add more windows");     

    root.getChildren().addAll(button);
    primaryStage.setResizable(false);
    primaryStage.setScene(new Scene(root, 600, 500));

    button.setOnAction(new EventHandler<ActionEvent>() {            
        @Override
        public void handle(ActionEvent arg0) {
            // create a window with title "My Window"
            Window w = new Window("My Window#"+counter);
            // set the window position to 10,10 (coordinates inside canvas)
            w.setLayoutX(10);
            w.setLayoutY(10);
            // define the initial window size
            w.setPrefSize(300, 200);
            // either to the left
            w.getLeftIcons().add(new CloseIcon(w));
            // .. or to the right
            w.getRightIcons().add(new MinimizeIcon(w));
            // add some content
            w.getContentPane().getChildren().add(new Label("Content... \nof the window#"+counter++));
            // add the window to the canvas
            root.getChildren().add(w);  
        }
    });
}

public double getSampleWidth() {return 600;}
public double getSampleHeight() {return 500;}

@Override
public void start(Stage primaryStage) throws Exception {
    init(primaryStage);
    primaryStage.show();


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

В исходной демонстрации код события находился в методе инициализации, а кнопки не было. Добавляю кнопку для динамического создания окон и добавления их на экран.

Вот снимок результата применения:

моментальный снимок

Я настоятельно рекомендую вам попробовать демо-версию jfxtras. У них действительно отличные вещи. Надеюсь, поможет.

person Antonio J.    schedule 17.07.2013
comment
Спасибо за ответ! Какую версию JVM вы используете? - person Peter Penzov; 17.07.2013
comment
Я использовал jdk7u10. Но если установлено более одной версии Java, я не совсем уверен, какая версия будет выполнена. Другой вариант — подождать, пока jfxtras не получит демонстрацию, которая правильно работает с последней версией Java. - person Antonio J.; 17.07.2013
comment
к сведению: я использую jfxtras-controls-9.0-rt, и класс Window не включен - person choff; 02.08.2018
comment
как скрыть заголовок окна?? - person Rawat; 09.04.2020

Вы можете сами реализовать простое внутреннее окно. Основная идея в том, что класс InternalWindow просто скелет, который имеет внутреннюю структуру, похожую на функциональность. Вы можете применить к нему любой контент.

1) Объявить класс

public class InternalWindow extends Region

2) Вы должны иметь возможность устанавливать содержимое в окне

public void setRoot(Node node) {
        getChildren().add(node);
}

3) Вы должны иметь возможность вывести окно на передний план, если существует много окон.

public void makeFocusable() {    
        this.setOnMouseClicked(mouseEvent -> {
            toFront();
        });    
}

4) Теперь нам нужна функция перетаскивания

//just for encapsulation
private static class Delta {
    double x, y;
}

//we can select nodes that react drag event
public void makeDragable(Node what) {
    final Delta dragDelta = new Delta();
    what.setOnMousePressed(mouseEvent -> {
        dragDelta.x = getLayoutX() - mouseEvent.getScreenX();
        dragDelta.y = getLayoutY() - mouseEvent.getScreenY();
        //also bring to front when moving
        toFront();
    });
    what.setOnMouseDragged(mouseEvent -> {
        setLayoutX(mouseEvent.getScreenX() + dragDelta.x);
        setLayoutY(mouseEvent.getScreenY() + dragDelta.y);
    });
}

5) Также мы хотим изменить размер окна (я показываю только простое изменение размера справа внизу)

//current state
private boolean RESIZE_BOTTOM;
private boolean RESIZE_RIGHT;

public void makeResizable(double mouseBorderWidth) {
    this.setOnMouseMoved(mouseEvent -> {
        //local window's coordiantes
        double mouseX = mouseEvent.getX();
        double mouseY = mouseEvent.getY();
        //window size
        double width = this.boundsInLocalProperty().get().getWidth();
        double height = this.boundsInLocalProperty().get().getHeight();
        //if we on the edge, change state and cursor
        if (Math.abs(mouseX - width) < mouseBorderWidth
                && Math.abs(mouseY - height) < mouseBorderWidth) {
            RESIZE_RIGHT = true;
            RESIZE_BOTTOM = true;
            this.setCursor(Cursor.NW_RESIZE);
        } else {
            RESIZE_BOTTOM = false;
            RESIZE_RIGHT = false;
            this.setCursor(Cursor.DEFAULT);
        }

    });
    this.setOnMouseDragged(mouseEvent -> {
        //resize root
        Region region = (Region) getChildren().get(0);
        //resize logic depends on state
        if (RESIZE_BOTTOM && RESIZE_RIGHT) {
            region.setPrefSize(mouseEvent.getX(), mouseEvent.getY());
        } else if (RESIZE_RIGHT) {
            region.setPrefWidth(mouseEvent.getX());
        } else if (RESIZE_BOTTOM) {
            region.setPrefHeight(mouseEvent.getY());
        }
    });
}

6) Использование. Сначала мы строим весь макет. Затем примените его к InternalWindow.

private InternalWindow constructWindow() {
    // content
    ImageView imageView = new ImageView("https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Cheetah4.jpg/250px-Cheetah4.jpg");
    // title bar
    BorderPane titleBar = new BorderPane();
    titleBar.setStyle("-fx-background-color: green; -fx-padding: 3");
    Label label = new Label("header");
    titleBar.setLeft(label);
    Button closeButton = new Button("x");
    titleBar.setRight(closeButton);
    // title bat + content
    BorderPane windowPane = new BorderPane();
    windowPane.setStyle("-fx-border-width: 1; -fx-border-color: black");
    windowPane.setTop(titleBar);
    windowPane.setCenter(imageView);

    //apply layout to InternalWindow
    InternalWindow interalWindow = new InternalWindow();
    interalWindow.setRoot(windowPane);
    //drag only by title
    interalWindow.makeDragable(titleBar);
    interalWindow.makeDragable(label);
    interalWindow.makeResizable(20);
    interalWindow.makeFocusable();
    return interalWindow;
}

7) И как добавить окно в макет

@Override
public void start(Stage primaryStage) throws Exception {
    Pane root = new Pane();
    root.getChildren().add(constructWindow());
    root.getChildren().add(constructWindow());
    primaryStage.setScene(new Scene(root, 300, 275));
    primaryStage.show();
}

Результат

введите здесь описание изображения

Полный код: суть

Обновление о кнопке закрытия:

Вы можете добавить метод в InternalWindow

public void setCloseButton(Button btn) {
    btn.setOnAction(event -> ((Pane) getParent()).getChildren().remove(this));
}

И при построении:

interalWindow.setCloseButton(closeButton);
person zella    schedule 29.04.2015
comment
Я заметил, что кнопка X не имеет никакого действия, связанного с ней - как бы вы удалили внутреннее окно со сцены, когда кнопка нажата? - person Rishi Pochiraju; 07.07.2017