JavaFX pane doesn't draw shapes on a resized area - javafx

I want to create a bouncer app using JavaFX. I used Pane to show moving shapes (circle, Rectange) on it. The problem happens when I resize the window to a larger area. When I do that, then the newly created area doesn't show moving shapes properly. What happens in this new area: shapes change color from black to white and they leave a white trace.
The shapes are moved using the setTranslateX (and Y) methods.
I also included a sample code below the screen shots. The code isn't the same as the one on the recorded screens, but it produces the same problem.
window with original size
resized window with an area where the shapes are not drawn properly
The FXML document named view.fxml
<?import javafx.scene.shape.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.company.bouncer.Controller">
<center>
<Pane fx:id="paneField" prefHeight="344.0" prefWidth="600.0" BorderPane.alignment="CENTER" />
</center>
<top>
<HBox alignment="CENTER_LEFT" prefHeight="56.0" prefWidth="600.0" spacing="30.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="btnLaunch" mnemonicParsing="false" onAction="#handleBtn" text="Launch" />
</children>
<opaqueInsets>
<Insets />
</opaqueInsets>
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<padding>
<Insets left="30.0" />
</padding>
</HBox>
</top>
</BorderPane>
Main class that extends Application
package com.company.bouncer;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/view.fxml"));
primaryStage.setTitle("Bouncer");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
/**
* called when the window is closed
*/
#Override
public void stop() throws Exception {
Controller.stopExecutor();
super.stop();
}
}
** Controller **
package com.company.bouncer;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
public class Controller implements Initializable {
#FXML
private Button btnLaunch;
#FXML
private Pane paneField;
private ShapePlatform shapeRunnable;
private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
#Override
public void initialize(URL location, ResourceBundle resources) {
shapeRunnable = new ShapePlatform();
paneField.setBackground(new Background(new BackgroundFill(Color.web("#aaaaaa"), CornerRadii.EMPTY, Insets.EMPTY)));
executor.scheduleAtFixedRate(shapeRunnable, 0, 10, TimeUnit.MILLISECONDS);
}
#FXML
private void handleBtn(){
shapeRunnable.generateShapeMover();
}
public static void stopExecutor(){
executor.shutdown();
}
public class ShapePlatform implements Runnable {
private List<ShapeMover> shapeList = new ArrayList<>();
/**
* Constructor
* #param parentPane Pane on which the shapes will be displayed
*/
public ShapePlatform(){
}
/**
* creates a new shape and adds it to the shapeList
*/
public void generateShapeMover(){
Shape newShape = new Rectangle(0, 0, 100, 80);
paneField.getChildren().add(newShape);
//position the object in some random location on the pane
newShape.setTranslateX(300);
newShape.setTranslateY(300);
//wrap it in shape mover
ShapeMover shapeMover = new ShapeMover(newShape);
shapeList.add(shapeMover);
}
/**
* executes one frame of moving objects
*/
private void moveAllOnce(){
shapeList.forEach(sm -> sm.move());
}
/**
* moves all objects, checks any intersections between objects
* and changes their direction if there is an intersection
*/
#Override
public void run() {
moveAllOnce();
}
public class ShapeMover {
private Shape shape;
private int xDir = 1;
private int yDir = 1;
private int periodSpeed = 1;
private int periodSpeedCountDown = periodSpeed;
/**
* constructs the object
* #param shape - shape to be moved
*/
public ShapeMover(Shape shape){
this.shape = shape;
}
/**
* moves object for one iteration
*/
public void move(){
if(periodSpeedCountDown == 0){
shape.setTranslateX(shape.getTranslateX() + xDir);
shape.setTranslateY(shape.getTranslateY() + yDir);
periodSpeedCountDown = periodSpeed;
} else {
periodSpeedCountDown--;
}
}
}
}
}

So, the problem was actually that I was running the movement handling background thread which probably produced my problem. With a suggestion from #James_D I implemented the movement handling using extention of AnimationTimer, and now the menitoned problem is gone.
The new code is int under the text. I still have to implement a mechanism to handle the right timing as now there are no periods defined in AnimationTimer
public class Controller implements Initializable {
#FXML
private Button btnLaunch;
#FXML
private Pane paneField;
private ShapePlatform shapeAnimTimer;
private static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
#Override
public void initialize(URL location, ResourceBundle resources) {
paneField.setBackground(new Background(new BackgroundFill(Color.web("#aaaaaa"), CornerRadii.EMPTY, Insets.EMPTY)));
shapeAnimTimer = new ShapePlatform();
shapeAnimTimer.start();
}
#FXML
private void handleBtn(){
shapeAnimTimer.generateShapeMover();
}
public static void stopExecutor(){
executor.shutdown();
}
public class ShapePlatform extends AnimationTimer {
private List<ShapeMover> shapeList = new ArrayList<>();
/**
* creates a new shape and adds it to the shapeList
*/
public void generateShapeMover(){
Shape newShape = new Rectangle(0, 0, 100, 80);
paneField.getChildren().add(newShape);
//position the object in some random location on the pane
newShape.setTranslateX(300);
newShape.setTranslateY(300);
//wrap it in shape mover
ShapeMover shapeMover = new ShapeMover(newShape);
shapeList.add(shapeMover);
}
/**
* executes one frame of moving objects
*/
private void moveAllOnce(){
shapeList.forEach(sm -> sm.move());
}
/**
* moves all objects, checks any intersections between objects
* and changes their direction if there is an intersection
* #param now current frame
*/
#Override
public void handle(long now) {
System.out.println(now);
moveAllOnce();
}
public class ShapeMover {
private Shape shape;
private int xDir = 1;
private int yDir = 1;
private int periodSpeed = 1;
private int periodSpeedCountDown = periodSpeed;
/**
* constructs the object
* #param shape - shape to be moved
*/
public ShapeMover(Shape shape){
this.shape = shape;
}
/**
* moves object for one iteration
*/
public void move(){
if(periodSpeedCountDown == 0){
shape.setTranslateX(shape.getTranslateX() + xDir);
shape.setTranslateY(shape.getTranslateY() + yDir);
periodSpeedCountDown = periodSpeed;
} else {
periodSpeedCountDown--;
}
}
}
}
}

Related

Can't seem to programmatically select TextField from TableCell (TextFieldTableCell-like) when adding a row to TableView (JavaFX 8)

In JavaFX 8, I have created a custom TableCell with a TextField to get more control than with a "regular" TextFieldTableCell. What I want to achieve is to have that TextField automatically selected when an Add button is clicked (so the user doesn't have to click on that TextField or Tab to it after the Add-Record button is fired. Unfortunately, I only manage to select the row/cell but not the underlying TextField (and the startEdit() method doesn't seem to be reached).
Here is my code (Main FX Application code, POJO, FXML code created in Scene Builder, Controller code, and CustomTextFieldTableCell class):
Main.java
package test;
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 {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
POJO
package test;
import javafx.beans.property.SimpleStringProperty;
class TestObject {
private final SimpleStringProperty field1 = new SimpleStringProperty();
private final SimpleStringProperty field2 = new SimpleStringProperty();
public SimpleStringProperty field1Property() {
return field1;
}
public void setField1(String string) {
field1.set(string);
}
public SimpleStringProperty field2Property() {
return field2;
}
public void setField2(String string) {
field2.set(string);
}
}
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="425.0" prefWidth="517.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.171" fx:controller="test.FXMLDocumentController">
<children>
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<TableView fx:id="tableView" layoutX="14.0" layoutY="52.0" prefHeight="359.0" prefWidth="489.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="52.0">
<columns>
<TableColumn fx:id="col1" prefWidth="150.0" text="C1" />
<TableColumn fx:id="col2" minWidth="0.0" prefWidth="141.0" text="C2" />
</columns>
</TableView>
<Button fx:id="btnAdd" layoutX="14.0" layoutY="14.0" onAction="#handleAdd" text="_Add" />
</children>
</AnchorPane>
FXMLDocumentController.java
package test;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
public class FXMLDocumentController implements Initializable {
#FXML
private Button btnAdd;
#FXML
private TableView<TestObject> tableView;
#FXML
private TableColumn<TestObject, String> col1;
#FXML
private TableColumn<TestObject, String> col2;
#FXML
private void handleAdd(ActionEvent event) {
TestObject testObject = new TestObject();
tableView.getItems().add(testObject);
tableView.edit(tableView.getItems().indexOf(testObject), col1);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
col1.setCellValueFactory(cellData -> cellData.getValue().field1Property());
col1.setCellFactory((final TableColumn<TestObject, String> column) -> new CustomTextFieldTableCell());
col1.setOnEditStart((TableColumn.CellEditEvent<TestObject, String> event) -> {
//Inside code doesn't seem to ever get reached
System.out.println("Edit started");
});
col2.setCellValueFactory(cellData -> cellData.getValue().field2Property());
col2.setCellFactory((final TableColumn<TestObject, String> column) -> new TableCell<>());
}
}
CustomTextFieldTableCell.java
package test;
import javafx.event.ActionEvent;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
public class CustomTextFieldTableCell extends TableCell<TestObject, String> {
private final TextField textField;
public CustomTextFieldTableCell() {
textField = new TextField();
textField.setOnAction((ActionEvent event) -> {
commitEdit(textField.getText());
event.consume();
});
textField.prefWidthProperty().bind(prefWidthProperty().subtract(3));
}
/** {#inheritDoc} */
#Override
public void startEdit() {
if (!isEditable()
|| getTableView() == null
|| getTableColumn() == null
|| getTableView() != null && !getTableView().isEditable()
|| getTableColumn() != null && !getTableColumn().isEditable()) {
return;
}
super.startEdit();
if (isEditing()) {
/*
textField.setText(getItem().trim());
this.setText(textField.getText());
*/
//Platform.runLater(() -> textField.requestFocus());
textField.requestFocus();
}
}
/** {#inheritDoc} */
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if (empty) {
setGraphic(null);
} else {
textField.setText(item == null ? "" : item.trim());
setGraphic(textField);
}
}
}
What visually occurs:
What I need my code to do is to have caret placed inside the TextField or TextField focused, but this doesn't occur with my code right now.
Any idea what I am missing out?

How to add data to tableView even if the textfield is empty?

I'm trying to make a program which gets data from textfield, adds it to tableview and then to DB. The problem is, that I also need a tableview to accept an empty textfield value.
This is how I add values to the tableview:
public void pievButtonClicked() {
int kods = Integer.parseInt(kodsT.getText());
String nosaukums = nosaukumsT.getText();
int inventars = Integer.parseInt(iegadesT.getText());
double uzskaite = Double.parseDouble(uzskaitesT.getText());
double iegade = Double.parseDouble(iegadesT.getText());
data.addAll(new Interjers(kods, nosaukums, inventars, uzskaite, iegade));
}
Maybe I need to change "Interijers" class or I need to change setCellValueFactory is some way. I really don't know.
I don't know what do want exactly ! but i made this example for you ,it seems explain your need
Model class:
package javafxapplication4;
public class Model {
String name;
String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public Model(String name, String age) {
this.name = name;
this.age = age;
}
public void setAge(String age) {
this.age = age;
}
}
Fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" styleClass="mainFxmlClass" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111" fx:controller="javafxapplication4.HomeController">
<stylesheets>
<URL value="#home.css" />
</stylesheets>
<children>
<TextField fx:id="nameField" layoutY="30.0" />
<TextField fx:id="ageField" layoutX="226.0" layoutY="30.0" />
<Button layoutX="451.0" layoutY="30.0" mnemonicParsing="false" onAction="#addLine" text="Button" />
<TableView fx:id="view" layoutX="52.0" layoutY="100.0" prefHeight="200.0" prefWidth="506.0">
<columns>
<TableColumn fx:id="nameCo" prefWidth="75.0" text="Name" />
<TableColumn fx:id="ageCo" prefWidth="75.0" text="Age" />
</columns>
</TableView>
</children>
</AnchorPane>
Controller class :
package javafxapplication4;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
/**
* FXML Controller class
*
* #author Ala_Eddine
*/
public class HomeController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML
public TableView<Model> view;
#FXML
public TableColumn<Model, String> nameCo;
#FXML
public TableColumn<Model, String> ageCo;
#FXML
public TextField nameField;
#FXML
public TextField ageField;
#Override
public void initialize(URL url, ResourceBundle rb) {
nameCo.setCellValueFactory(new PropertyValueFactory<>("name"));
ageCo.setCellValueFactory(new PropertyValueFactory<>("age"));
}
#FXML
public void addLine() {
String name = nameField.getText();
String age = ageField.getText();
Model model = new Model(name, age);
view.getItems().add(model);
}
}
Main class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javafxapplication4;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author Ala_Eddine
*/
public class JavaFXApplication4 extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Stage stage=new Stage();
Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Result

How to switch stages in JavaFX

I have a login stage (300 x 250), I want to open another main stage (fullscreen) if the credentials are correct.
I have figured out how to check the login credentials, but how can I close the login stage and open another stage?
If my application is supposed to work in one window I prefer using a GUI manager singleton class, which manages changing windows. Below I provided the complete code of a simple application which uses this mechanism. Let's assume all the files are in one package, called sample.
Main.java - you initialize the JavaFX components here:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/sample/root.fxml"));
try{
StackPane rootPane;
rootPane = loader.load();
GuiManager guiModel = GuiManager.getInstance();
guiModel.setRootPane(rootPane);
Scene scene = new Scene(rootPane);
primaryStage.setScene(scene);
primaryStage.show();
guiModel.changeWindow("/sample/firstwindow.fxml");
} catch (IOException exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
root.fxml - all the windows are supposed to be based on it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<StackPane fx:id="rootPane"
xmlns="http://javafx.com/javafx/8.0.60"
xmlns:fx="http://javafx.com/fxml/1"
prefWidth="1" prefHeight="1"/>
firstwindow.fxml - first actual window which will be displayed:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.FirstWindowController">
<Label text="First window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
FirstWindowController.java - a controller class of the first window:
package sample;
import javafx.fxml.FXML;
public class FirstWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/secondwindow.fxml");
}
}
secondwindow.fxml - it will be displayed after clicking the button of the first window:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.SecondWindowController" >
<Label text="Second window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
SecondWindowController.java - a controller class of the second window:
package sample;
import javafx.fxml.FXML;
public class SecondWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/firstwindow.fxml");
}
}
GuiManager.java - a class that manages changing windows based on the root:
package sample;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.io.IOException;
public class GuiManager {
private StackPane rootPane;
private static GuiManager instance;
public static GuiManager getInstance() {
if (instance == null) {
instance = new GuiManager();
}
return instance;
}
private GuiManager() {}
public void changeWindow(String path) {
changeWindow(rootPane, path, this);
rootPane.setPrefWidth(-1);
rootPane.setPrefHeight(-1);
}
public static void changeWindow(Pane pane, String newWindowPath, Object callingController) {
Window window = pane.getScene().getWindow();
double x = window.getX() + getHorizontalMidpoint(window);
double y = window.getY() + getVerticalMidpoint(window);
ObservableList<Node> childrenList = pane.getChildren();
removeAllIncludedChildren(childrenList);
FXMLLoader loader = new FXMLLoader(callingController.getClass().getResource(newWindowPath));
try {
pane.getChildren().add(loader.load());
Stage primaryStage = (Stage) window;
primaryStage.setMinHeight(0);
primaryStage.setMinWidth(0);
window.sizeToScene();
window.setX(x - getHorizontalMidpoint(window));
window.setY(y - getVerticalMidpoint(window));
primaryStage.setMinHeight(window.getHeight());
primaryStage.setMinWidth(window.getWidth());
} catch (IOException exception) {
exception.printStackTrace();
}
}
private static double getHorizontalMidpoint(Window window) {
int horizontalBisectionCoefficient = 2;
return window.getWidth() / horizontalBisectionCoefficient;
}
private static double getVerticalMidpoint(Window window) {
int verticalBisectionCoefficient = 2;
return window.getHeight() / verticalBisectionCoefficient;
}
private static void removeAllIncludedChildren(ObservableList<Node> childrenList) {
for (int childIndex = 0; childIndex < childrenList.size(); childIndex++) {
childrenList.remove(childIndex);
}
}
public void setRootPane(StackPane rootPane) {
this.rootPane = rootPane;
}
}
I just run in the same issue and this answer solved my issue perfectly while being short and clean.
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
//Here I want to swap the screen!
Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
// OR
Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
// these two of them return the same stage
// Swap screen
stage.setScene(new Scene(new Pane()));
}
PS.: Remember to click the original answer and upvote it. The guy deserves...
PPS.: I am not sure just copying an answer is okay(instead of just share the link through a comment) but since this doesnt have a correct answer yet i decided to do it for visibility.

Create a Circle on Clicking Button JavaFX

I try to create a new shape (Circle for this example) by clicking a button.
I'm not completely in JavaFX yet so there are small problems in executing. I'm familiar with changing sizes, colors and so on of existing shapes, but I don't know how to create something on a click.
My Controller and my Main so far:
package javafxapplication1;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
/**
*
* #author Tom
*/
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
--------------------here starts the controller---------------
package javafxapplication1;
import java.awt.Paint;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
/**
*
* #author Tom
*/
public class FXMLDocumentController implements Initializable {
#FXML
private Button btn;
#FXML
public void pressButton(ActionEvent event){
Circle kreis1;
kreis1 = new Circle(200, 200, 10, Color.BLACK);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Could you please help me? I need these basics but can't find any explanation online! Thx in advance!
You actually almost did it, only missing two things.
First of all you did not include FXMLDocument.fxml but I assume pressButton method is bound to the onAction event of the button.
You created a Circle on your button action, now you need to add that circle to a pane. Without adding to a pane that circle would not be seen.
For example if we had this fxml;
<AnchorPane fx:id="root" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<Button fx:id="btn" layoutX="271.0" layoutY="331.0" onAction="#pressButton" text="Button" />
</children>
</AnchorPane>
We have an AnchorPane with fx:id="root" and we want to add circles to that on button action.
Now in our controller class, we need to bind the AnchorPane
#FXML private AnchorPane root;
Now just add your circle to this root in your pressButton method.
#FXML
public void pressButton(ActionEvent event){
Circle kreis1;
kreis1 = new Circle(200, 200, 10, Color.BLACK);
root.getChildren().add(kreis1);
}
That would create a circle in x,y coordinates 200,200.
For example this pressButton method would create circles with random coordinates and random colors in the Pane.
#FXML
public void pressButton(ActionEvent event) {
Random rand = new Random();
int x = rand.nextInt(500) + 1;
int y = rand.nextInt(400) + 1;
int r = rand.nextInt(40) + 10;
double red = rand.nextDouble();
double green = rand.nextDouble();
double blue = rand.nextDouble();
Circle kreis1;
kreis1 = new Circle(x, y, r, new Color(red, green, blue,1));
root.getChildren().add(kreis1);
}

JavaFX: How to drag imageview on a Pane

Can somebody give a simple example about how to set up the EventHandler for dragging imageviews on a Pane(JavaFX). For dragging I mean press the mouse on the image, drag and image should follow, then release the mouse and the imageview will stop at that location.
read docs first Drag and drop in javafx
or you can do it yourself by getMouseX and getMouseY points and change the coordinates of the imageView in AnchorPane ....
I wanted to try out the proposed solution with the drag and drop. I find it to be not optimal.
By doing it with drag and drop you trigger some mechanisms that are unnecessary:
You can drag it outside of your application
Cursor changes ...
I also had problems that the calulation of the position delta seems to be speed dependent
Nether the less, in case someone is interested this is my code:
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 {
#Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Controller controller = new Controller();
loader.setController(controller);
Parent root = (Parent)loader.load();
controller.InitUi();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java
package sample;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.input.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Rectangle;
public class Controller
{
#FXML
private Rectangle draggable;
private Double lastX = null;
private Double lastY = null;
public void InitUi()
{
if (this.draggable != null)
{
this.draggable.setOnDragOver(new EventHandler<DragEvent>()
{
#Override
public void handle(DragEvent dragEvent)
{
HandleMouseMovement(dragEvent.getSceneX(), dragEvent.getSceneY());
}
});
this.draggable.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
Dragboard db = draggable.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
content.putString("Does not matter");
db.setContent(content);
event.consume();
lastX = event.getSceneX();
lastY = event.getSceneY();
}
});
}
}
private synchronized void HandleMouseMovement(double sceneX, double sceneY)
{
double deltaX = sceneX - lastX;
double deltaY = sceneY - lastY;
lastX = sceneX;
lastY = sceneY;
double currentXAnchor =AnchorPane.getLeftAnchor(this.draggable);
double currentYAnchor =AnchorPane.getTopAnchor(this.draggable);
AnchorPane.setLeftAnchor( this.draggable, currentXAnchor + deltaX*1.5);
AnchorPane.setTopAnchor(this.draggable, currentYAnchor + deltaY*1.5);
}
}
sample.fxml
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Rectangle?>
<GridPane xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10" prefHeight="500" prefWidth="500">
<AnchorPane>
<Rectangle fx:id="draggable" width="40" height="50" AnchorPane.topAnchor="20" AnchorPane.leftAnchor="20"/>
</AnchorPane>
</GridPane>

Resources