Internal Frames in JavaFX

前端 未结 2 1748
鱼传尺愫
鱼传尺愫 2020-11-29 09:50

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

2条回答
  •  感动是毒
    2020-11-29 10:27

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

提交回复
热议问题