How to generate rectangle with user values in output? - javafx

I have seen examples of Rectangle in JavaFx. But Please can anybody Provide me the example where in output window/Scene, if user put desirable width and height, rectangle should be generated automatically.
here is my example
VBox vb = new VBox(20);
HBox h1 = new HBox(7);
HBox h2 = new HBox(7);
Label lebel1 = new Label("X:");
Label lebel2 = new Label("Y:");
TextField txt1 = new TextField();
TextField txt2 = new TextField();
//Converting textfield to integer only
ChangeListener<String> forceNumberListener = (observable, oldValue, newValue) -> {
if (!newValue.matches("\\d*"))
((StringProperty) observable).set(oldValue);
};
txt1.textProperty().addListener(forceNumberListener);
txt2.textProperty().addListener(forceNumberListener);
double width = Double.parseDouble(txt1.getText());
double height = Double.parseDouble(txt2.getText());
Rectangle rect1 = new Rectangle();
rect1.setHeight(height);
rect1.setWidth(width);
h1.getChildren().addAll(lebel1, txt1);
h2.getChildren().addAll(lebel2, txt2);
vb.getChildren().addAll(h1,h2,rect1);
If user put any integer value in "x" as width, "y" as height, Rectangle should be generated below fields. but this code is wrong and i don't know other methods. Please
Thank you so much

You should use the TextField's onkeyreleased event handler. In this app, if both TextFields have a number typed in, a rectangle will be generated. Both TextFields have an event handler that does the same thing if one of their text is changed. This does not catch for any non-double values.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication104 extends Application
{
#Override
public void start(Stage primaryStage)
{
BorderPane root = new BorderPane();
VBox vbox = new VBox();
vbox.setMinWidth(100);
TextField textfield1 = new TextField();
TextField textfield2 = new TextField();
textfield1.setPrefWidth(50);
textfield1.setPromptText("Enter height");
textfield1.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textfield1.getText().length() > 0 && textfield2.getText().length() > 0)
{
Rectangle rectangle = new Rectangle();
rectangle.setHeight(Double.parseDouble(textfield1.getText()));
rectangle.setWidth(Double.parseDouble(textfield2.getText()));
rectangle.setFill(Color.BLUE);
root.setCenter(rectangle);
}
}
});
textfield2.setPrefWidth(100);
textfield2.setPromptText("Enter length");
textfield2.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textfield1.getText().length() > 0 && textfield2.getText().length() > 0)
{
Rectangle rectangle = new Rectangle();
rectangle.setHeight(Double.parseDouble(textfield1.getText()));
rectangle.setWidth(Double.parseDouble(textfield2.getText()));
rectangle.setFill(Color.BLUE);
root.setCenter(rectangle);
}
}
});
vbox.getChildren().addAll(textfield1, textfield2);
root.setLeft(vbox);
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}

Related

How to stop transition when checkbox is unchecked javafx

So I've made a checkbox that applies a scale transition to a rectangle when checked. But the problem is that the transition keeps going even after I uncheck the checkbox. Any ideas on how to make it stop after un-checking?
checkbox.setOnAction(e -> {
ScaleTransition scaleT = new ScaleTransition(Duration.seconds(5), rectangle);
scaleT.setAutoReverse(true);
scaleT.setCycleCount(Timeline.INDEFINITE);
scaleT.setToX(2);
scaleT.setToY(2);
scaleT.play();
});
To control the animation, you need to define the transistion(with INDEFINITE cycle count) outside the CheckBox listener/action. Then you can just play/pause the animation as you required.
Below is the quick demo:
import javafx.animation.ScaleTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ScaleTransitionDemo extends Application {
#Override
public void start(Stage stage) {
Shape rectangle = new Rectangle(50, 50, Color.BLUE);
ScaleTransition transition = new ScaleTransition(Duration.seconds(1), rectangle);
transition.setDuration(Duration.seconds(1));
transition.setAutoReverse(true);
transition.setCycleCount(Timeline.INDEFINITE);
transition.setToX(3);
transition.setToY(3);
CheckBox checkBox = new CheckBox("Animate");
checkBox.selectedProperty().addListener((obs, old, selected) -> {
if (selected) {
transition.play();
} else {
transition.pause();
}
});
StackPane pane = new StackPane(rectangle);
VBox.setVgrow(pane, Priority.ALWAYS);
VBox root = new VBox(20, checkBox, pane);
root.setPadding(new Insets(10));
Scene scene = new Scene(root, 300, 300);
stage.setScene(scene);
stage.setTitle("Scale transition");
stage.show();
}
public static void main(String[] args) {
launch();
}
}
checking whether checkbox is selected or not with .isSelected() method . In this approach , scaled node will back to xy = 1 scale if checkbox is unchecked , but it will be disabled until transition ends .You can adjust setDuration . I've changed it just for gif recording. This is a single class javafx app you can try .
App.java
public class App extends Application {
#Override
public void start(Stage stage) {
Shape rectangle = new Rectangle(50, 50, Color.BLUE);
ScaleTransition scaleT = new ScaleTransition(Duration.seconds(1), rectangle);
CheckBox checkBox = new CheckBox("scale");
checkBox.setOnAction(e -> {
if (checkBox.isSelected()) {
scaleT.setDuration(Duration.seconds(1));
scaleT.setAutoReverse(true);
scaleT.setCycleCount(Timeline.INDEFINITE);
scaleT.setToX(2);
scaleT.setToY(2);
scaleT.play();
} else {
scaleT.setDuration(scaleT.getCurrentTime());
scaleT.stop();
scaleT.setCycleCount(1);
scaleT.setToX(1);
scaleT.setToY(1);
scaleT.play();
checkBox.setDisable(true);
scaleT.setOnFinished((t) -> {
checkBox.setDisable(false);
});
}
});
var scene = new Scene(new HBox(50, rectangle, checkBox), 640, 480);
stage.setScene(scene);
stage.setTitle("scale transition");
stage.show();
}
public static void main(String[] args) {
launch();
}
}

JavaFX: transparency of popup window only changes brightness, still displays as solid color and hides underlying stage

I have the main window (mainWindow.fxml) on top of which I want to display a transparent popup window (errorDialog.fxml) with 50% opacity so that the main window's content can still be seen underneath.
However, my attempts at making the background colour of overlay inside errorDialog.fxml transparent only results in the background colour being displayed as a solid 50% grey that hides the main window completely.
I tried to set the transparency both in the style attribute of "overlay" as well as in in the initialize method of controllerErrorDialog.java.
Any help is appreciated!
controllerMainWindow.java
package myPackage;
import [...];
public class controllerMainWindow extends AbstractController
{
#FXML
private Button btnOpenPopup;
#FXML
private BorderPane paneMainWindow;
//---------------------------------------------------------------------------------------------------
public void initialize()
{
}
//---------------------------------------------------------------------------------------------------
#FXML
public void handleButtonAction(ActionEvent event)
{
try {
if (event.getSource().equals(btnOpenPopup)) {
FXMLLoader errorLoader = new FXMLLoader();
errorLoader.setLocation(getClass().getResource("errorDialog.fxml"));
controllerErrorDialog errorController = new controllerErrorDialog();
errorLoader.setController(errorController);
Parent layout;
layout = errorLoader.load();
Scene errorScene = new Scene(layout);
Stage errorStage = new Stage();
errorStage.initStyle(StageStyle.UNDECORATED);
errorStage.setMaximized(true);
errorController.setStage(errorStage);
if(this.main!=null) {
errorStage.initOwner(main.getPrimaryStage());
}
errorStage.initModality(Modality.APPLICATION_MODAL);
errorStage.setScene(errorScene);
errorStage.showAndWait();
}
}catch (IOException exceptionCockpitSettings) {
System.out.println("Error when switching to cockpitSettings.");
exceptionCockpitSettings.printStackTrace();
return;
}
}
//---------------------------------------------------------------------------------------------------
}
controllerErrorDialog.java
package myPackage;
import [...];
public class controllerErrorDialog extends AbstractController implements Initializable
{
#FXML
private BorderPane overlay;
private Stage stage = null;
//-------------------------------------------------------------------------------------------------------
#Override
public void initialize(URL url, ResourceBundle rb)
{
overlay.setStyle("fx-background-color: transparent");
}
//---------------------------------------------------------------------------------------------------
public void setStage(Stage stage) {
this.stage = stage;
}
//---------------------------------------------------------------------------------------------------
}
errorDialog.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import [...]?>
<BorderPane fx:id="overlay" prefWidth="1920" prefHeight="1080" style="-fx-background-color: rgba(0,0,0,0.5)" xmlns:fx="http://javafx.com/fxml">
<top></top>
<left></left>
<center></center>
<right></right>
<bottom></bottom>
</BorderPane>
You need to make sure:
The scene has a transparent background, with errorScene.setFill(Color.TRANSPARENT);
The stage is transparent, using errorStage.initStyle(StageStyle.TRANSPARENT);
Any content (that you explicitly want to see through) other than the root has fully transparent background
Here's a complete (albeit not very user-friendly) example:
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Random;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
/**
* JavaFX App
*/
public class App extends Application {
private Random rng = new Random();
#Override
public void start(Stage stage) {
Button createError = new Button("Try something dangerous");
createError.setOnAction(e -> {
try {
throw new Exception("Boom!");
} catch (Exception exc) {
BorderPane root = new BorderPane();
root.setTop(new Label("Error"));
Label stackTrace = new Label();
StringWriter sw = new StringWriter();
exc.printStackTrace(new PrintWriter(sw));
ScrollPane scroller = new ScrollPane(stackTrace);
stackTrace.setText(sw.toString());
root.setCenter(scroller);
Button close = new Button("Close");
HBox buttons = createHBox(close);
root.setBottom(buttons);
Scene errorScene = new Scene(root, 400, 400);
errorScene.setFill(Color.TRANSPARENT);
errorScene.getStylesheets().add(getClass().getResource("transparent.css").toExternalForm());
Stage errorStage = new Stage();
close.setOnAction(evt -> errorStage.close());
errorStage.setScene(errorScene);
errorStage.initStyle(StageStyle.TRANSPARENT);
errorStage.initModality(Modality.APPLICATION_MODAL);
errorStage.initOwner(stage);
errorStage.show();
}
});
HBox buttons = createHBox(createError);
BorderPane root = new BorderPane(createContent());
root.setBottom(buttons);
Scene scene = new Scene(root, 600, 600);
stage.setScene(scene);
stage.show();
}
private HBox createHBox(Node... content) {
HBox buttons = new HBox(content);
buttons.setAlignment(Pos.CENTER);
buttons.setPadding(new Insets(2));
return buttons;
}
private Node createContent() {
Pane pane = new Pane();
for (int i = 0 ; i < 15 ; i++) {
Circle circle = new Circle(
50 + rng.nextDouble() * 500,
50 + rng.nextDouble() * 500,
50 + rng.nextDouble() * 50,
randomColor());
pane.getChildren().add(circle);
}
return pane ;
}
private Color randomColor() {
return Color.color(rng.nextDouble(), rng.nextDouble(), rng.nextDouble(), 0.5 + 0.25 * rng.nextDouble());
}
public static void main(String[] args) {
launch();
}
}
with transparent.css being:
.root {
-fx-background-color: #ffffff7f ;
}
.root HBox, .root .scroll-pane, .root .scroll-pane .viewport {
-fx-background-color: transparent ;
}

How do I show contents from the password field in javafx using checkbox [duplicate]

This question already has answers here:
How to unmask a JavaFX PasswordField or properly mask a TextField?
(7 answers)
Closed 3 years ago.
Im a student studying java and javafx, how do I show the password in the passwordfield using a checkbox? I am using gluon scenebuilder as my fxml editor
The duplicate is listed above for the correct but more complicated way of doing this. In this answer, I am showing two examples. One with a CheckBox and the other with the all-seeing eye. The eye is to use a StackPane to layer the node. For the CheckBox solution, put a TextField and then a PasswordField in the StackPane. Bring the TextField toFront when the CheckBox is checked and set its text using the PasswordField. Clear the TextField when the CheckBox is not checked and move the PasswordField toFront. For the All-seeing eye example, use the same ideas but add an ImageView and always keep the ImageView toFront.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestingGround extends Application
{
Image image = new Image("https://previews.123rf.com/images/andrerosi/andrerosi1905/andrerosi190500216/123158287-eye-icon-vector-look-and-vision-icon-eye-vector-icon.jpg");
#Override
public void start(Stage primaryStage)
{
HBox passwordControl1 = createPasswordFieldWithCheckBox();
HBox passwordControl2 = createPasswordFieldWithCheckBox();
StackPane passwordControl3 = createPasswordFieldWithEye();
StackPane passwordControl4 = createPasswordFieldWithEye();
VBox root = new VBox(passwordControl1, passwordControl2, passwordControl3, passwordControl4);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
HBox createPasswordFieldWithCheckBox()
{
PasswordField passwordField = new PasswordField();
passwordField.setPrefHeight(50);
TextField textField = new TextField();
textField.setPrefHeight(50);
passwordField.textProperty().bindBidirectional(textField.textProperty());
StackPane stackPane = new StackPane(textField, passwordField);
CheckBox checkBox = new CheckBox();
checkBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
textField.toFront();
}
else {
passwordField.toFront();
}
});
HBox root = new HBox(stackPane, checkBox);
root.setSpacing(5);
root.setAlignment(Pos.CENTER);
return root;
}
StackPane createPasswordFieldWithEye()
{
PasswordField passwordField = new PasswordField();
passwordField.setPrefHeight(50);
TextField textField = new TextField();
passwordField.textProperty().bindBidirectional(textField.textProperty());
textField.setPrefHeight(50);
ImageView imageView = new ImageView(image);
imageView.setFitHeight(32);
imageView.setFitWidth(32);
StackPane.setMargin(imageView, new Insets(0, 10, 0, 0));
StackPane.setAlignment(imageView, Pos.CENTER_RIGHT);
imageView.setOnMousePressed((event) -> {
textField.toFront();
imageView.toFront();
});
imageView.setOnMouseReleased((event) -> {
passwordField.toFront();
imageView.toFront();
});
StackPane root = new StackPane(textField, passwordField, imageView);
return root;
}
}
You could use a custom Tooltip to show the password:
import javafx.application.Application;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class FxMain extends Application {
private SimpleBooleanProperty showPassword ;
private CheckBox checkBox;
private Tooltip toolTip;
private PasswordField pF;
private Stage stage;
#Override
public void start(Stage stage) {
this.stage = stage;
showPassword = new SimpleBooleanProperty();
showPassword.addListener((ChangeListener<Boolean>) (observable, oldValue, newValue) -> {
if(newValue){
showPassword();
}else{
hidePassword();
}
});
final Label message = new Label("");
Label label = new Label("Password");
toolTip = new Tooltip();
toolTip.setShowDelay(Duration.ZERO);
toolTip.setAutoHide(false);
toolTip.setMinWidth(50);
pF = new PasswordField();
pF.setOnKeyTyped(e -> {
if ( showPassword.get() ) {
showPassword();
}
});
HBox hb = new HBox(10, label, pF);
hb.setAlignment(Pos.CENTER_LEFT);
checkBox = new CheckBox("Show password");
showPassword.bind(checkBox.selectedProperty());
VBox vb = new VBox(10, hb, checkBox, message);
vb.setPadding(new Insets(10));
stage.setScene(new Scene(vb,300,100));
stage.show();
}
private void showPassword(){
Point2D p = pF.localToScene(pF.getBoundsInLocal().getMaxX(), pF.getBoundsInLocal().getMaxY());
toolTip.setText(pF.getText());
toolTip.show(pF,
p.getX() + stage.getScene().getX() + stage.getX(),
p.getY() + stage.getScene().getY() + stage.getY());
}
private void hidePassword(){
toolTip.setText("");
toolTip.hide();
}
public static void main(String[] args) {
launch(args);
}
}

How to set popup scene mouse transparent in javafx

How to do that in JavaFX?
The popup shows up when the mouse enters a node. When the mouse enters the showing popup, the popup obscures the mouse from the node. Then the node fire exit event. How to make the popup ignore the mouse events?
code
package sample;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
primaryStage.setScene(new Scene(root, 300, 275));
Label labelNode = new Label("Label Node");
labelNode.setPrefHeight(200);
labelNode.styleProperty().set("-fx-background-color: orange");
Popup popup = new Popup();
popup.getScene().getRoot().setMouseTransparent(true);
AnchorPane popContent =new AnchorPane();
popContent.styleProperty().set("-fx-background-color: red");
popContent.setPrefHeight(100);
popContent.getChildren().add(new Label("Popup content"));
popup.getContent().add(popContent);
labelNode.setOnMouseEntered(event->{
Point3D point3D = labelNode.localToScene(event.getX(), event.getY(), 0);
popup.show(primaryStage, point3D.getX()-5, point3D.getY()-5);
});
labelNode.setOnMouseExited(event->{
popup.hide();
});
root.getChildren().add(labelNode);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Please try moving the cursor in to "yellow" several times.
Solution:
Keep two boolean nodeExited and popupExited statuses. Hide popup when both are true.
package sample;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class Main extends Application {
boolean nodeExited = false;
boolean popupExited = false;
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
primaryStage.setScene(new Scene(root, 300, 275));
Label labelNode = new Label("Label Node");
labelNode.setPrefHeight(200);
labelNode.styleProperty().set("-fx-background-color: orange");
Popup popup = new Popup();
popup.getScene().getRoot().setMouseTransparent(true);
AnchorPane popContent = new AnchorPane();
popContent.styleProperty().set("-fx-background-color: red");
popContent.setPrefHeight(100);
popContent.getChildren().add(new Label("Popup content"));
popup.getContent().add(popContent);
popup.getScene().setOnMouseEntered(event -> {
popupExited = false;
});
popup.getScene().setOnMouseExited(event -> {
popupExited = true;
if (nodeExited)
popup.hide();
});
labelNode.setOnMouseEntered(event -> {
nodeExited = false;
Point3D point3D = labelNode.localToScene(event.getX(), event.getY(), 0);
popup.show(primaryStage, point3D.getX() - 5, point3D.getY() - 5);
});
labelNode.setOnMouseExited(event -> {
nodeExited = true;
if (popupExited)
popup.hide();
});
root.getChildren().add(labelNode);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Scroll ScrollPane down or up when dragging/dropping an item into it.

I would like to have a ScrollPane scroll up or down when a user drags something to its edge. The ScrollPane would have a VBox inside it and would be inside a VBox too.
I assume I need to put something in setOnDragExited. But what exactly?
Here a minimal program for an example:
package application;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
VBox outerBox = new VBox();
outerBox.setMaxSize(700, 300);
root.setCenter(outerBox);
Label outerLabel = new Label("I am outside!");
ScrollPane sp = new ScrollPane();
outerBox.getChildren().addAll(outerLabel,sp);
VBox innerBox = new VBox();
//setting size bigger than ScrollPane's view.
innerBox.setPrefSize(600, 600);
sp.setContent(innerBox);
Label dragMe = new Label("Drag me to the edge of scroll pane! \n"+"or drop me in the scrollpane!");
root.setTop(dragMe);
dragMe.setOnDragDetected((MouseEvent event) ->{
Dragboard db = dragMe.startDragAndDrop(TransferMode.ANY);
db.setDragView(((Node) event.getSource()).snapshot(null, null));
ClipboardContent content = new ClipboardContent();
content.putString((dragMe.getText()));
db.setContent(content);
event.consume();
});
sp.setOnDragOver((DragEvent event) ->{
event.acceptTransferModes(TransferMode.MOVE);
event.consume();
});
sp.setOnDragEntered((DragEvent event) -> {
});
sp.setOnDragExited((DragEvent event) -> {
System.out.println("-----Make the scrollpane scroll up or down depending on exiting on bottem or top------");
event.consume();
});
sp.setOnDragDropped((DragEvent event) ->{
Dragboard db = event.getDragboard();
System.out.println(((VBox) sp.getContent()).getChildren().add(new Label(db.getString())));
});
Scene scene = new Scene(root,1000,1000);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Found this answer here:
Want to trigger scroll when dragging node outside the visible area in ScrollPane
It was not answered completely and did not use a ScrollPane so I thought I post my work/findings as an answer.
I found out you can do this by creating an animation:
private Timeline scrolltimeline = new Timeline();
....
scrolltimeline.setCycleCount(Timeline.INDEFINITE);
scrolltimeline.getKeyFrames()
.add(new KeyFrame(Duration.millis(20), (ActionEvent) -> { dragScroll();}));
Minimal:
package application;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private ScrollPane sp;
private Timeline scrolltimeline = new Timeline();
private double scrollVelocity = 0;
boolean dropped;
//Higher speed value = slower scroll.
int speed = 200;
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
sp = new ScrollPane();
sp.setPrefSize(300, 300);
VBox outer = new VBox(sp);
VBox innerBox = new VBox();
innerBox.setPrefSize(200,1000);
sp.setContent(innerBox);
root.setCenter(outer);
Label dragMe = new Label("drag me to edge!\n"+"or drop me in scrollpane!");
root.setTop(dragMe);
setupScrolling();
dragMe.setOnDragDetected((MouseEvent event) ->{
Dragboard db = dragMe.startDragAndDrop(TransferMode.ANY);
db.setDragView(((Node) event.getSource()).snapshot(null, null));
ClipboardContent content = new ClipboardContent();
content.putString((dragMe.getText()));
db.setContent(content);
event.consume();
});
Scene scene = new Scene(root, 640, 480);
primaryStage.setScene(scene);
primaryStage.show();
}
private void setupScrolling() {
scrolltimeline.setCycleCount(Timeline.INDEFINITE);
scrolltimeline.getKeyFrames().add(new KeyFrame(Duration.millis(20), (ActionEvent) -> { dragScroll();}));
sp.setOnDragExited((DragEvent event) -> {
if (event.getY() > 0) {
scrollVelocity = 1.0 / speed;
}
else {
scrollVelocity = -1.0 / speed;
}
if (!dropped){
scrolltimeline.play();
}
});
sp.setOnDragEntered(event -> {
scrolltimeline.stop();
dropped = false;
});
sp.setOnDragDone(event -> {
System.out.print("test");
scrolltimeline.stop();
});
sp.setOnDragDropped((DragEvent event) ->{
Dragboard db = event.getDragboard();
((VBox) sp.getContent()).getChildren().add(new Label(db.getString()));
scrolltimeline.stop();
event.setDropCompleted(true);
dropped = true;
});
sp.setOnDragOver((DragEvent event) ->{
event.acceptTransferModes(TransferMode.MOVE);
});
sp.setOnScroll((ScrollEvent event)-> {
scrolltimeline.stop();
});
sp.setOnMouseClicked((MouseEvent)->{
System.out.println(scrolltimeline.getStatus());
});
}
private void dragScroll() {
ScrollBar sb = getVerticalScrollbar();
if (sb != null) {
double newValue = sb.getValue() + scrollVelocity;
newValue = Math.min(newValue, 1.0);
newValue = Math.max(newValue, 0.0);
sb.setValue(newValue);
}
}
private ScrollBar getVerticalScrollbar() {
ScrollBar result = null;
for (Node n : sp.lookupAll(".scroll-bar")) {
if (n instanceof ScrollBar) {
ScrollBar bar = (ScrollBar) n;
if (bar.getOrientation().equals(Orientation.VERTICAL)) {
result = bar;
}
}
}
return result;
}
public static void main(String[] args) {
launch(args);
}
}
JavaFX-8 has not public API to scroll a ScrollPane to a certain position (https://bugs.openjdk.java.net/browse/JDK-8102126) and cast your vote to get such API in.
A hack to scroll to a certain position in Java8 (who will break in Java9!) is to get the Skin of the ScrollPane who is of type ScrollPaneSkin and call the onTraverse-method there.

Resources