drawing rectangle in drawing issue - swt

We are creating some graphical applications to the our project. We are using Draw2d and GEF technologies in our project. We have to draw one rectangle in the draw area. The functionality is as follows.
Use click the rectangle button from the toolbar.
Changes cursor to Cross curson symbol.
When the user clicks the area and drag the mouse, it shows the rectangle based on the dragging of the mouse.
Till now it is working fine. Now the issue is, we have zoom in and zoom out functionality.
When the use zoom in and draw the rectangle, it is not coming in the desired position.
It is going below parts of the area.Then user has to scroll and see the rectangle. This problem happens only when we use zoom in and zoom out.
How to ressolve this issue? Please see my code below.
package draw2dview;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.FreeformLayout;
import org.eclipse.draw2d.FreeformViewport;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.RectangleFigure;
import org.eclipse.draw2d.ScalableFigure;
import org.eclipse.draw2d.ScalableFreeformLayeredPane;
import org.eclipse.draw2d.ToolbarLayout;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartFactory;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.editparts.ScalableRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.ui.actions.ZoomInAction;
import org.eclipse.gef.ui.actions.ZoomOutAction;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.part.ViewPart;
public class View extends ViewPart implements org.eclipse.swt.events.MouseListener {
public static final String ID = "draw2dview.view";
private Action drawAction;
private ScalableFreeformLayeredPane root;
ScalableRootEditPart editPart = null ;
private XYLayout layout;
private ZoomManager zoomManager ;
EditDomain editDomain = new DefaultEditDomain(null);
GraphicalViewer graphicalViewer = new ScrollingGraphicalViewer();
ScalableFreeformRootEditPart rootEditPart = new ScalableFreeformRootEditPart();
private FigureCanvas createContents(Composite parent){
root = new ScalableFreeformLayeredPane();
zoomManager = new ZoomManager(root,new FreeformViewport());
root.setFont(parent.getFont());
//layout = new XYLayout();
layout= new FreeformLayout();
root.setLayoutManager(layout);
FigureCanvas figureCanvas = new FigureCanvas(parent,SWT.DOUBLE_BUFFERED);
figureCanvas.addMouseListener(this);
figureCanvas.setBackground(ColorConstants.white);
LightweightSystem lws = new LightweightSystem(figureCanvas);
lws.setContents(root);
return figureCanvas ;
}
private IFigure createPersonFigure() {
RectangleFigure rectangleFigure = new RectangleFigure();
rectangleFigure.setBackgroundColor(ColorConstants.blue);
rectangleFigure.setLayoutManager(new ToolbarLayout());
rectangleFigure.setPreferredSize(100, 100);
return rectangleFigure ;
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(Composite parent) {
/* graphicalViewer.createControl(parent);
editDomain.addViewer(graphicalViewer);
graphicalViewer.setRootEditPart(rootEditPart);*/
createContents(parent);
createAction();
contributeToActionBars();
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
addToToolBar(bars.getToolBarManager());
}
private void addToToolBar(IToolBarManager toolBarManager2){
toolBarManager2.add(drawAction);
toolBarManager2.add(new ZoomInAction(zoomManager));
toolBarManager2.add(new ZoomOutAction(zoomManager));
}
private void createAction() {
drawAction = new Action() {
public void run() {
System.out.println("execued..");
}
};
drawAction.setText("Draw");
drawAction.setImageDescriptor(Activator.getImageDescriptor("icons/alt_window_16.gif"));
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
// viewer.getControl().setFocus();
}
#Override
public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent e) {
}
#Override
public void mouseDown(org.eclipse.swt.events.MouseEvent e) {
System.out.println("inside..Mousedeown:: "+e.x+","+e.y);
IFigure personFigure = createPersonFigure();
root.add(personFigure);
layout.setConstraint(personFigure, new Rectangle(new Point(e.x,e.y),personFigure.getPreferredSize()));
//layout.setConstraint(personFigure, new Rectangle(new Point(e.x,e.y),personFigure.getPreferredSize()));
}
#Override
public void mouseUp(org.eclipse.swt.events.MouseEvent e) {
}
}

You will need to scale your mouse event coordinates according to the zoom level your zoom manager is currently using. The mouse events are absolute pixels, but your ZoomManger is causing a scale factor to be applied to your figure's coordinates. I think you will also need to take into account your ViewPort's client area.
First, when you constuct your ZoomManager pass in the ViewPort from your FigureCanvas:
zoomManager = new ZoomManager(root, figureCanvas.getViewPort());
Then try something like:
double scaleFactor = zoomManager.getZoom();
Rectangle r = figureCanvas.getViewport().getClientArea();
layout.setConstraint(personFigure, new Rectangle(new Point((e.x + r.x) * scaleFactor,(e.y + r.y) * scaleFactor),personFigure.getPreferredSize()));
This may need tweaked to get it right, let me know....

You have to translate from absolute coordinates obtained from the mouse event to relative coordinates to the person figure's parent:
#Override
public void mouseDown(org.eclipse.swt.events.MouseEvent e) {
System.out.println("inside..Mousedeown:: "+e.x+","+e.y);
IFigure personFigure = createPersonFigure();
root.add(personFigure);
Point p = new PrecisionPoint(e.x,e.y);
personFigure.translateToRelative(p);
layout.setConstraint(personFigure, new Rectangle(p,personFigure.getPreferredSize()));
}
For more information look at draw2d help

Related

Javafx Stage is blank for a few seconds before showing elements

I am trying to create a game with JavaFX. I have created 2 stages, one is for the splashscreen, the second one is for the actual game itself. This is my first ever JavaFX program, i am a student learning JavaFX. The problem i am having is that when i hide the first stage and show the second one, the second stage stays blank for a few seconds and then continues to show all element(s). For now, there is only a gif showing in the stage with some music(which is not delayed in loading, because it is an instance variable). I don't want to create many instance variables for each of the elements i wish to put into the stage. Below is the code, where only the necessary code is shown to understand the problem:
import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.File;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
Dimension window = Toolkit.getDefaultToolkit().getScreenSize();
private double screenWidth = window.getWidth();
private double screenHeight = window.getHeight();
private boolean fullscreen = false;
private boolean music = false;
private double value = 0;
private Group root, root2;
private Image start;
private Image startHover;
private ImageView startViewer;
private Stage stage;
private boolean firstWindowExists = true;
private CheckBox full;
private CheckBox sound;
private Slider slider;
private Image BG;
private ImageView BGView;
private String path = "bin/Audio/8_bit_march.mp3";
private Media media;
private MediaPlayer player;
public static void main(String[] args) {
launch();
}
private void run() {
Image title = new Image("Title.png", 300, 0, true, true);
ImageView titleView= new ImageView();
titleView.setX(200);
titleView.setY(10);
titleView.setImage(title);
add(titleView);
start = new Image("Start1.png", 200, 0, true, true);
startHover = new Image("Start_Hover1.png", 200, 0, true, true);
startViewer= new ImageView();
startViewer.setX(250);
startViewer.setY(300);
startViewer.setOnMouseEntered(mouseEnter);
startViewer.setOnMouseExited(mouseExit);
startViewer.setOnMouseReleased(mouseReleased);
startViewer.setImage(start);
add(startViewer);
if (!firstWindowExists) {//this code works
Image title2 = new Image("BG.gif", (screenWidth/1.25) + 4, (screenHeight/1.25)+4, false, true);
ImageView titleView2= new ImageView();
titleView2.setX(-2);
titleView2.setY(-2);
titleView2.setImage(title2);
add2(titleView2);
}
}
EventHandler<ActionEvent> event = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e)
{
if (sound.isSelected()) { // the checkbox is checked to be enabled
slider.setVisible(true);
}
else {
slider.setVisible(false);
}
}
};
EventHandler<MouseEvent> mouseEnter = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) { // irrelevant for this problem
startViewer.setImage(startHover);
}
};
EventHandler<MouseEvent> mouseExit = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
startViewer.setImage(start);
}
};
EventHandler<MouseEvent> mouseReleased = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
stage.hide(); //hide first window
firstWindowExists = false;
Stage stage2 = new Stage(); // creating a new stage
root2 = new Group(); //creating new group
Scene scene2 = new Scene(root2, Color.WHITE);// creating a scene and adding the newly created Group
Canvas canvas2 = new Canvas(screenWidth/1.25, screenHeight/1.25); // creating a canvas for the screen
root2.getChildren().add(canvas2); // adding canvas to the group (window)
stage2.setTitle("Game"); // setting the title of the window
stage2.setScene(scene2); // Adds scene to the stage
stage2.setFullScreen(fullscreen);
stage2.show(); //after showing the screen here, it stays blank and then adds the title2 gif
stage2.centerOnScreen();
if (music) { //plays music
player.play();
player.setVolume(value);
player.setCycleCount(MediaPlayer.INDEFINITE);
}
run(); // runs the method with heavy lifting stuff
}
};
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> {
}));
private void add(Node node) {
if (firstWindowExists) {
root.getChildren().add(node);
}
}
private void add2(Node node) {
root2.getChildren().add(node);
}
#Override
public void start(Stage stage) throws Exception { // main method which creates the first window
this.stage = stage;
stage.setTitle("Test GUI");
root = new Group();
Scene scene = new Scene(root, Color.DARKGRAY);
Canvas canvas = new Canvas(700, 350);
root.getChildren().add(canvas);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
stage.centerOnScreen();
root.requestFocus();
run();
media = new Media(new File(path).toURI().toString());
player = new MediaPlayer(media);
}
}

My circles won't show. What am I missing here?

In Javafx, I am trying to create a pane where I can add points through a mouse click event. When you click on the pane a circle should appear at your mouse position. The circles are being created, as I am tracking them in the console, but they are not showing in the graphics.
I did a similar program to this that auto drew an image that resized with the stage/window, I am using all the same techniques but that project didn't include event handling.
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.paint.Color;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
public class ClickToShape extends Application {
private ClickPane clickPane = new ClickPane();
#Override
public void start(Stage primaryStage) throws Exception {
Pane clickPane = new ClickPane();
clickPane.setOnMouseClicked(new ClickHandler());
// create the scene
Scene clickScene = new Scene(clickPane, 500, 500);
// set up the window/stage
primaryStage.setTitle("Click To Draw");
primaryStage.setScene(clickScene); // add the scene to the stage
primaryStage.show(); // fire it off
}
public static void main(String[] args) {
launch(args);
}
class ClickHandler implements EventHandler<MouseEvent> {
#Override
public void handle(MouseEvent e) {
System.out.println("MouseEvent occured");
clickPane.addPoint(e.getX(), e.getY());
}
}
}
class ClickPane extends Pane{
private ArrayList<Circle> points = new ArrayList<Circle>();
private Color color1 = Color.BLACK;
public void addPoint(double x, double y) {
System.out.println("A new point function ran");
Circle newPoint = new Circle (x, y, 300, color1 );
System.out.println(newPoint.toString());
points.add(newPoint);
getChildren().clear();
getChildren().add(newPoint);
}
}
There are no error messages.
the problem is that you instantiated two ClickPane objects, one outside the start method, and another inside the start method, you added the second one to the scene but used the first one to add points, and that's why points aren't showing in your scene
what you can do about this is delete the first line in your start method, so the application will be using the same instance to fire events as to add to the scene, the code would look like this
import java.util.ArrayList;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
public class ClickToShape extends Application {
private ClickPane clickPane = new ClickPane();
#Override
public void start(Stage primaryStage) throws Exception {
clickPane.setOnMouseClicked(new ClickHandler());
// create the scene
Scene clickScene = new Scene(clickPane, 500, 500);
// set up the window/stage
primaryStage.setTitle("Click To Draw");
primaryStage.setScene(clickScene); // add the scene to the stage
primaryStage.show(); // fire it off
}
public static void main(String[] args) {
launch(args);
}
class ClickHandler implements EventHandler<MouseEvent> {
#Override
public void handle(MouseEvent e) {
System.out.println("MouseEvent occured");
clickPane.addPoint(e.getX(), e.getY());
}
}
}
class ClickPane extends Pane{
private ArrayList<Circle> points = new ArrayList<Circle>();
private Color color1 = Color.BLACK;
public void addPoint(double x, double y) {
System.out.println("A new point function ran");
Circle newPoint = new Circle (x, y, 10, color1 );
System.out.println(newPoint.toString());
points.add(newPoint);
getChildren().setAll(newPoint);
}
}

JavaFX8 - How to draw random circles with random x/y centers?

I am trying to draw random circles with random x/y centers, but the result of my code is only one circle at the center of the stage (window).
I use Task class to update my UI every 1 second.
This is my code:
package javafxupdateui;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class JavaFXUpdateUI extends Application {
private Stage window;
private StackPane layout;
private Scene scene;
#Override
public void start(Stage primaryStage) {
window = primaryStage;
window.setTitle("JavaFX - Update UI");
layout = new StackPane();
scene = new Scene(layout, 500, 500);
window.setScene(scene);
window.show();
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
}
Task task = new Task<Void>() {
#Override
protected Void call() throws Exception {
while (true) {
Platform.runLater(new Runnable() {
#Override
public void run() {
drawCircles();
}
});
Thread.sleep(1000);
}
}
};
public void drawCircles() {
Circle circle;
float x = (float)(Math.random()*501);
float y = (float)(Math.random()*501);
circle = new Circle(x, y, 25, Color.RED);
layout.getChildren().add(circle);
scene.setRoot(layout);
window.setScene(scene);
}
public static void main(String[] args) {
launch(args);
}
}
The result of the above code is:
Result GUI
What is going wrong
StackPane is a layout pane, it centers everything by default. As you want to manually place the circles at random locations, you don't want to use a pane which manages the layout for you.
How to fix it
Use a Pane or a Group instead of StackPane. Neither Pane nor Group manage the layout of items for you, so children you add to them at specific locations will remain at those locations.
Aside
You might wish to use a Timeline for your periodic updates rather than a Task with runLater (though the later will still work OK, with a Timeline you don't have to deal with additional complexities of concurrent code).

how to add same background color for all pane in javafx?

I want to maintain single background color(black) for all panes, and for all views. i don't want write css for every view. i am using only vbox and hbox mostly. and very few table views. is there any easy way to write css once and apply to all. thank you in advance
You don't write a css for every view, you give every element the same style class.
Pane pane = new Pane();
pane.getStyleClass().add("bg-black-style");
Somewhere you need to add the stylesheet to the scene
scene.getStylesheets().add("css-file.css");
And in the css file
.bg-black-style {
-fx-background-color: black;
}
This way every thing that should look the same has it's style all in one place.
You can just use .pane in CSS class, and it will work for all the panes.
.pane{
-fx-background-color: black;
}
Same works with .button etc.
You can apply the style sheet to the entire application like this:
package hacks;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import java.net.URL;
/**
* Created by BDay on 7/10/17.<br>
* <br>
* CssStyle sets the style for the entire project
*/
public class CssStyle extends Application {
private String yourCss = "YourResource.css";
public CssStyle() {
try {
Application.setUserAgentStylesheet(getCss()); //null sets default style
} catch (NullPointerException ex) {
System.out.println(yourCss + " resource not found");
}
}
private Button button = new Button("Button Text");
private TextArea textArea = new TextArea("you text here");
private ObservableList<String> listItems = FXCollections.observableArrayList("one", "two", "three");
private ListView listView = new ListView<String>(listItems);
private FlowPane root = new FlowPane(button, textArea, listView);
private Scene scene = new Scene(root);
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(scene);
primaryStage.show();
}
private String getCss() throws NullPointerException {
ClassLoader classLoader = getClass().getClassLoader();
URL resource = classLoader.getResource(yourCss);
String asString = resource.toExternalForm(); //throws null
return asString;
}
}

Why are KeyEvents Only Generated for the Last Key Pressed?

I'm testing key handlers, and I ran into a problem.
In its barest form, I have the following code:
mainScene.setOnKeyPressed( event -> {
System.out.println("Handler called for: " + event.getCode());
});
As expected, when a key is pressed, it prints out the associated code.
The problem is, if I hold 2 keys at once, only the last key pressed generates constant events. I want to be able to add pressed keys to a queue to be dealt with elsewhere, but only the last key pressed will be added to the queue.
Is there any way to change this behavior?
The only workaround I could find was to use a map to record codes, and set up a separate pressed and released handler to add/remove codes from the map. This works, but requires constant polling of every key I may need to react to, instead of being able to just check if the pressed-key queue is empty.
I suspect the JVM is receiving the key pressed event from the operating system, so the repeat-key behavior when you hold two keys down is determined at the OS level.
To manage your own key press repeats, you can use a timeline with an indefinite cycle count; start the timeline when the key is pressed and stop it when the key is released. You will probably need to manage these in a Map<KeyCode, Timeline> to handle multiple keys. Have the timelines call a method and pass the key code for central handling of the key presses: this will avoid the need for polling.
SSCCE:
import java.util.HashMap;
import java.util.Map;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class MultiRepeatKey extends Application {
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new Pane(), 400, 400);
Map<KeyCode, Timeline> keyRepeats = new HashMap<>();
Duration keyPressDelay = Duration.millis(200);
scene.setOnKeyPressed(e -> {
if (! keyRepeats.containsKey(e.getCode())) {
Timeline repeat = new Timeline(new KeyFrame(Duration.ZERO, event -> processKey(e.getCode())),
new KeyFrame(keyPressDelay));
repeat.setCycleCount(Animation.INDEFINITE);
repeat.play();
keyRepeats.put(e.getCode(), repeat);
}
});
scene.setOnKeyReleased(e -> {
if (keyRepeats.containsKey(e.getCode())) {
Timeline repeat = keyRepeats.get(e.getCode());
repeat.stop();
keyRepeats.remove(e.getCode());
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
private void processKey(KeyCode code) {
System.out.println(code.getName());
}
public static void main(String[] args) {
launch(args);
}
}
Depending on your use case, another option that may make sense for you is to just keep a Map from keys to some representation of the functionality you want, and then to keep a Set of the implementations of those functionality. Then use an AnimationTimer to update the UI depending on which keys are pressed. (An AnimationTimerexecutes its handle method on each frame rendering; the parameter passed in is a timestamp in nanoseconds.).
Obviously if you had many mappings, you would define the mappings elsewhere, but here is the idea:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.DoubleFunction;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class MultiRepeatKey extends Application {
#Override
public void start(Stage primaryStage) {
Rectangle rect = new Rectangle(20, 20, 50, 50);
rect.setFill(Color.CORNFLOWERBLUE);
Pane pane = new Pane(rect);
Set<DoubleFunction<Point2D>> motions = new HashSet<>();
Map<KeyCode, DoubleFunction<Point2D>> keyMappings = new HashMap<>();
keyMappings.put(KeyCode.UP, delta -> new Point2D(0, -delta));
keyMappings.put(KeyCode.DOWN, delta -> new Point2D(0, delta));
keyMappings.put(KeyCode.LEFT, delta -> new Point2D(-delta, 0));
keyMappings.put(KeyCode.RIGHT, delta -> new Point2D(delta, 0));
double speed = 150.0 ; // pixels / second
AnimationTimer anim = new AnimationTimer() {
private long lastUpdate = 0 ;
#Override
public void handle(long now) {
if (lastUpdate > 0) {
double elapsedSeconds = (now - lastUpdate) / 1_000_000_000.0 ;
double delta = speed * elapsedSeconds ;
Point2D loc = motions.stream()
.map(m -> m.apply(delta))
.reduce(new Point2D(rect.getX(), rect.getY()), Point2D::add);
loc = clamp(loc, 0, 0, pane.getWidth() - rect.getWidth(), pane.getHeight() - rect.getHeight());
rect.setX(loc.getX());
rect.setY(loc.getY());
}
lastUpdate = now ;
}
};
anim.start();
Scene scene = new Scene(pane, 400, 400);
scene.setOnKeyPressed(e -> motions.add(keyMappings.get(e.getCode())));
scene.setOnKeyReleased(e -> motions.remove(keyMappings.get(e.getCode())));
primaryStage.setScene(scene);
primaryStage.show();
}
private Point2D clamp(Point2D p, double minX, double minY, double maxX, double maxY) {
if (p.getX() < minX) {
p = new Point2D(minX, p.getY());
} else if (p.getX() > maxX) {
p = new Point2D(maxX, p.getY());
}
if (p.getY() < minY) {
p = new Point2D(p.getX(), minY);
} else if (p.getY() > maxY) {
p = new Point2D(p.getX(), maxY);
}
return p ;
}
public static void main(String[] args) {
launch(args);
}
}