├── Executable └── ImageCropper.jar ├── LICENCE ├── README.md └── Source Code ├── Main.java └── ResizableRectangle.java /Executable/ImageCropper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgeself/JavaFX-ImageCropper/ac1c79ff539520484118534b586f47b62463b4c7/Executable/ImageCropper.jar -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 karakullukcuhuseyin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaFX-ImageCropper 2 | 3 | Simple image cropper, using Java and JavaFX GUI lib. 4 | Created for cropping screenshot images. 5 | 6 | # Instructions 7 | Download ImageCropper.jar in executable folder and run it. 8 | Click "File"and open image by clicking "Open". 9 | Than click "Options" and select "Select Area", click and drag mouse to select area, after that click "Crop". 10 | New window pops up your cropped image in it. If okay click "File" and save image. Simple is that. 11 | 12 | # Develop Requirements 13 | Java 8 (JavaFX 8 built in Java 8) 14 | -------------------------------------------------------------------------------- /Source Code/Main.java: -------------------------------------------------------------------------------- 1 | import java.awt.Graphics2D; 2 | import java.awt.image.BufferedImage; 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | 6 | import javax.imageio.ImageIO; 7 | 8 | import javafx.application.Application; 9 | import javafx.embed.swing.SwingFXUtils; 10 | import javafx.event.EventHandler; 11 | import javafx.geometry.Bounds; 12 | import javafx.geometry.Rectangle2D; 13 | import javafx.scene.Group; 14 | import javafx.scene.Scene; 15 | import javafx.scene.SnapshotParameters; 16 | import javafx.scene.control.Menu; 17 | import javafx.scene.control.MenuBar; 18 | import javafx.scene.control.MenuItem; 19 | import javafx.scene.control.ScrollPane; 20 | import javafx.scene.image.Image; 21 | import javafx.scene.image.ImageView; 22 | import javafx.scene.image.WritableImage; 23 | import javafx.scene.input.MouseEvent; 24 | import javafx.scene.layout.BorderPane; 25 | import javafx.scene.paint.Color; 26 | import javafx.scene.paint.Paint; 27 | import javafx.scene.shape.Rectangle; 28 | import javafx.stage.FileChooser; 29 | import javafx.stage.FileChooser.ExtensionFilter; 30 | import javafx.stage.Stage; 31 | 32 | 33 | public class Main extends Application { 34 | 35 | private static final String APPLICATION_NAME = "ImageCropper"; 36 | private ImageView mainImageView; 37 | private Image mainImage; 38 | private boolean isAreaSelected = false; 39 | 40 | public static void main(String[] args) { 41 | launch(args); 42 | } 43 | 44 | @Override 45 | public void start(Stage primaryStage) throws Exception { 46 | primaryStage.setTitle(APPLICATION_NAME); 47 | primaryStage.setResizable(true); 48 | 49 | final BorderPane borderPane = new BorderPane(); 50 | final ScrollPane rootPane = new ScrollPane(); 51 | final Scene scene = new Scene(borderPane, 800, 800); 52 | mainImageView = new ImageView(); 53 | final AreaSelection areaSelection = new AreaSelection(); 54 | final Group selectionGroup = new Group(); 55 | final MenuBar menuBar = new MenuBar(); 56 | 57 | final Menu menu1 = new Menu("File"); 58 | final Menu menu2 = new Menu("Options"); 59 | 60 | final MenuItem open = new MenuItem("Open"); 61 | final MenuItem clear = new MenuItem("Clear"); 62 | menu1.getItems().addAll(open,clear); 63 | clear.setOnAction(event -> { 64 | clearSelection(selectionGroup); 65 | mainImageView.setImage(null); 66 | System.gc(); 67 | }); 68 | 69 | final MenuItem select = new MenuItem("Select Area"); 70 | menu2.getItems().add(select); 71 | select.setOnAction(event -> areaSelection.selectArea(selectionGroup)); 72 | 73 | final MenuItem crop = new MenuItem("Crop"); 74 | menu2.getItems().add(crop); 75 | crop.setOnAction(event -> { 76 | if (isAreaSelected) 77 | cropImage(areaSelection.selectArea(selectionGroup).getBoundsInParent(),mainImageView); 78 | }); 79 | 80 | open.setOnAction(event -> { 81 | FileChooser fileChooser = new FileChooser(); 82 | fileChooser.setTitle("Open Image file"); 83 | fileChooser.getExtensionFilters().addAll( 84 | new ExtensionFilter("Image Files", "*.png", "*.jpg")); 85 | File selectedFile = fileChooser.showOpenDialog(primaryStage); 86 | if (selectedFile != null) { 87 | clearSelection(selectionGroup); 88 | mainImage = convertFileToImage(selectedFile); 89 | mainImageView.setImage(mainImage); 90 | changeStageSizeImageDimensions(primaryStage,mainImage); 91 | } 92 | }); 93 | 94 | final MenuItem clearSelectionItem = new MenuItem("Clear Selection"); 95 | menu2.getItems().add(clearSelectionItem); 96 | clearSelectionItem.setOnAction(event -> clearSelection(selectionGroup)); 97 | 98 | selectionGroup.getChildren().add(mainImageView); 99 | rootPane.setContent(selectionGroup); 100 | borderPane.setCenter(rootPane); 101 | menuBar.getMenus().addAll(menu1,menu2); 102 | borderPane.setTop(menuBar); 103 | primaryStage.setScene(scene); 104 | primaryStage.show(); 105 | } 106 | 107 | private void cropImage(Bounds bounds, ImageView imageView) { 108 | 109 | int width = (int) bounds.getWidth(); 110 | int height = (int) bounds.getHeight(); 111 | 112 | SnapshotParameters parameters = new SnapshotParameters(); 113 | parameters.setFill(Color.TRANSPARENT); 114 | parameters.setViewport(new Rectangle2D(bounds.getMinX(), bounds.getMinY(), width, height)); 115 | 116 | WritableImage wi = new WritableImage(width, height); 117 | Image croppedImage = imageView.snapshot(parameters, wi); 118 | 119 | showCroppedImageNewStage(wi, croppedImage); 120 | } 121 | 122 | private void showCroppedImageNewStage(WritableImage wi, Image croppedImage) { 123 | final Stage croppedImageStage = new Stage(); 124 | croppedImageStage.setResizable(true); 125 | croppedImageStage.setTitle("Cropped Image"); 126 | changeStageSizeImageDimensions(croppedImageStage,croppedImage); 127 | final BorderPane borderPane = new BorderPane(); 128 | final MenuBar menuBar = new MenuBar(); 129 | final Menu menu1 = new Menu("File"); 130 | final MenuItem save = new MenuItem("Save"); 131 | save.setOnAction(event -> saveCroppedImage(croppedImageStage,wi)); 132 | menu1.getItems().add(save); 133 | menuBar.getMenus().add(menu1); 134 | borderPane.setTop(menuBar); 135 | borderPane.setCenter(new ImageView(croppedImage)); 136 | final Scene scene = new Scene(borderPane); 137 | croppedImageStage.setScene(scene); 138 | } 139 | 140 | private void saveCroppedImage(Stage stage, WritableImage wi) { 141 | FileChooser fileChooser = new FileChooser(); 142 | fileChooser.setTitle("Save Image"); 143 | fileChooser.setInitialFileName("cats.png"); 144 | 145 | File file = fileChooser.showSaveDialog(stage); 146 | if (file == null) 147 | return; 148 | 149 | Runnable runnable = () -> { 150 | BufferedImage bufImageARGB = SwingFXUtils.fromFXImage(wi, null); 151 | BufferedImage bufImageRGB = new BufferedImage(bufImageARGB.getWidth(), 152 | bufImageARGB.getHeight(), BufferedImage.BITMASK); 153 | 154 | Graphics2D graphics = bufImageRGB.createGraphics(); 155 | graphics.drawImage(bufImageARGB, 0, 0, null); 156 | 157 | try { 158 | ImageIO.write(bufImageRGB, "png", file); 159 | } catch (Exception e) { 160 | e.printStackTrace(); 161 | } finally { 162 | graphics.dispose(); 163 | System.gc(); 164 | } 165 | }; 166 | 167 | Thread thread = new Thread(runnable); 168 | thread.start(); 169 | stage.close(); 170 | } 171 | 172 | private void clearSelection(Group group) { 173 | //deletes everything except for base container layer 174 | isAreaSelected = false; 175 | group.getChildren().remove(1,group.getChildren().size()); 176 | 177 | } 178 | 179 | private void changeStageSizeImageDimensions(Stage stage, Image image) { 180 | if (image != null) { 181 | stage.setMinHeight(250); 182 | stage.setMinWidth(250); 183 | stage.setWidth(image.getWidth()+4); 184 | stage.setHeight(image.getHeight()+56); 185 | } 186 | stage.show(); 187 | } 188 | 189 | private Image convertFileToImage(File imageFile) { 190 | Image image = null; 191 | try (FileInputStream fileInputStream = new FileInputStream(imageFile)){ 192 | image = new Image(fileInputStream); 193 | } catch (Exception e) { 194 | e.printStackTrace(); 195 | } 196 | return image; 197 | } 198 | 199 | 200 | 201 | private class AreaSelection { 202 | 203 | private Group group; 204 | 205 | private ResizableRectangle selectionRectangle = null; 206 | private double rectangleStartX; 207 | private double rectangleStartY; 208 | private Paint darkAreaColor = Color.color(0,0,0,0.5); 209 | 210 | private ResizableRectangle selectArea(Group group) { 211 | this.group = group; 212 | 213 | // group.getChildren().get(0) == mainImageView. We assume image view as base container layer 214 | if (mainImageView != null && mainImage != null) { 215 | this.group.getChildren().get(0).addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler); 216 | this.group.getChildren().get(0).addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler); 217 | this.group.getChildren().get(0).addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler); 218 | } 219 | 220 | return selectionRectangle; 221 | } 222 | 223 | EventHandler onMousePressedEventHandler = event -> { 224 | if (event.isSecondaryButtonDown()) 225 | return; 226 | 227 | rectangleStartX = event.getX(); 228 | rectangleStartY = event.getY(); 229 | 230 | clearSelection(group); 231 | 232 | selectionRectangle = new ResizableRectangle(rectangleStartX, rectangleStartY, 0, 0, group); 233 | 234 | darkenOutsideRectangle(selectionRectangle); 235 | 236 | }; 237 | 238 | EventHandler onMouseDraggedEventHandler = event -> { 239 | if (event.isSecondaryButtonDown()) 240 | return; 241 | 242 | double offsetX = event.getX() - rectangleStartX; 243 | double offsetY = event.getY() - rectangleStartY; 244 | 245 | if (offsetX > 0) { 246 | if (event.getX() > mainImage.getWidth()) 247 | selectionRectangle.setWidth(mainImage.getWidth() - rectangleStartX); 248 | else 249 | selectionRectangle.setWidth(offsetX); 250 | } else { 251 | if (event.getX() < 0) 252 | selectionRectangle.setX(0); 253 | else 254 | selectionRectangle.setX(event.getX()); 255 | selectionRectangle.setWidth(rectangleStartX - selectionRectangle.getX()); 256 | } 257 | 258 | if (offsetY > 0) { 259 | if (event.getY() > mainImage.getHeight()) 260 | selectionRectangle.setHeight(mainImage.getHeight() - rectangleStartY); 261 | else 262 | selectionRectangle.setHeight(offsetY); 263 | } else { 264 | if (event.getY() < 0) 265 | selectionRectangle.setY(0); 266 | else 267 | selectionRectangle.setY(event.getY()); 268 | selectionRectangle.setHeight(rectangleStartY - selectionRectangle.getY()); 269 | } 270 | 271 | }; 272 | 273 | EventHandler onMouseReleasedEventHandler = event -> { 274 | if (selectionRectangle != null) 275 | isAreaSelected = true; 276 | }; 277 | 278 | 279 | private void darkenOutsideRectangle(Rectangle rectangle) { 280 | Rectangle darkAreaTop = new Rectangle(0,0,darkAreaColor); 281 | Rectangle darkAreaLeft = new Rectangle(0,0,darkAreaColor); 282 | Rectangle darkAreaRight = new Rectangle(0,0,darkAreaColor); 283 | Rectangle darkAreaBottom = new Rectangle(0,0,darkAreaColor); 284 | 285 | darkAreaTop.widthProperty().bind(mainImage.widthProperty()); 286 | darkAreaTop.heightProperty().bind(rectangle.yProperty()); 287 | 288 | darkAreaLeft.yProperty().bind(rectangle.yProperty()); 289 | darkAreaLeft.widthProperty().bind(rectangle.xProperty()); 290 | darkAreaLeft.heightProperty().bind(rectangle.heightProperty()); 291 | 292 | darkAreaRight.xProperty().bind(rectangle.xProperty().add(rectangle.widthProperty())); 293 | darkAreaRight.yProperty().bind(rectangle.yProperty()); 294 | darkAreaRight.widthProperty().bind(mainImage.widthProperty().subtract( 295 | rectangle.xProperty().add(rectangle.widthProperty()))); 296 | darkAreaRight.heightProperty().bind(rectangle.heightProperty()); 297 | 298 | darkAreaBottom.yProperty().bind(rectangle.yProperty().add(rectangle.heightProperty())); 299 | darkAreaBottom.widthProperty().bind(mainImage.widthProperty()); 300 | darkAreaBottom.heightProperty().bind(mainImage.heightProperty().subtract( 301 | rectangle.yProperty().add(rectangle.heightProperty()))); 302 | 303 | // adding dark area rectangles before the selectionRectangle. So it can't overlap rectangle 304 | group.getChildren().add(1,darkAreaTop); 305 | group.getChildren().add(1,darkAreaLeft); 306 | group.getChildren().add(1,darkAreaBottom); 307 | group.getChildren().add(1,darkAreaRight); 308 | 309 | // make dark area container layer as well 310 | darkAreaTop.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler); 311 | darkAreaTop.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler); 312 | darkAreaTop.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler); 313 | 314 | darkAreaLeft.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler); 315 | darkAreaLeft.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler); 316 | darkAreaLeft.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler); 317 | 318 | darkAreaRight.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler); 319 | darkAreaRight.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler); 320 | darkAreaRight.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler); 321 | 322 | darkAreaBottom.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler); 323 | darkAreaBottom.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler); 324 | darkAreaBottom.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler); 325 | } 326 | } 327 | 328 | 329 | } -------------------------------------------------------------------------------- /Source Code/ResizableRectangle.java: -------------------------------------------------------------------------------- 1 | import javafx.scene.Cursor; 2 | import javafx.scene.Group; 3 | import javafx.scene.input.MouseEvent; 4 | import javafx.scene.paint.Color; 5 | import javafx.scene.paint.Paint; 6 | import javafx.scene.shape.Rectangle; 7 | 8 | 9 | class ResizableRectangle extends Rectangle { 10 | 11 | private double rectangleStartX; 12 | private double rectangleStartY; 13 | private double mouseClickPozX; 14 | private double mouseClickPozY; 15 | private static final double RESIZER_SQUARE_SIDE = 8; 16 | private Paint resizerSquareColor = Color.WHITE; 17 | private Paint rectangleStrokeColor = Color.BLACK; 18 | 19 | ResizableRectangle(double x, double y, double width, double height, Group group) { 20 | super(x,y,width,height); 21 | group.getChildren().add(this); 22 | super.setStroke(rectangleStrokeColor); 23 | super.setStrokeWidth(1); 24 | super.setFill(Color.color(1, 1, 1, 0)); 25 | 26 | 27 | Rectangle moveRect = new Rectangle(0,0,0,0); 28 | moveRect.setFill(Color.color(1,1,1,0)); 29 | moveRect.xProperty().bind(super.xProperty()); 30 | moveRect.yProperty().bind(super.yProperty()); 31 | moveRect.widthProperty().bind(super.widthProperty()); 32 | moveRect.heightProperty().bind(super.heightProperty()); 33 | 34 | group.getChildren().add(moveRect); 35 | 36 | moveRect.addEventHandler(MouseEvent.MOUSE_ENTERED, event -> 37 | moveRect.getParent().setCursor(Cursor.HAND)); 38 | 39 | moveRect.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> { 40 | moveRect.getParent().setCursor(Cursor.MOVE); 41 | mouseClickPozX = event.getX(); 42 | mouseClickPozY = event.getY(); 43 | 44 | }); 45 | 46 | moveRect.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> 47 | moveRect.getParent().setCursor(Cursor.HAND)); 48 | 49 | moveRect.addEventHandler(MouseEvent.MOUSE_EXITED, event -> 50 | moveRect.getParent().setCursor(Cursor.DEFAULT)); 51 | 52 | moveRect.addEventHandler(MouseEvent.MOUSE_DRAGGED,event -> { 53 | 54 | double offsetX = event.getX() - mouseClickPozX; 55 | double offsetY = event.getY() - mouseClickPozY; 56 | double newX = super.getX() + offsetX ; 57 | double newY = super.getY() + offsetY ; 58 | 59 | if (newX >= 0 && newX + super.getWidth() <= super.getParent().getBoundsInLocal().getWidth() ) { 60 | super.setX(newX); 61 | } 62 | 63 | if (newY >= 0 && newY + super.getHeight() <= super.getParent().getBoundsInLocal().getHeight()) { 64 | super.setY(newY); 65 | } 66 | mouseClickPozX = event.getX(); 67 | mouseClickPozY = event.getY(); 68 | 69 | }); 70 | 71 | 72 | makeNWResizerSquare(group); 73 | makeCWResizerSquare(group); 74 | makeSWResizerSquare(group); 75 | makeSCResizerSquare(group); 76 | makeSEResizerSquare(group); 77 | makeCEResizerSquare(group); 78 | makeNEResizerSquare(group); 79 | makeNCResizerSquare(group); 80 | 81 | 82 | } 83 | 84 | private void makeNWResizerSquare(Group group) { 85 | Rectangle squareNW = new Rectangle(RESIZER_SQUARE_SIDE,RESIZER_SQUARE_SIDE); 86 | 87 | squareNW.xProperty().bind(super.xProperty().subtract(squareNW.widthProperty().divide(2.0))); 88 | squareNW.yProperty().bind(super.yProperty().subtract(squareNW.heightProperty().divide(2.0))); 89 | group.getChildren().add(squareNW); 90 | 91 | squareNW.addEventHandler(MouseEvent.MOUSE_ENTERED,event -> 92 | squareNW.getParent().setCursor(Cursor.NW_RESIZE)); 93 | 94 | prepareResizerSquare(squareNW); 95 | 96 | squareNW.addEventHandler(MouseEvent.MOUSE_DRAGGED,event -> { 97 | rectangleStartX = super.getX(); 98 | rectangleStartY = super.getY(); 99 | double offsetX = event.getX() - rectangleStartX; 100 | double offsetY = event.getY() - rectangleStartY; 101 | double newX = super.getX() + offsetX ; 102 | double newY = super.getY() + offsetY ; 103 | 104 | if (newX >= 0 && newX <= super.getX() + super.getWidth() ) { 105 | super.setX(newX); 106 | super.setWidth(super.getWidth() - offsetX); 107 | } 108 | 109 | if (newY >= 0 && newY <= super.getY() + super.getHeight() ) { 110 | super.setY(newY); 111 | super.setHeight(super.getHeight() - offsetY); 112 | } 113 | 114 | }); 115 | } 116 | 117 | private void makeCWResizerSquare(Group group) { 118 | Rectangle squareCW = new Rectangle(RESIZER_SQUARE_SIDE,RESIZER_SQUARE_SIDE); 119 | squareCW.xProperty().bind(super.xProperty().subtract(squareCW.widthProperty().divide(2.0))); 120 | squareCW.yProperty().bind(super.yProperty().add(super.heightProperty().divide(2.0).subtract( 121 | squareCW.heightProperty().divide(2.0)))); 122 | group.getChildren().add(squareCW); 123 | 124 | squareCW.addEventHandler(MouseEvent.MOUSE_ENTERED,event -> 125 | squareCW.getParent().setCursor(Cursor.W_RESIZE)); 126 | 127 | prepareResizerSquare(squareCW); 128 | 129 | squareCW.addEventHandler(MouseEvent.MOUSE_DRAGGED, event -> { 130 | rectangleStartX = super.getX(); 131 | double offsetX = event.getX() - rectangleStartX; 132 | double newX = super.getX() + offsetX; 133 | 134 | if (newX >= 0 && newX <= super.getX() + super.getWidth() - 5) { 135 | super.setX(newX); 136 | super.setWidth(super.getWidth() - offsetX); 137 | } 138 | 139 | }); 140 | 141 | } 142 | 143 | private void makeSWResizerSquare(Group group) { 144 | Rectangle squareSW = new Rectangle(RESIZER_SQUARE_SIDE,RESIZER_SQUARE_SIDE); 145 | squareSW.xProperty().bind(super.xProperty().subtract(squareSW.widthProperty().divide(2.0))); 146 | squareSW.yProperty().bind(super.yProperty().add(super.heightProperty().subtract( 147 | squareSW.heightProperty().divide(2.0)))); 148 | group.getChildren().add(squareSW); 149 | 150 | squareSW.addEventHandler(MouseEvent.MOUSE_ENTERED,event -> 151 | squareSW.getParent().setCursor(Cursor.SW_RESIZE)); 152 | 153 | prepareResizerSquare(squareSW); 154 | 155 | squareSW.addEventHandler(MouseEvent.MOUSE_DRAGGED, event -> { 156 | rectangleStartX = super.getX(); 157 | rectangleStartY = super.getY(); 158 | double offsetX = event.getX() - rectangleStartX; 159 | double offsetY = event.getY() - rectangleStartY; 160 | double newX = super.getX() + offsetX; 161 | 162 | if (newX >= 0 && newX <= super.getX() + super.getWidth() - 5) { 163 | super.setX(newX); 164 | super.setWidth(super.getWidth() - offsetX); 165 | } 166 | 167 | if (offsetY >= 0 && offsetY <= super.getY() + super.getHeight() - 5) { 168 | super.setHeight(offsetY); 169 | } 170 | }); 171 | } 172 | 173 | private void makeSCResizerSquare(Group group) { 174 | Rectangle squareSC = new Rectangle(RESIZER_SQUARE_SIDE,RESIZER_SQUARE_SIDE); 175 | 176 | squareSC.xProperty().bind(super.xProperty().add(super.widthProperty().divide(2.0).subtract( 177 | squareSC.widthProperty().divide(2.0)))); 178 | squareSC.yProperty().bind(super.yProperty().add(super.heightProperty().subtract( 179 | squareSC.heightProperty().divide(2.0)))); 180 | group.getChildren().add(squareSC); 181 | 182 | squareSC.addEventHandler(MouseEvent.MOUSE_ENTERED,event -> 183 | squareSC.getParent().setCursor(Cursor.S_RESIZE)); 184 | 185 | prepareResizerSquare(squareSC); 186 | 187 | squareSC.addEventHandler(MouseEvent.MOUSE_DRAGGED,event -> { 188 | rectangleStartY = super.getY(); 189 | double offsetY = event.getY() - rectangleStartY; 190 | 191 | if (offsetY >= 0 && offsetY <= super.getY() + super.getHeight() - 5) { 192 | super.setHeight(offsetY); 193 | } 194 | 195 | }); 196 | } 197 | 198 | private void makeSEResizerSquare(Group group) { 199 | Rectangle squareSE = new Rectangle(RESIZER_SQUARE_SIDE,RESIZER_SQUARE_SIDE); 200 | squareSE.xProperty().bind(super.xProperty().add(super.widthProperty()).subtract( 201 | squareSE.widthProperty().divide(2.0))); 202 | squareSE.yProperty().bind(super.yProperty().add(super.heightProperty().subtract( 203 | squareSE.heightProperty().divide(2.0)))); 204 | group.getChildren().add(squareSE); 205 | 206 | squareSE.addEventHandler(MouseEvent.MOUSE_ENTERED,event -> 207 | squareSE.getParent().setCursor(Cursor.SE_RESIZE)); 208 | 209 | prepareResizerSquare(squareSE); 210 | 211 | squareSE.addEventHandler(MouseEvent.MOUSE_DRAGGED, event -> { 212 | rectangleStartX = super.getX(); 213 | rectangleStartY = super.getY(); 214 | double offsetX = event.getX() - rectangleStartX; 215 | double offsetY = event.getY() - rectangleStartY; 216 | 217 | if (offsetX >= 0 && offsetX <= super.getX() + super.getWidth() - 5) { 218 | super.setWidth(offsetX); 219 | } 220 | 221 | if (offsetY >= 0 && offsetY <= super.getY() + super.getHeight() - 5) { 222 | super.setHeight(offsetY); 223 | } 224 | }); 225 | } 226 | 227 | private void makeCEResizerSquare(Group group) { 228 | Rectangle squareCE = new Rectangle(RESIZER_SQUARE_SIDE,RESIZER_SQUARE_SIDE); 229 | squareCE.xProperty().bind(super.xProperty().add(super.widthProperty()).subtract( 230 | squareCE.widthProperty().divide(2.0))); 231 | squareCE.yProperty().bind(super.yProperty().add(super.heightProperty().divide(2.0).subtract( 232 | squareCE.heightProperty().divide(2.0)))); 233 | group.getChildren().add(squareCE); 234 | 235 | squareCE.addEventHandler(MouseEvent.MOUSE_ENTERED,event -> 236 | squareCE.getParent().setCursor(Cursor.E_RESIZE)); 237 | 238 | prepareResizerSquare(squareCE); 239 | 240 | squareCE.addEventHandler(MouseEvent.MOUSE_DRAGGED, event -> { 241 | rectangleStartX = super.getX(); 242 | double offsetX = event.getX() - rectangleStartX; 243 | if (offsetX >= 0 && offsetX <= super.getX() + super.getWidth() - 5) { 244 | super.setWidth(offsetX); 245 | } 246 | 247 | }); 248 | } 249 | 250 | private void makeNEResizerSquare(Group group){ 251 | Rectangle squareNE = new Rectangle(RESIZER_SQUARE_SIDE,RESIZER_SQUARE_SIDE); 252 | 253 | squareNE.xProperty().bind(super.xProperty().add(super.widthProperty()).subtract( 254 | squareNE.widthProperty().divide(2.0))); 255 | squareNE.yProperty().bind(super.yProperty().subtract(squareNE.heightProperty().divide(2.0))); 256 | group.getChildren().add(squareNE); 257 | 258 | squareNE.addEventHandler(MouseEvent.MOUSE_ENTERED,event -> 259 | squareNE.getParent().setCursor(Cursor.NE_RESIZE)); 260 | 261 | prepareResizerSquare(squareNE); 262 | 263 | squareNE.addEventHandler(MouseEvent.MOUSE_DRAGGED,event -> { 264 | rectangleStartX = super.getX(); 265 | rectangleStartY = super.getY(); 266 | double offsetX = event.getX() - rectangleStartX; 267 | double offsetY = event.getY() - rectangleStartY; 268 | double newY = super.getY() + offsetY ; 269 | 270 | if (offsetX >= 0 && offsetX <= super.getX() + super.getWidth() - 5) { 271 | super.setWidth(offsetX); 272 | } 273 | 274 | if (newY >= 0 && newY <= super.getY() + super.getHeight() - 5) { 275 | super.setY(newY); 276 | super.setHeight(super.getHeight() - offsetY); 277 | } 278 | 279 | }); 280 | } 281 | 282 | private void makeNCResizerSquare(Group group){ 283 | Rectangle squareNC = new Rectangle(RESIZER_SQUARE_SIDE,RESIZER_SQUARE_SIDE); 284 | 285 | squareNC.xProperty().bind(super.xProperty().add(super.widthProperty().divide(2.0).subtract( 286 | squareNC.widthProperty().divide(2.0)))); 287 | squareNC.yProperty().bind(super.yProperty().subtract( 288 | squareNC.heightProperty().divide(2.0))); 289 | group.getChildren().add(squareNC); 290 | 291 | squareNC.addEventHandler(MouseEvent.MOUSE_ENTERED,event -> 292 | squareNC.getParent().setCursor(Cursor.N_RESIZE)); 293 | 294 | prepareResizerSquare(squareNC); 295 | 296 | squareNC.addEventHandler(MouseEvent.MOUSE_DRAGGED,event -> { 297 | rectangleStartY = super.getY(); 298 | double offsetY = event.getY() - rectangleStartY; 299 | double newY = super.getY() + offsetY ; 300 | 301 | if (newY >= 0 && newY <= super.getY() + super.getHeight()) { 302 | super.setY(newY); 303 | super.setHeight(super.getHeight() - offsetY); 304 | } 305 | 306 | }); 307 | } 308 | 309 | private void prepareResizerSquare(Rectangle rect) { 310 | rect.setFill(resizerSquareColor); 311 | 312 | rect.addEventHandler(MouseEvent.MOUSE_EXITED, event -> 313 | rect.getParent().setCursor(Cursor.DEFAULT)); 314 | } 315 | 316 | 317 | 318 | } --------------------------------------------------------------------------------