Moving marker in a Grid Pane - javafx

I have created a Grid Pane with a number of rows. A marker should only be moveable on 1 row. When moving the mouse it should move sideways only, left or right. When you click on the marker it should be locked, no more movement. It should be highlighted with a different color.
How can I achive this?
If you know any tutorials or examples please add, thanks.
Message Output:
Executing
C:\Users\s22380\Desktop\temp\JavaFXApplication9\dist\run269988000\JavaFXApplication9.jar
using platform C:\Program Files\Java\jdk1.8.0_92\jre/bin/java
Exception in Application constructor
java.lang.reflect.InvocationTargetException at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at
com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Unable to construct Application
instance: class javafxapplication9.JavaFXApplication9 at
com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:907)
at
com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:745) Caused by:
java.lang.reflect.InvocationTargetException at
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at
com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:819)
at
com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at
com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method) at
com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at
com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at
com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
... 1 more Caused by: java.lang.NullPointerException at
sample.Controller.(Controller.java:33) at
javafxapplication9.JavaFXApplication9.(JavaFXApplication9.java:19)
... 13 more Exception running application
javafxapplication9.JavaFXApplication9 Java Result: 1 Deleting
directory
C:\Users\s22380\Desktop\temp\JavaFXApplication9\dist\run269988000
jfxsa-run: BUILD SUCCESSFUL (total time: 1 second)

How about this: Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application
{
Controller controller = new Controller(10,10);
#Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
loader.setController(this.controller);
Parent root = (Parent)loader.load();
this.controller.InitUi();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This is basically the sample code when you say new JavaFX project in IntelliJ. I changed it to explicitly set the controller. But that is just personal preference.
The xaml for that
<?import javafx.scene.layout.*?>
<GridPane fx:id="mainGrid" alignment="center" gridLinesVisible="true" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
</children>
</GridPane>
Again. Basically the default stuff.
I also added a style sheet to define the different lock for the not movable state.
redStyle.css
.button {
-fx-text-fill: #006464;
-fx-background-color: #DFB951;
-fx-border-radius: 20;
-fx-background-radius: 20;
-fx-padding: 5;
}
Now for the controller.
It will do a few things:
Listen to the mouse events of the object I want to push around. If the delata is big enough I will move it => if the mouse is moved fast enough
When the button is pressed I will switch out the style sheet to get the different look. Right now this style works on all buttons in the scene. It could be changed to work only on a specific one.
package sample;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.scene.shape.Rectangle;
public class Controller
{
#FXML
private GridPane mainGrid;
#FXML
private Button movable;
private final int sizeX;
private final int sizeY;
private final double minMoveDistanc = 3;
private boolean canMove = true;
private Double lastX = null;
private Double lastY = null;
private String redButtonStyle = Controller.class.getResource("redStyle.css").toExternalForm();
public Controller(int sizeX, int sizeY)
{
this.sizeX = sizeX;
this.sizeY = sizeY;
}
public void InitUi()
{
if (this.mainGrid != null)
{
final int numCols = sizeX;
final int numRows = sizeY;
for (int i = 0; i < numCols; i++)
{
ColumnConstraints colConst = new ColumnConstraints();
this.mainGrid.getColumnConstraints().add(colConst);
}
for (int i = 0; i < numRows; i++)
{
RowConstraints rowConst = new RowConstraints();
this.mainGrid.getRowConstraints().add(rowConst);
}
// add rectangle to keep grid in size
for (int i = 0; i < numCols; i++)
{
for (int j = 0; j < numRows; j++)
{
Rectangle rect = new Rectangle();
rect.setWidth(50);
rect.setHeight(50);
this.mainGrid.add(rect,i,j);
}
}
// ad movable object (Button)
this.movable = new Button("Hallo");
this.movable.setPrefWidth(50);
this.movable.setPrefHeight(50);
this.movable.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent actionEvent)
{
canMove = ! canMove;
movable.setText(canMove? "move" : "stop");
if (canMove)
{
movable.getScene().getStylesheets().remove(redButtonStyle);
}
else
{
movable.getScene().getStylesheets().add(redButtonStyle);
}
}
});
this.mainGrid.add(this.movable,5,5);
}
if (this.movable != null)
{
this.movable.setOnMouseEntered(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent mouseEvent)
{
lastX = null;
lastY = null;
}
});
this.movable.setOnMouseExited(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent mouseEvent)
{
lastX = null;
lastY = null;
}
});
this.movable.setOnMouseMoved(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent mouseEvent)
{
if (!canMove)
{ return; }
double x = mouseEvent.getSceneX();
double y = mouseEvent.getSceneY();
if (lastX == null)
{
lastX = x;
lastY = y;
return;
}
// calculate delta
double deltaX = x - lastX;
double deltaY = y - lastY;
// remember new position
lastX = x;
lastY = y;
boolean moved = false;
// x movement
if (Math.abs(deltaX) > minMoveDistanc)
{
moved = true;
int currentColumn = GridPane.getColumnIndex(movable);
if (deltaX < 0)
{
GridPane.setColumnIndex(movable, Math.max(currentColumn -1 ,0));
}
else
{
GridPane.setColumnIndex(movable, Math.min(currentColumn + 1 ,sizeX-1));
}
}
// y movement
if (Math.abs(deltaY) > minMoveDistanc)
{
moved = true;
int currentRow = GridPane.getRowIndex(movable);
if (deltaY < 0)
{
GridPane.setRowIndex(movable, Math.max(currentRow - 1 ,0));
}
else
{
GridPane.setRowIndex(movable, Math.min(currentRow + 1 ,sizeY-1));
}
}
if (moved)
{
lastX = null;
lastY = null;
}
}
});
}
}
}

Related

Exception in Application constructor, JavaFX [duplicate]

This question already has answers here:
getResourceAsStream returns null
(26 answers)
How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?
(1 answer)
Closed 1 year ago.
first of all, I'm a complete begginer in Java and JavaFX, using IntelliJ Idea for that.
I have tried to download and run a piece of game's code but ran into a problem that I can't pinpoint the cause of.
I have this in my VM options:
--module-path
${PATH_TO_FX};${OUTPUT}
--add-modules
javafx.controls,javafx.fxml
Error message itself:
Exception in Application constructor
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Unable to construct Application instance: class gg.game.Game
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:891)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:803)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
... 1 more
Caused by: java.lang.NullPointerException: Input stream must not be null
at javafx.graphics/javafx.scene.image.Image.validateInputStream(Image.java:1142)
at javafx.graphics/javafx.scene.image.Image.<init>(Image.java:705)
at gg.game/gg.game.Game.<init>(Game.java:19)
... 14 more
Exception running application gg.game.Game
Game's code:
package gg.game;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.HashMap;
public class Game extends Application {
public static ArrayList<Block> platforms = new ArrayList<>();
private HashMap<KeyCode,Boolean> keys = new HashMap<>();
Image backgroundImg = new Image(getClass().getResourceAsStream("background.png"));
public static final int BLOCK_SIZE = 45;
public static final int MARIO_SIZE = 40;
public static Pane appRoot = new Pane();
public static Pane gameRoot = new Pane();
public Character player;
int levelNumber = 0;
private int levelWidth;
private void initContent(){
ImageView backgroundIV = new ImageView(backgroundImg);
backgroundIV.setFitHeight(14*BLOCK_SIZE);
backgroundIV.setFitWidth(212*BLOCK_SIZE);
levelWidth = LevelData.levels[levelNumber][0].length()*BLOCK_SIZE;
for(int i = 0; i < LevelData.levels[levelNumber].length; i++){
String line = LevelData.levels[levelNumber][i];
for(int j = 0; j < line.length();j++){
switch (line.charAt(j)){
case '0':
break;
case '1':
Block platformFloor = new Block(Block.BlockType.PLATFORM, j * BLOCK_SIZE, i * BLOCK_SIZE);
break;
case '2':
Block brick = new Block(Block.BlockType.BRICK,j*BLOCK_SIZE,i*BLOCK_SIZE);
break;
case '3':
Block bonus = new Block(Block.BlockType.BONUS,j*BLOCK_SIZE,i*BLOCK_SIZE);
break;
case '4':
Block stone = new Block(Block.BlockType.STONE,j * BLOCK_SIZE, i * BLOCK_SIZE);
break;
case '5':
Block PipeTopBlock = new Block(Block.BlockType.PIPE_TOP,j * BLOCK_SIZE, i * BLOCK_SIZE);
break;
case '6':
Block PipeBottomBlock = new Block(Block.BlockType.PIPE_BOTTOM,j * BLOCK_SIZE, i * BLOCK_SIZE);
break;
case '*':
Block InvisibleBlock = new Block(Block.BlockType.INVISIBLE_BLOCK,j * BLOCK_SIZE, i * BLOCK_SIZE);
break;
}
}
}
player =new Character();
player.setTranslateX(0);
player.setTranslateY(400);
player.translateXProperty().addListener((obs,old,newValue)->{
int offset = newValue.intValue();
if(offset>640 && offset<levelWidth-640){
gameRoot.setLayoutX(-(offset-640));
backgroundIV.setLayoutX(-(offset-640));
}
});
gameRoot.getChildren().add(player);
appRoot.getChildren().addAll(backgroundIV,gameRoot);
}
private void update(){
if(isPressed(KeyCode.UP) && player.getTranslateY()>=5){
player.jumpPlayer();
}
if(isPressed(KeyCode.LEFT) && player.getTranslateX()>=5){
player.setScaleX(-1);
player.animation.play();
player.moveX(-5);
}
if(isPressed(KeyCode.RIGHT) && player.getTranslateX()+40 <=levelWidth-5){
player.setScaleX(1);
player.animation.play();
player.moveX(5);
}
if(player.playerVelocity.getY()<10){
player.playerVelocity = player.playerVelocity.add(0,1);
}
player.moveY((int)player.playerVelocity.getY());
}
private boolean isPressed(KeyCode key){
return keys.getOrDefault(key,false);
}
#Override
public void start(Stage primaryStage) throws Exception {
initContent();
Scene scene = new Scene(appRoot,1200,620);
scene.setOnKeyPressed(event-> keys.put(event.getCode(), true));
scene.setOnKeyReleased(event -> {
keys.put(event.getCode(), false);
player.animation.stop();
});
primaryStage.setTitle("Mini Mario");
primaryStage.setScene(scene);
primaryStage.show();
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
update();
}
};
timer.start();
}
public static void main(String[] args) {
launch(args);
}
}
I would be grateful to any kind of response. Thank you.

Add FreeHand functionality in JavaFX

Actually I am making an application which allows user to crop an image an then gives functionality of free-hand drawing and to also to draw different shapes. I have achieved functionality of cropping and drawing shapes like line etc. But I am facing some problems in free-hand drawing.
I have added my image on "HBox" and cropped that image through "Rectangle" in JavaFX class which is added on "Group". And all these are added on "Pane" class. Now for free-hand drawing, I am using "Canvas". Where to add canvas, whether on "HBox" or "Group" or "Pane" class. And Canvas is only initialized on clicking pencil button. I have added single functions for Mouse-Events and applied if-checks for different functionalities in those functions.
basically how to draw pencil on image or how to add lineTo on group.
Can someone please help me in solving my problem??
`
package application;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.imageio.ImageIO;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.Rectangle;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class Main extends Application {
int dragStatus = 0;
double startingPointX;
double startingPointY;
double currentEndingPointX;
double currentEndingPointY;
BufferedImage bufferedImage;
Robot robot;
ImageView imageView;
Button pencilBtn;
Image image;
Pane rootPane;
HBox pictureRegion;
Scene scene;
Rectangle croppedArea;
Canvas canvas;
GraphicsContext gc;
WritableImage writableImage;
Group group = new Group();
Line line;
LineTo lineTo;
String shape;
Boolean canvasAdded;
#Override
public void start(Stage primaryStage) {
try {
int sleepTime = 120;
Thread.sleep(sleepTime);
pencilBtn = createButton("save.png");
pictureRegion = new HBox();
rootPane = new Pane();
scene = new Scene(rootPane);
robot = new Robot();
java.awt.Rectangle capture = new java.awt.Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
bufferedImage = robot.createScreenCapture(capture);
image = ConvertBufferedToJavaFXImage.convertToFxImage(bufferedImage);
pencilBtn.setOnAction(e -> geometrySelection("pencil"));
croppedArea = new Rectangle();
if(canvas != null) {
canvas.setOnMousePressed(e -> onMousePressed(e));
canvas.setOnMousePressed(e -> onMouseDragged(e));
}
imageView = new ImageView(image);
scene.setOnMouseEntered(e -> onMouseEntered(e, "scene"));
scene.setOnMousePressed(e -> onMousePressed(e));
scene.setOnMouseReleased(e -> onMouseReleased(e));
scene.setOnMouseDragged(e -> onMouseDragged(e));
pictureRegion.getChildren().add(imageView);
rootPane.getChildren().add(pictureRegion);
rootPane.getChildren().add(group);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setMaximized(true);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void onMouseEntered(MouseEvent ev, String nodeType) {
if (nodeType == "scene") {
scene.setCursor(Cursor.CROSSHAIR);
} else if (nodeType == "croppedArea") {
croppedArea.setCursor(Cursor.TEXT);
//croppedArea.setOnMousePressed(e -> onMousePressed(e));
} else if (nodeType == "btn") {
pencilBtn.setCursor(Cursor.HAND);
}
}
public void onMousePressed(MouseEvent event) {
if ((startingPointX < event.getX() && event.getX() < currentEndingPointX)
&& (startingPointY < event.getY() && event.getY() < currentEndingPointY)) {
if(shape == "pencil") {
lineTo = new LineTo();
System.out.println("lineTo1");
gc.beginPath();
gc.lineTo(event.getX(), event.getY());
gc.stroke();
}
} else {
shape = "croppedArea";
rootPane.getChildren().remove(canvas);
group.getChildren().clear();
startingPointX = event.getX();
startingPointY = event.getY();
group.getChildren().add(croppedArea);
}
}
public void onMouseDragged(MouseEvent event) {
dragStatus = 1;
if (dragStatus == 1) {
// if((startingPointX < event.getX() && event.getX() < currentEndingPointX)
// && (startingPointY < event.getY() && event.getY() < currentEndingPointY)) {
if(shape == "pencil") {
System.out.println("lineTo1");
gc.lineTo(event.getX(), event.getY());
gc.stroke();
}
else {
currentEndingPointX = event.getX();
currentEndingPointY = event.getY();
rootPane.getChildren().remove(pencilBtn);
croppedArea.setFill(Color.TRANSPARENT);
croppedArea.setStroke(Color.BLACK);
croppedArea.setOnMouseEntered(e -> onMouseEntered(e, "croppedArea"));
adjustRectangleProperties(startingPointX, startingPointY, currentEndingPointX, currentEndingPointY,
croppedArea);
}
}
}
public void geometrySelection(String tempShape) {
if(tempShape == "pencil") {
shape = "pencil";
canvas = new Canvas();
gc = canvas.getGraphicsContext2D();
//gc.setFill(Color.LIGHTGRAY);
gc.setStroke(Color.BLACK);
gc.setLineWidth(5);
canvas.setLayoutX(startingPointX);
canvas.setLayoutY(startingPointY);
canvas.setWidth(croppedArea.getWidth());
canvas.setHeight(croppedArea.getHeight());
System.out.println("canvasAdded");
group.getChildren().add(canvas);
}
}
public void onMouseReleased(MouseEvent event) {
if(dragStatus == 1) {
if(shape == "croppedArea") {
if (croppedArea.getHeight() > 0 && croppedArea.getWidth() > 0) {
pencilBtn.setLayoutX(Math.max(startingPointX, currentEndingPointX) + 5);
pencilBtn.setLayoutY(Math.max(startingPointY, currentEndingPointY) - 120);
rootPane.getChildren().add(pencilBtn);
dragStatus = 0;
}
}
bufferedImage = robot.createScreenCapture(new java.awt.Rectangle((int) startingPointX, (int) startingPointY,
(int) croppedArea.getWidth(), (int) croppedArea.getHeight()));
}
}
void adjustRectangleProperties(Double startingPointX, Double startingPointY, Double currentEndingPointX,
Double currentEndingPointY, Rectangle givenRectangle) {
givenRectangle.setX(startingPointX);
givenRectangle.setY(startingPointY);
givenRectangle.setWidth(currentEndingPointX - startingPointX);
givenRectangle.setHeight(currentEndingPointY - startingPointY);
if (givenRectangle.getWidth() < 0) {
givenRectangle.setWidth(-givenRectangle.getWidth());
givenRectangle.setX(givenRectangle.getX() - givenRectangle.getWidth());
}
if (givenRectangle.getHeight() < 0) {
givenRectangle.setHeight(-givenRectangle.getHeight());
givenRectangle.setY(givenRectangle.getY() - givenRectangle.getHeight());
}
}
public Button createButton(String imageName) throws FileNotFoundException {
FileInputStream iconFile = new FileInputStream(imageName);
Image iconImage = new Image(iconFile);
Button button = new Button();
button.setGraphic(new ImageView(iconImage));
button.setMaxSize(20, 20);
button.setPadding(Insets.EMPTY);
return button;
}
public static void main(String[] args) {
launch(args);
}
}
`

getting the Id of a button in JavaFX

I created about 10 buttons in javafx each of them onclick is suppose to change the label field in a certain way. My problem is that I don't want to create 10 different methods for each label I will like to use one method then test the id of the button if correct I preform what I want
example of what I am asking
if (button.id == Info_205_btn) {
System.out.println("clicked");
subject_name.setText("stanly");
}
This is an update after #math answer
Here is the code I did
#FXML
private void chooseSubject() {
for (int i = 0; i < buttonInfo.length; i++) {
buttonInfo[i] = new Button("Info"+i);
buttonInfo[i].setId("Info"+i);
int finalI = i;
buttonInfo[i].setOnAction(event -> checkID(buttonInfo[finalI]));
}
}
#FXML
private void checkID(Button button){
System.out.println("running");
if (button.getId().equals("Info0")) {
System.out.println("clicked");
subject_name.setText("stanly");
}
else if (button.getId().equals("Info1")) {
System.out.println("clicked");
subject_name.setText("stanly1");
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
chooseSubject();
}
also on click I placed the method chooseSubject in FXML controller
For all of your buttons I think you will still need to put a .setOnAction but you can have them all point to the same function
button.setOnAction(event -> checkID(button));
and from that function check the id
private void checkID(Button button){
if (button.getId().equals("Info_205_btn")) {
System.out.println("clicked");
button.setText("stanly");
}
else if (button.getId().equals("Info_206_btn")) {
System.out.println("clicked");
button.setText("stanly");
}
//So on
}
Also if you put all of your buttons into a list or if they are already in a list you can iterate though the list and do the .setOnAction that way
for (int i = 0; i < buttonList.length; i++)
button[i].setOnAction(event -> checkId((Button) event.getSource()));
Here is a test program I just wrote to give you an example
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button[] buttonList = new Button[10];
for (int i = 0; i < buttonList.length; i++) {
buttonList[i] = new Button("Button "+i);
buttonList[i].setId("Button"+i);
buttonList[i].setOnAction(event -> checkId((Button) event.getSource()));
}
VBox root = new VBox();
root.setAlignment(Pos.CENTER);
root.getChildren().addAll(buttonList);
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setWidth(200);
stage.setScene(scene);
stage.show();
}
private void checkId(Button button) {
for (int i = 0; i <= 10; i++) {
if(button.getId().equals("Button" + i))
if(!button.getText().equals("Button " + i + " Clicked"))
button.setText("Button " + i + " Clicked");
else
button.setText("Button " + i);
}
}
public static void main(String[] args) { launch(args); }
}
Edit: Got carried away

How to detect mouse movement over node while button is pressed?

Problem
You can add an event listener to a node which detects mouse movement over it. This doesn't work if a mouse button was pressed before you moved over the node.
Question
Does anyone know how to detect mouse movement while the button is pressed? So far I've only found a solution by using the MOUSE_DRAGGED event and then instead of using getSource() using getPickResult() and evaluating the PickResult data.
Here's the code including Uluk's solution. The old and new solution are switchable via the useNewVersion (Uluk's version) boolean:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.PickResult;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
boolean useNewVersion= true;
int rows = 10;
int columns = 20;
double width = 1024;
double height = 768;
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
// create grid
Grid grid = new Grid( columns, rows, width, height);
MouseGestures mg = new MouseGestures();
// fill grid
for (int row = 0; row < rows; row++) {
for (int column = 0; column < columns; column++) {
Cell cell = new Cell(column, row);
mg.makePaintable(cell);
grid.add(cell, column, row);
}
}
root.setCenter(grid);
// create scene and stage
Scene scene = new Scene(root, width, height);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
private class Grid extends Pane {
int rows;
int columns;
double width;
double height;
Cell[][] cells;
public Grid( int columns, int rows, double width, double height) {
this.columns = columns;
this.rows = rows;
this.width = width;
this.height = height;
cells = new Cell[rows][columns];
}
/**
* Add cell to array and to the UI.
*/
public void add(Cell cell, int column, int row) {
cells[row][column] = cell;
double w = width / columns;
double h = height / rows;
double x = w * column;
double y = h * row;
cell.setLayoutX(x);
cell.setLayoutY(y);
cell.setPrefWidth(w);
cell.setPrefHeight(h);
getChildren().add(cell);
}
}
private class Cell extends StackPane {
int column;
int row;
public Cell(int column, int row) {
this.column = column;
this.row = row;
getStyleClass().add("cell");
Label label = new Label(this.toString());
getChildren().add(label);
}
public void highlight() {
getStyleClass().add("cell-highlight");
}
public void unhighlight() {
getStyleClass().remove("cell-highlight");
}
public String toString() {
return this.column + "/" + this.row;
}
}
public class MouseGestures {
public void makePaintable( Node node) {
if( useNewVersion) {
node.setOnMousePressed( onMousePressedEventHandler);
node.setOnDragDetected( onDragDetectedEventHandler);
node.setOnMouseDragEntered( onMouseDragEnteredEventHandler);
} else {
node.setOnMousePressed( onMousePressedEventHandler);
node.setOnMouseDragged( onMouseDraggedEventHandler);
node.setOnMouseReleased( onMouseReleasedEventHandler);
}
}
/* old version */
EventHandler<MouseEvent> onMousePressedEventHandler = event -> {
Cell cell = (Cell) event.getSource();
if( event.isPrimaryButtonDown()) {
cell.highlight();
} else if( event.isSecondaryButtonDown()) {
cell.unhighlight();
}
};
EventHandler<MouseEvent> onMouseDraggedEventHandler = event -> {
PickResult pickResult = event.getPickResult();
Node node = pickResult.getIntersectedNode();
if( node instanceof Cell) {
Cell cell = (Cell) node;
if( event.isPrimaryButtonDown()) {
cell.highlight();
} else if( event.isSecondaryButtonDown()) {
cell.unhighlight();
}
}
};
EventHandler<MouseEvent> onMouseReleasedEventHandler = event -> {
};
EventHandler<MouseEvent> onDragDetectedEventHandler = event -> {
Cell cell = (Cell) event.getSource();
cell.startFullDrag();
};
EventHandler<MouseEvent> onMouseDragEnteredEventHandler = event -> {
Cell cell = (Cell) event.getSource();
if( event.isPrimaryButtonDown()) {
cell.highlight();
} else if( event.isSecondaryButtonDown()) {
cell.unhighlight();
}
};
}
}
In the end you should be able to paint via primary mouse button and erase the paint via secondary mouse button:
One solution is to add an event filter to the scene which enables the sourceNode.startFullDrag(). This will work even if you start dragging the mouse outside of your canvas (if you want any space without nodes in your application).
Like this:
scene.addEventFilter(MouseEvent.DRAG_DETECTED , new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
scene.startFullDrag();
}
});
And then you could:
node.setOnMouseDragEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
led.setOn(true);
}
});
The (source) node which handles the initial DRAG_DETECTED event should invoke sourceNode.startFullDrag(), then the target node will able to handle one of MouseDragEvents, for instance MOUSE_DRAG_OVER or MOUSE_DRAG_ENTERED event with respective targetNode.setOn<MouseDragEvent>() method.

JavaFX Load exception in main

I am having some problems with my code I'm writing for an exam project. It's in JavaFX.
I an sending some parameters from my model to my main, and then again from the main to the controller. I am getting a LoadException even though the location set should be correct.
This is the error code:
javafx.fxml.LoadException:
bio/grpro_project/target/classes/project/view/reservation.fxml
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2595)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2565)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2435)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
at project.ReservationMain.showReservationView(ReservationMain.java:22)
at project.ReservationMain.start(ReservationMain.java:37)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
at com.sun.javafx.application.LauncherImpl$$Lambda$50/272422922.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
at com.sun.javafx.application.PlatformImpl$$Lambda$46/2050891229.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
at com.sun.javafx.application.PlatformImpl$$Lambda$48/1063369253.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/1170609517.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/1399457240.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2560)
... 18 more
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at project.controller.ReservationController.initialize(ReservationController.java:166)
... 28 more
This is the main class:
public class ReservationMain extends Application {
public void showReservationView(Stage stage, String showtitle, String showdate, String showtime) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("view/reservation.fxml"));
Parent reservationView = loader.load();
ReservationController controller = loader.<ReservationController>getController();
controller.setup(showtitle, showdate, showtime);
stage.setTitle("Reservation");
stage.setScene(new Scene(reservationView, 800, 600));
stage.show();
} catch (IOException e) {
e.printStackTrace(); //Show a dialog or something... ?
}
}
#Override
public void start(Stage primaryStage) throws Exception {
showReservationView(primaryStage, "", "", "");
}
public static void main(String[] args) {
launch(args);
}
}
And this is the method in the model used to send parameters to the main:
reservationButton.setOnAction((event) -> {
System.out.println(showtime + showdate + showtime);
ReservationMain newscene = new ReservationMain();
Stage stage = new Stage();
newscene.showReservationView(stage, showtitle, showdate, showtime);
});
Hope someone can help - I've been trying to fix this for many hours now.
The controller code (gets data from a model class, should not be a problem though):
public class ReservationController {
private Reservation reservation = new Reservation();
private DatabaseLoad databaseLoad = new DatabaseLoad();
private DatabaseInsert databaseInsert = new DatabaseInsert();
private int theater;
private ObservableList numberOfSeatsSelectedItems = FXCollections.observableArrayList();
private int numberOfSeatsToSelect = 1;
private int selectedRow;
private int selectedSeat;
private int showID;
#FXML
private TextField nameField;
#FXML
private TextField phoneField;
#FXML
private GridPane seatsGridContainer;
#FXML
private VBox movieScreenBox;
#FXML
private Text theaterNumber;
#FXML
private Text freeSeats;
#FXML
private ComboBox seatsSelectedBox;
#FXML
private Button reserveButton;
#FXML
private Text movieTitleText;
#FXML
private Text movieDateText;
#FXML
private Text movieTimeText;
public ReservationController() {
}
public void setup(String showtitle, String showdate, String showtime){
showID = reservation.loadTheatertoShow(showtitle, showdate, showtime);
reservation.loadTheaterFromDatabase(showID);
theater = reservation.getTheaterNumber();
numberOfSeatsSelectedItems.addAll(1,2,3,4,5,6,7,8);
}
#FXML
public void initialize() {
//int numberOfSeatsSelected;
seatsSelectedBox.setItems(numberOfSeatsSelectedItems);
seatsSelectedBox.setOnAction((event) -> {
numberOfSeatsToSelect = (int) seatsSelectedBox.getSelectionModel().getSelectedItem();
});
movieScreenBox.setBackground(new Background(new BackgroundFill(Color.GRAY, CornerRadii.EMPTY, Insets.EMPTY)));
seatsGridContainer.setHgap(8);
seatsGridContainer.setVgap(8);
seatsGridContainer.setAlignment(Pos.CENTER);
ArrayList occupiedSeats = reservation.loadOccupiedSeats(showID);
Seat[][] seat = new Seat[reservation.getNumberOfRows()][reservation.getNumberOfSeatsInARow()];
for (int row = 0; row < seat.length; row++) {
for (int seatNumber = 0; seatNumber < seat[0].length; seatNumber++) {
seat[row][seatNumber] = new Seat("");
seat[row][seatNumber].setPrefSize(30, 30);
//
final int finalRow = row;
final int finalSeatNumber = seatNumber;
seat[row][seatNumber].setOnMouseClicked(arg0 -> {
selectedRow = finalRow;
selectedSeat = finalSeatNumber;
for (int i = 0; i < seat.length; i++) {
for (int j = 0; j < seat[0].length; j++) {
if (seat[i][j].isFree()) {
seat[i][j].setStyle("-fx-background-color: green;");
seat[i][j].setSelected(false);
}
}
}
// check: does the seat selection extend the boundaries of the theater or go into already booked seats?
if(seat[finalRow].length <= finalSeatNumber-1 + numberOfSeatsToSelect) {
int seatsLeft = seat[finalRow].length - finalSeatNumber;
seatsSelectedBox.setValue(seatsLeft);
for(int i = 0 ; i < seatsLeft ; i++) {
seat[finalRow][finalSeatNumber + i].setStyle("-fx-background-color: dodgerblue;");
}
}
else {
for(int i = 0 ; i < numberOfSeatsToSelect ; i++) {
if(!seat[finalRow][finalSeatNumber + i].isFree()) {
seatsSelectedBox.setValue(i);
break;
}
seat[finalRow][finalSeatNumber + i].setStyle("-fx-background-color: dodgerblue;");
seat[finalRow][finalSeatNumber + i].setSelected(true);
}
}
});
// checks and sets which seats are booked
if(occupiedSeats.contains("" + row + seatNumber)) {
seat[row][seatNumber].setIsFree(false);
}
//set free seats to change the cursor on mouseover
if (seat[row][seatNumber].isFree()) {
seat[row][seatNumber].setStyle("-fx-background-color: green;");
seat[row][seatNumber].setOnMouseEntered(me -> seatsGridContainer.setCursor(Cursor.HAND));
seat[row][seatNumber].setOnMouseExited(me -> seatsGridContainer.setCursor(Cursor.DEFAULT));
}
// set booked seats to display as red
else {
seat[row][seatNumber].setStyle("-fx-background-color: red;");
seat[row][seatNumber].setDisable(true);
}
seatsGridContainer.add(seat[row][seatNumber], seatNumber, row);
}
}
reserveButton.setOnAction((event) -> {
databaseInsert.newPersonInDatabase(nameField.getText(),phoneField.getText());
ArrayList nextPersonIDs = databaseLoad.getFromDatabase(
"SELECT * FROM person WHERE PhoneNumber=" + phoneField.getText(),"person")[2];
int nextPersonID = (int) nextPersonIDs.get(nextPersonIDs.size() - 1);
ArrayList arr = databaseLoad.getFromDatabase("SELECT * FROM reservations","reservations")[0];
int nextReservationID = (int) arr.get(arr.size()-1) + 1;
for(int i = 0; i < numberOfSeatsToSelect ; i++) {
databaseInsert.newReservationInDatabase(
nextReservationID, nextPersonID, showID, selectedRow, selectedSeat+i);
}
initialize();
});
ArrayList[] shows = databaseLoad.getFromDatabase("SELECT * FROM shows WHERE ShowID=" + showID, "shows");
movieTitleText.setText("Film: " + shows[0].get(0));
movieDateText.setText("Dato: " + shows[1].get(0).toString());
movieTimeText.setText("Tidspunkt: " + shows[2].get(0).toString());
theaterNumber.setText("Sal nr: " + theater);
freeSeats.setText("Ledige sæder: " + (reservation.getNumberOfSeats()-occupiedSeats.size()));
}
}
If I try adding a / to the folder of the fxml file (/view/reservation.fxml), this is the error message:
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:875)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$147(LauncherImpl.java:157)
at com.sun.javafx.application.LauncherImpl$$Lambda$1/245257410.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Location is not set.
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2428)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
at project.ReservationMain.showReservationView(ReservationMain.java:22)
at project.ReservationMain.start(ReservationMain.java:38)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
at com.sun.javafx.application.LauncherImpl$$Lambda$50/2038127331.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
at com.sun.javafx.application.PlatformImpl$$Lambda$46/1716030070.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
at com.sun.javafx.application.PlatformImpl$$Lambda$48/1391275142.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/156840264.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/848186220.run(Unknown Source)
... 1 more
Process finished with exit code 1

Resources