I am working on making a screen recorder in JavaFX and one utility that is mandatory in the screen recorder is to let the user define how much area to record.
I managed to make an undecorated , semi-transparent Stage
that can be dragged around to define the area and added a close
button to let the user confirm the area which is to be recorded.
Now, how do I let the user resize the stage by dragging it by its edges ?
SSCCE:
package draggable; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Pos; import javafx.geometry.Rectangle2D; import javafx.scene.Scene; import javafx.scene.SceneBuilder; import javafx.scene.control.Button; import javafx.scene.control.ButtonBuilder; import javafx.scene.input.MouseEvent; import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPaneBuilder; import javafx.scene.paint.Color; import javafx.stage.Screen; import javafx.stage.Stage; import javafx.stage.StageStyle; public class DraggableStage extends Application{ Button close; StackPane holder; Rectangle2D maxBounds; Scene theScene; double pressedX; double pressedY; double draggedX; double draggedY; @Override public void start(Stage stage) throws Exception { final Stage theStage = stage; // determine how big the screen is maxBounds = Screen.getPrimary().getVisualBounds(); //create the close button close = ButtonBuilder .create() .text("Close") .build(); //create the StackPane holder for the button holder = StackPaneBuilder .create() .alignment(Pos.CENTER) .children(close) .build(); // you cannot resize the screen beyond the max resolution of the screen holder.setMaxSize(maxBounds.getWidth(), maxBounds.getHeight()); //you cannot resize under half the width and height of the screen holder.setMinSize(maxBounds.getWidth() / 2,maxBounds.getHeight() / 2); //the scene where it all happens theScene = SceneBuilder .create() .root(holder) .width(maxBounds.getWidth() / 2) .height(maxBounds.getHeight() / 2) .build(); // add the button listeners close.setOnAction(new EventHandler<ActionEvent>(){ @Override public void handle(ActionEvent event) { theStage.close(); } }); // add the drag and press listener for the StackPane holder.setOnMousePressed(new EventHandler<MouseEvent>(){ @Override public void handle(MouseEvent e) { pressedX = e.getX(); pressedY = e.getY(); } }); holder.setOnMouseDragged(new EventHandler<MouseEvent>(){ @Override public void handle(MouseEvent e) { draggedX = e.getX(); draggedY = e.getY(); double differenceX = draggedX - pressedX; double differenceY = draggedY - pressedY; theStage.setX(theStage.getX() + differenceX); theStage.setY(theStage.getY() + differenceY); } }); //the mandatory mumbo jumbo theScene.setFill(Color.rgb(128, 128, 128, 0.5)); stage.initStyle(StageStyle.TRANSPARENT); stage.setScene(theScene); stage.sizeToScene(); stage.show(); } public static void main(String[] args) { Application.launch("draggable.DraggableStage"); } }
Image:
I created a ResizeHelper class which can help you in that case, usage:
ResizeHelper.addResizeListener(yourStage);
the helper class:
import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.event.EventType; import javafx.scene.Cursor; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.input.MouseEvent; import javafx.stage.Stage; //created by Alexander Berg public class ResizeHelper { public static void addResizeListener(Stage stage) { ResizeListener resizeListener = new ResizeListener(stage); stage.getScene().addEventHandler(MouseEvent.MOUSE_MOVED, resizeListener); stage.getScene().addEventHandler(MouseEvent.MOUSE_PRESSED, resizeListener); stage.getScene().addEventHandler(MouseEvent.MOUSE_DRAGGED, resizeListener); stage.getScene().addEventHandler(MouseEvent.MOUSE_EXITED, resizeListener); stage.getScene().addEventHandler(MouseEvent.MOUSE_EXITED_TARGET, resizeListener); ObservableList<Node> children = stage.getScene().getRoot().getChildrenUnmodifiable(); for (Node child : children) { addListenerDeeply(child, resizeListener); } } public static void addListenerDeeply(Node node, EventHandler<MouseEvent> listener) { node.addEventHandler(MouseEvent.MOUSE_MOVED, listener); node.addEventHandler(MouseEvent.MOUSE_PRESSED, listener); node.addEventHandler(MouseEvent.MOUSE_DRAGGED, listener); node.addEventHandler(MouseEvent.MOUSE_EXITED, listener); node.addEventHandler(MouseEvent.MOUSE_EXITED_TARGET, listener); if (node instanceof Parent) { Parent parent = (Parent) node; ObservableList<Node> children = parent.getChildrenUnmodifiable(); for (Node child : children) { addListenerDeeply(child, listener); } } } static class ResizeListener implements EventHandler<MouseEvent> { private Stage stage; private Cursor cursorEvent = Cursor.DEFAULT; private int border = 4; private double startX = 0; private double startY = 0; public ResizeListener(Stage stage) { this.stage = stage; } @Override public void handle(MouseEvent mouseEvent) { EventType<? extends MouseEvent> mouseEventType = mouseEvent.getEventType(); Scene scene = stage.getScene(); double mouseEventX = mouseEvent.getSceneX(), mouseEventY = mouseEvent.getSceneY(), sceneWidth = scene.getWidth(), sceneHeight = scene.getHeight(); if (MouseEvent.MOUSE_MOVED.equals(mouseEventType) == true) { if (mouseEventX < border && mouseEventY < border) { cursorEvent = Cursor.NW_RESIZE; } else if (mouseEventX < border && mouseEventY > sceneHeight - border) { cursorEvent = Cursor.SW_RESIZE; } else if (mouseEventX > sceneWidth - border && mouseEventY < border) { cursorEvent = Cursor.NE_RESIZE; } else if (mouseEventX > sceneWidth - border && mouseEventY > sceneHeight - border) { cursorEvent = Cursor.SE_RESIZE; } else if (mouseEventX < border) { cursorEvent = Cursor.W_RESIZE; } else if (mouseEventX > sceneWidth - border) { cursorEvent = Cursor.E_RESIZE; } else if (mouseEventY < border) { cursorEvent = Cursor.N_RESIZE; } else if (mouseEventY > sceneHeight - border) { cursorEvent = Cursor.S_RESIZE; } else { cursorEvent = Cursor.DEFAULT; } scene.setCursor(cursorEvent); } else if(MouseEvent.MOUSE_EXITED.equals(mouseEventType) || MouseEvent.MOUSE_EXITED_TARGET.equals(mouseEventType)){ scene.setCursor(Cursor.DEFAULT); } else if (MouseEvent.MOUSE_PRESSED.equals(mouseEventType) == true) { startX = stage.getWidth() - mouseEventX; startY = stage.getHeight() - mouseEventY; } else if (MouseEvent.MOUSE_DRAGGED.equals(mouseEventType) == true) { if (Cursor.DEFAULT.equals(cursorEvent) == false) { if (Cursor.W_RESIZE.equals(cursorEvent) == false && Cursor.E_RESIZE.equals(cursorEvent) == false) { double minHeight = stage.getMinHeight() > (border*2) ? stage.getMinHeight() : (border*2); if (Cursor.NW_RESIZE.equals(cursorEvent) == true || Cursor.N_RESIZE.equals(cursorEvent) == true || Cursor.NE_RESIZE.equals(cursorEvent) == true) { if (stage.getHeight() > minHeight || mouseEventY < 0) { stage.setHeight(stage.getY() - mouseEvent.getScreenY() + stage.getHeight()); stage.setY(mouseEvent.getScreenY()); } } else { if (stage.getHeight() > minHeight || mouseEventY + startY - stage.getHeight() > 0) { stage.setHeight(mouseEventY + startY); } } } if (Cursor.N_RESIZE.equals(cursorEvent) == false && Cursor.S_RESIZE.equals(cursorEvent) == false) { double minWidth = stage.getMinWidth() > (border*2) ? stage.getMinWidth() : (border*2); if (Cursor.NW_RESIZE.equals(cursorEvent) == true || Cursor.W_RESIZE.equals(cursorEvent) == true || Cursor.SW_RESIZE.equals(cursorEvent) == true) { if (stage.getWidth() > minWidth || mouseEventX < 0) { stage.setWidth(stage.getX() - mouseEvent.getScreenX() + stage.getWidth()); stage.setX(mouseEvent.getScreenX()); } } else { if (stage.getWidth() > minWidth || mouseEventX + startX - stage.getWidth() > 0) { stage.setWidth(mouseEventX + startX); } } } } } } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With