Node movement - JavaFX - java

I have this programming working for the most part. The circle seems to only be able to move in a small area. Then it hits a border. Why is this? Do I need to make circlePane larger?
MoveTheCircle:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class MoveTheCircle extends Application {
private CirclePane circlePane = new CirclePane();
public void start(Stage primaryStage) {
HBox hBox = new HBox();
hBox.setSpacing(10);
hBox.setAlignment(Pos.CENTER);
Button btLeft = new Button("Left");
Button btRight = new Button("Right");
Button btUp = new Button("Up");
Button btDown = new Button("Down");
hBox.getChildren().add(btLeft);
hBox.getChildren().add(btRight);
hBox.getChildren().add(btUp);
hBox.getChildren().add(btDown);
btLeft.setOnAction(e -> circlePane.left());
btRight.setOnAction(e -> circlePane.right());
btUp.setOnAction(e -> circlePane.up());
btDown.setOnAction(e -> circlePane.down());
circlePane.setOnMouseClicked(e -> {
if (e.getButton() == MouseButton.PRIMARY) {
circlePane.left();
} else if (e.getButton() == MouseButton.PRIMARY) {
circlePane.right();
} else if (e.getButton() == MouseButton.PRIMARY) {
circlePane.up();
} else if (e.getButton() == MouseButton.PRIMARY) {
circlePane.down();
}
});
BorderPane borderPane = new BorderPane();
borderPane.setCenter(circlePane);
borderPane.setBottom(hBox);
BorderPane.setAlignment(hBox, Pos.CENTER);
Scene scene = new Scene(borderPane, 350, 250);
primaryStage.setTitle("Move The Ball");
primaryStage.setScene(scene);
primaryStage.show();
}
class CirclePane extends StackPane {
private Circle circle = new Circle(25);
public CirclePane() {
getChildren().add(circle);
circle.setStroke(Color.BLACK);
circle.setFill(Color.WHITE);
}
public void left() {
circlePane.getTranslateX();
circlePane.setTranslateX(-10);
}
public void right() {
circlePane.getTranslateX();
circlePane.setTranslateX(+10);
}
public void up() {
circlePane.getTranslateY();
circlePane.setTranslateY(-10);
}
public void down() {
circlePane.getTranslateY();
circlePane.setTranslateY(+10);
}
}
public static void main(String[] args) {
launch(args);
}
}
Any and all help is appreciated.

You need to have
public void left() {
circle.setTranslateX(circle.getTranslateX()-10);
}
instead of
public void left() {
circle.getTranslateX();
circle.setTranslateX(-10);
}
Any similarly for all the other methods as well.

Related

How to update part of BufferedImage and display it with javafx

I have an image. At the beginning I want the image to be displayed with only the first frame. On the keyboard with 'u' key pressed, drink water and load the second frame. If I understand correctly the whole image should be loaded at the beginning. And then I need to set new y.
How to complete this task? What is the right way to display this image?
My code in:
package testDesktopUi;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class DesktopUi extends Application {
private static int y = 0;
private static BufferedImage bufferedImage;
private static final ImageView imageView = new ImageView();
private static final HBox root = new HBox();
#Override
public void start(Stage primaryStage) throws IOException {
String path = "Bottle.png";
bufferedImage = ImageIO.read(new File(path)).getSubimage(0, 0, 32, 32);
Image image = SwingFXUtils.toFXImage(bufferedImage, null);
imageView.setImage(image);
root.getChildren().add(imageView);
Scene scene = new Scene(root);
scene.setOnKeyPressed(key -> {
if (key.getCode() == KeyCode.U) {
System.out.println("u pressed");
updateImage(bufferedImage);
System.out.println(y);
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
private static void updateImage(BufferedImage bufferedImage) {
int maxHeight = 352;
if (y + 32 >= maxHeight) {
y = 0;
} else {
y += 32;
}
//?? bufferedImage.getSubimage(0, y, 32, 32);
}
}
If you're using JavaFX, stick just to the JavaFX image API: there is no need to first load an AWT BufferedImage and convert it to a JavaFX image.
To display portions of an image, you can create an ImageView from the image and set the ImageView's viewport.
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class DesktopUi extends Application {
private int y = 0;
private final ImageView imageView = new ImageView();
private final HBox root = new HBox();
#Override
public void start(Stage primaryStage) {
String path = "Bottle.png";
// Assumes Bottle.png is in the same package as the current class:
Image image = new Image(getClass().getResource("Bottle.png").toExternalForm());
imageView.setImage(image);
// display only a portion of the image:
imageView.setViewport(new Rectangle2D(0, y, 32, 32));
root.getChildren().add(imageView);
Scene scene = new Scene(root);
scene.setOnKeyPressed(key -> {
if (key.getCode() == KeyCode.U) {
System.out.println("u pressed");
System.out.println(y);
updateImage();
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
private void updateImage() {
// update y
int maxHeight = 352;
if (y + 32 >= maxHeight) {
y = 0;
} else {
y += 32;
}
// update portion of image displayed
imageView.setViewport(new Rectangle2D(0, y, 32, 32));
}
public static void main(String[] args) {
Application.launch(args);
}
}
Note this also lends itself nicely to animations:
#Override
public void start(Stage primaryStage) {
int numSprites = 11 ;
Image image = new Image(getClass().getResource("Bottle.png").toExternalForm());
imageView.setImage(image);
IntegerProperty spriteIndex = new SimpleIntegerProperty();
spriteIndex.addListener((obs, oldIndex, newIndex) -> System.out.println(newIndex));
imageView.viewportProperty().bind(Bindings.createObjectBinding(
() -> new Rectangle2D(0, spriteIndex.get() * 32 , 32, 32),
spriteIndex
));
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(5),
new KeyValue(spriteIndex, numSprites - 1)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
root.getChildren().add(imageView);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

Change object color when mouse is in and change it back when it's out JavaFx

The root is Group and 3 children has been added to the group: a square from Rectangle class, a triangle from Polygon class and a circle from Circle class. These 3 objects are all built in different colors.
Task: when the mouse is on a specific object, change the color of that object. The color will change back if the mouse is out of that object.
Here's what I did:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ColouredShapes extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Group group = new Group();
// square
Rectangle square = new Rectangle(40,40);
square.setFill(Color.BLUE);
// triangle
Polygon triangle = new Polygon();
triangle.setLayoutX(80);
triangle.getPoints().addAll(
40.0,0.0,
80.0,40.0,
0.0,40.0
);
triangle.setFill(Color.RED);
//circle
Circle circle = new Circle(20);
circle.setLayoutX(240);
circle.setCenterY(20);
// ************** where everything happens *****************
group.onMouseMovedProperty().set(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.printf("coordinate X: %.2f, coordinate Y: %.2f\n",event.getX(),event.getY());
System.out.println(event.getSource());
if (event.getSource() instanceof Rectangle) {
square.setFill(Color.MAGENTA);
} else square.setFill(Color.BLUE);
}
});
group.getChildren().add(circle);
group.getChildren().add(triangle);
group.getChildren().add(square);
Scene scene = new Scene(group,700,500);
primaryStage.setScene(scene);
primaryStage.show();
} }
The problem is event.getSource() returns a result of Group#52d9d54c[styleClass=root] rather than the class of its children. As a result, the child cannot be identified, color won't change when mouse moved in to that child.
event.getSource() returns the node which triggered the event, which in this case is the Group, since that's the node on which you registered the handler.
Use onMouseEntered and onMouseExited handlers on each of the individual nodes instead:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
public class ColoredShapes extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Group group = new Group();
// square
Rectangle square = new Rectangle(40, 40);
square.setFill(Color.BLUE);
// triangle
Polygon triangle = new Polygon();
triangle.setLayoutX(80);
triangle.getPoints().addAll(40.0, 0.0, 80.0, 40.0, 0.0, 40.0);
triangle.setFill(Color.RED);
// circle
Circle circle = new Circle(20);
circle.setLayoutX(240);
circle.setCenterY(20);
registerHandler(square, Color.BLUE, Color.MAGENTA);
registerHandler(triangle, Color.RED, Color.MAGENTA);
registerHandler(circle, Color.BLACK, Color.MAGENTA);
group.getChildren().add(circle);
group.getChildren().add(triangle);
group.getChildren().add(square);
Scene scene = new Scene(group, 700, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
private void registerHandler(Shape s, Color defaultColor, Color hoverColor) {
s.setOnMouseEntered( e -> s.setFill(hoverColor));
s.setOnMouseExited(e -> s.setFill(defaultColor));
}
}
You can also do this without using event handlers at all. Either use bindings:
square.fillProperty().bind(Bindings
.when(square.hoverProperty())
.then(Color.MAGENTA)
.otherwise(Color.BLUE));
or using CSS:
square.getStyleClass().add("square");
and then in an external CSS file:
.square {
-fx-fill: blue ;
}
.square:hover {
-fx-fill: magenta ;
}

Add address bar to Java WebView

I have this code that creates a Java window that displays web pages, however I want the user to be able to go to other web pages with their own free will. So I was wondering if it is possible to put in an address bar so user can input a site address and go there, as well as putting in forward and backward buttons. Here is my Java code:
package stallionbrowser;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
/**
*
* #author seanguy4
*/
public class StallionBrowser extends Application {
private Scene scene;
#Override public void start(Stage stage) {
// create the scene
stage.setTitle("Web View");
scene = new Scene(new Browser(),750,500, Color.web("#666970"));
stage.setScene(scene);
scene.getStylesheets().add("webviewsample/BrowserToolbar.css");
stage.show();
}
public static void main(String[] args){
launch(args);
}
}
class Browser extends Region {
final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
public Browser() {
//apply the styles
getStyleClass().add("browser");
// load the web page
webEngine.load("http://www.stallionware.weebly.com");
//add the web view to the scene
getChildren().add(browser);
}
private Node createSpacer() {
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
return spacer;
}
#Override protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
layoutInArea(browser,0,0,w,h,0, HPos.CENTER, VPos.CENTER);
}
#Override protected double computePrefWidth(double height) {
return 750;
}
#Override protected double computePrefHeight(double width) {
return 500;
}
}

JavaFx how to move the window position with Timeline

I have this Stage and when im showing it . I want it to display at bottom of the screen and then go up to the center screen.
just like a notification .
my code
try {
Stage window = new Stage();
window.initModality(Modality.APPLICATION_MODAL);
window.setTitle(Message);
AnchorPane layout = (AnchorPane) FXMLLoader.load(Notification.class.getResource("window.fxml"));
Scene scene = new Scene(layout);
window.setScene(scene);
window.showAndWait();
} catch (Exception e) {
System.out.println(e);
}
Create a property specifically for the Timeline, and then add a listener to it:
double startPos = ... ;
double endPos = ... ;
DoubleProperty y = new SimpleDoubleProperty(startPos);
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new KeyValue(y, endPos)));
y.addListener((obs, oldValue, newValue) ->
window.setY(newValue.doubleValue()));
timeline.play();
SSCCE:
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Popup;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;
public class SlidingNotificationWindow extends Application {
#Override
public void start(Stage primaryStage) {
Button button = new Button("Show notification");
button.setOnAction(e -> {
Popup window = new Popup();
StackPane content = new StackPane(new Label("Notification"));
content.setStyle("-fx-background-color: aquamarine; -fx-padding: 40;");
content.setOnMouseClicked(evt -> window.hide());
window.getContent().add(content);
window.setWidth(120);
window.setHeight(75);
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
double startPos = primaryScreenBounds.getMaxY();
double endPos = 2*primaryScreenBounds.getMinY()/3 + primaryScreenBounds.getMaxY() / 3 ;
DoubleProperty y = new SimpleDoubleProperty(startPos);
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new KeyValue(y, endPos)));
y.addListener((obs, oldValue, newValue) ->
window.setY(newValue.doubleValue()));
timeline.play();
window.setX(primaryScreenBounds.getMaxX() - 120);
window.show(primaryStage);
});
StackPane root = new StackPane(button);
primaryStage.setScene(new Scene(root, 350, 120));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You need to add a Timer where the window will be moved. This is because the Window/Stage only have ReadOnlyProperties for X and Y values, so you cannot make a simple Timeline Animation with Keyframes.
You need to play a bit with the height and width of the primaryScreenBounds, so it will fit your needs.
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class TimelineEvents extends Application {
private AnimationTimer timer;
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
double x = primaryScreenBounds.getMaxX() - 180;
double y = primaryScreenBounds.getMaxY() - 180;
double centerX = primaryScreenBounds.getWidth() / 2;
double centerY = primaryScreenBounds.getHeight() / 2;
double tickX = (x - centerX) / primaryScreenBounds.getWidth() * 10;
double tickY = (y - centerY) / primaryScreenBounds.getHeight() * 10;
#Override
public void start(Stage stage) {
Button btn = new Button();
btn.setText("Show Message");
btn.setOnAction((ActionEvent event) -> {
Label l = new Label("Message");
BorderPane root = new BorderPane(l);
Scene s = new Scene(root, 100, 100);
Stage window = new Stage();
window.setX(x);
window.setY(y);
timer = new AnimationTimer() {
#Override
public void handle(long l) {
x = x - tickX;
y = y - tickY;
if (x >= centerX) {
window.setX(x);
window.setY(y);
} else {
stop();
}
}
};
timer.start();
window.setScene(s);
window.showAndWait();
});
BorderPane pane = new BorderPane(btn);
Scene scene = new Scene(pane, 200, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}

Dragging Function does not work correctly! JavaFX VBox Dragging

I create a new Stage in the Code and it's needed, that the Stage is undecorated! In this case the new created Stage loses the Drag-Function.
I created the following code, now i can drag the Stage, but the handling is incorrect and the Stage follows not in a correct way the Mouse.
I hope you can tell me my mistake and fix my error.
Thanks for your help.
EXAMPLE - CODE:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuBar;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class DragStuff extends Application{
VBox mainContainer;
Stage mainSt;
#Override
public void start(Stage mainStage) throws Exception {
// TODO Auto-generated method stub
mainStage.initStyle(StageStyle.UNDECORATED);
mainSt = mainStage;
mainContainer = new VBox();
mainContainer.setStyle("-fx-background-color:red");
Label headlineInformation = new Label("Testing");
headlineInformation.getStyleClass().addAll("popup-label-name");
headlineInformation.setMaxWidth(Double.MAX_VALUE);
Button closeButton = new Button("X");
closeButton.setVisible(true);
closeButton.getStyleClass().addAll("popup-button",
"popup-button-color");
HBox headContainer = new HBox();
HBox.setHgrow(headlineInformation, Priority.ALWAYS);
headContainer.setPadding(new Insets(5, 5, 5, 5));
headContainer.getChildren().addAll(headlineInformation, closeButton);
Pane pane = new Pane();
pane.getChildren().addAll(new Label("Text Stuff"));
mainContainer.getChildren().addAll(headContainer,pane);
Scene sc = new Scene(mainContainer);
mainStage.setScene(sc);
mainStage.show();
dragHandling();
}
public void dragHandling()
{
final ObjectProperty<Point2D> mouseKoordinates = new SimpleObjectProperty<>();
mainContainer.setOnMousePressed(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent event)
{
mouseKoordinates.set(new Point2D(event.getSceneX(), event.getSceneY()));
mainContainer.getScene().setCursor(Cursor.HAND);
};
});
mainContainer.setOnMouseReleased(new EventHandler<MouseEvent>()
{
#Override
public void handle(final MouseEvent arg0)
{
mouseKoordinates.set(null);
mainContainer.getScene().setCursor(Cursor.DEFAULT);
}
});
mainContainer.setOnMouseDragged(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent event)
{
if (mouseKoordinates.get() != null)
{
double x = event.getScreenX();
double deltaX = x - mouseKoordinates.get().getX();
double y = event.getScreenY();
double deltaY = y - mouseKoordinates.get().getY();
mainSt.setX(mainSt.getX() + deltaX);
mainSt.setY(mainSt.getY() + deltaY);
mouseKoordinates.set(new Point2D(x, y));
}
}
});
}
public static void main(String[] args) {
launch(args);
}
}
You must not use getScreenX() and getScreenY() in your code as they return the absolute positions. In place of them try using getX() and getY().
Moreover, I don't understand why are you using mouseKoordinates.set(new Point2D(x, y)); as well.
Try using the following code
mainContainer.setOnMouseDragged(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent event)
{
if (mouseKoordinates.get() != null)
{
double x = event.getX();
double deltaX = x - mouseKoordinates.get().getX();
double y = event.getY();
double deltaY = y - mouseKoordinates.get().getY();
mainSt.setX(mainSt.getX() + deltaX);
mainSt.setY(mainSt.getY() + deltaY);
}
}
});

Categories

Resources