Internal Frames in JavaFX
Asked Answered
R

2

7

I found this example of Internal Frames

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

Is it possible to make the same internal Frames in JavaFX?

Redwood answered 16/7, 2013 at 9:49 Comment(3)
Take a look on jfxtras.org they have an internal window implementation quite good. They have a demo where you can test them.Extracanonical
I tried to open the demo application but with no luck. It seems that JVM 7_25 64 cannot run these examples.Redwood
I am tempted to say "of course not" to the "cannot run ..." seeing as this is about JavaFX, and most likely only compatible with JavaFX 8 (i.e. part of Java 8, including reliance on lambdas et al.)Diluvium
E
11

With JFXtras there is a Window control, where you can add content and handle the internal window behavior.

First you will need to put in your classpath the jfxtras library. They have some instructions where you can get the library. If you are using maven, just need to add:

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

Or download the library and put it into your project classpath, whatever.

Now I put a sample of the demo of the Window with a little difference, allowing generation of several windows.

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);}
}

In the original demo, the event code was in the init method, and no button was included. I add the button to create dynamically windows and adding them to the screen.

Here is a snapshot of the result of the application:

snapshot

I totally recommend you try the demo of jfxtras. They have really great stuff. Hope it helps.

Extracanonical answered 17/7, 2013 at 7:42 Comment(4)
Thank you for the answer! Which version of JVM do you use?Redwood
I've been using jdk7u10. But with more than one version of java installed, I'm not pretty sure which version will executed. The other option is wait until jfxtras get a demo that properly works with the latest java version.Extracanonical
fyi - I'm using jfxtras-controls-9.0-rt and the Window class is not includedTeyde
how to hide title bar of the window??Jolynnjon
M
11

You can implement simple internal window themselves. Main idea, that InternalWindow class just skeleton, that has internal frame like functionality. You can apply any content to it.

1) Declare class

public class InternalWindow extends Region

2) You should be able to set content in window

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

3) You should be able to bring window to front if many window exist

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

4) Now we need dragging functionality

//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) Also we want able to resize window (I show only simple right-bottom resizing)

//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) Usage. First we construct all layout. Then apply it to 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) And how add window to layout

@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();
}

Result

enter image description here

Full code: gist

Upd about close button:

You can add method to InternalWindow

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

And when construct:

interalWindow.setCloseButton(closeButton);
Mantle answered 29/4, 2015 at 23:8 Comment(1)
I noticed that the X button doesn't have any action associated with it - how would you remove the internal window from the stage when the button is pressed?Profiteer

© 2022 - 2024 — McMap. All rights reserved.