Creating a Mouselistner to Javafx rectangle - java

I want to create a mouselistner on my javafx rectangle.
the idea is that the rectangle has to change color when i press it?
Does anyone know how to add a listner to shapes in Javafx?
so far ive tried this:
final Rectangle rect = new Rectangle();
rect.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
// TODO Auto-generated method stub
}
});
However i get an error saying that
the method setOnMouseClicked(new EventHandler(){}) is
undefined for the type Rectangle
Abit more information:
The only options i have for rect are these:
rect.add()
rect.contains()
rect.grow();
rect.hashcode()
rect.intersection();
and a few others of no importance.
The import i am using are the following:
import com.sun.glass.events.MouseEvent;
import com.sun.javafx.geom.Rectangle;
import com.sun.javafx.geom.Shape;

Your code looks correct and matches any examples I can find. To demonstrate this I have thrown together a quick example:
public class JavaFXApplication extends Application {
Rectangle rect = new Rectangle(100,100);
#Override
public void start(Stage primaryStage) {
rect.setFill(Color.BLUE);
rect.setOnMouseClicked(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent t) {
rect.setFill(Color.RED);
}
});
StackPane root = new StackPane();
root.getChildren().add(rect);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
}
When the rectangle is clicked, the colour changes from blue to red.
This might be a long shot but make sure you are referencing the Rectangle type from the JavaFX library and not the AWT Rectangle i.e. make sure your import is:
import javafx.scene.shape.Rectangle;
and not
import java.awt.Rectangle;
Update
As per my original comment it looks as though you are referencing the wrong import for the Rectangle type. I don't recognise the import com.sun.javafx.geom.Rectangle, is this from an older version of JavaFX?
You are also referencing the incorrect MouseEvent type.
Change:
import com.sun.glass.events.MouseEvent;
To:
import javafx.scene.input.MouseEvent;

I understand this answer is quite old -- but as an update (Java 13, JavaFX 13):
import javafx.scene.shape.Rectangle;
// ...
public void createRectangle() {
Rectangle rect = new Rectanlge(200, 200);
// On mouse click, code within here will be run.
rect.setOnMouseClicked(mouseEvent -> {
// Read from another property to toggle
rect.setFill(Color.RED);
});
// Add to scene in start()
}

Related

How to position a JavaFX context menu inside the main window?

Hi I am a JavaFX newbie and I am trying to write my first application. I want to start with an empty window and provide a popup menu that allows users to add 3D elements to the window.
I have created a simple Group containing a few trivial geometric shapes and added this group as the parent to a Scene. I define a mouse event handler for the scene and call setScene to make this the scene for my Stage (passed in to my Application's start method).
Unfortunately, I can't seem to find a way of positioning the menu correctly in response to a mouse pressed event. I get it that I need to get the X and Y coordinates from the Event, but when I pass these unchanged to the context menu show method, the menu appears in the top left-hand corner of my laptop display, rather than inside my application window.
Clearly, I need to offset these values by the origin of some other window, but what? I have tried the Scene, the Group and and the Stage, but with no success :-( This ought to be a trivial problem - where am I going wrong??
Code sample shown below:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Box;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.Sphere;
import javafx.stage.Stage;
public class PopupTest extends Application {
private static final ContextMenu contextMenu = new ContextMenu();
public static void main(String[] args) {
MenuItem cut = new MenuItem("Cut");
MenuItem copy = new MenuItem("Copy");
MenuItem paste = new MenuItem("Paste");
contextMenu.getItems().addAll(cut, copy, paste);
Application.launch(args);
}
#Override
public void start(Stage stage) {
// Create a Box
Box box = new Box(100, 100, 100);
box.setTranslateX(150);
box.setTranslateY(0);
box.setTranslateZ(400);
// Create a Sphere
Sphere sphere = new Sphere(50);
sphere.setTranslateX(300);
sphere.setTranslateY(-5);
sphere.setTranslateZ(400);
// Create a Cylinder
Cylinder cylinder = new Cylinder(40, 120);
cylinder.setTranslateX(500);
cylinder.setTranslateY(-25);
cylinder.setTranslateZ(600);
// Create a Light
PointLight light = new PointLight(Color.YELLOW);
light.setTranslateX(350);
light.setTranslateY(100);
light.setTranslateZ(300);
// Create a Camera to view the 3D Shapes
PerspectiveCamera camera = new PerspectiveCamera(false);
camera.setTranslateX(100);
camera.setTranslateY(-50);
camera.setTranslateZ(300);
// Add the Shapes and the Light to the Group
Group root = new Group(box, sphere, cylinder, light);
// Create a Scene with depth buffer enabled
Scene scene = new Scene(root, 400, 300, true);
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("mouse click detected!");
if (event.isPopupTrigger()) {
// similar results with getX() vs getSceneX() etc.
System.out.println("Display menu at (" + event.getSceneX() + "," + event.getSceneY() + ")");
contextMenu.show(root, event.getSceneX(), event.getSceneY());
}
}
});
// Add the Camera to the Scene
scene.setCamera(camera);
// Add the Scene to the Stage
stage.setScene(scene);
// Set the Title of the Stage
stage.setTitle("Trying to get popup menu working");
// Display the Stage
stage.show();
}
}

How to position a button in JavaFX scene ? ( Randomly )

I want somehow to make the button change his position randomly when i push the button. I've got one idea how to solve this problem, one of them i've highlighted below, but i already think that this is not what i need.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Ulesanne6 extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Test");
Button btn = new Button();
btn.setText("Hello");
btn.setOnAction(new EventHandler <javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent event) {
//btn.setLayoutY(Math.random());
//btn.setLayoutX(Math.random());
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
}
I think that somewhere here i suppose to do that, but i don't know how... yet.
public void handle(javafx.event.ActionEvent event) {
//btn.setLayoutY(Math.random());
//btn.setLayoutX(Math.random());
}
How about this?
public void handle(javafx.event.ActionEvent event) {
btn.setTranslateX(ThreadLocalRandom.current().nextDouble(800));
btn.setTranslateY(ThreadLocalRandom.current().nextDouble(600));
}
You might also want to make sure that the button is placed somewhere on the screen and not off the screen. So if you know the width and height of the button, take it into account.
public void handle(javafx.event.ActionEvent event) {
btn.setTranslateX(ThreadLocalRandom.current().nextDouble(800 - buttonWidth));
btn.setTranslateY(ThreadLocalRandom.current().nextDouble(600 - buttonHeight));
}
EDIT: Please note that you are using a StackPane as your root parent. StackPane likes to position its children based on alignment attribute of the StackPane. As such, for my answer to work correctly, you must make your root parent a Group instead of a StackPane. A regular Pane can also work.
Group root = new Group();

How do I make JavaFX MediaView stretch media to fill parent?

I want make JavaFX MediaView stretch to fill parent container.
I tried some methods from google before,but nothing helpful(maybe i'm not apply it right),and there is a question with same name as this,but solutions in that question maybe not suit me.
first i use the ahchorpane to anchor mediaview but find it can not stretch mediaview,and I don't know why because other controls like button can work.
Then i try bind its width and height to anchorpane(parent of mediaview)
Region region=(Region) mediaplayer.getParent();
mediaplayer.setPreserveRatio(false);
mediaplayer.fitWidthProperty().bind(region.widthProperty());
mediaplayer.fitHeightProperty().bind(region.heightProperty());
it's can expand mediaview exactly when i resize window,but can't Shrink down!
I guess it's maybe because size of region depend on it childs?
finally,i try to bind mediaview'size to stage'size,it's work,but the code looks like ugly,because i need calculate size manully.
mediaplayer.setPreserveRatio(false);
mediaplayer.fitWidthProperty().bind(stage.widthProperty().subtract(200));
mediaplayer.fitHeightProperty().bind(stage.heightProperty().subtract(135));
are there have any better solutions?
Using the code below you will see that you are able to stretch and shrink the mediaView as much as you like ( depending of the stage dimensions)
import java.io.File;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class TestApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
BorderPane pane = new BorderPane();
FileChooser fc = new FileChooser();
File mediaFile = fc.showOpenDialog(null);
MediaView moviePlayer;
if (mediaFile != null) {
MediaPlayer player = new MediaPlayer(new Media(mediaFile.toURI().toString()));
moviePlayer = new MediaView(player);
moviePlayer.setPreserveRatio(false);
moviePlayer.fitWidthProperty().bind(pane.widthProperty());
moviePlayer.fitHeightProperty().bind(pane.heightProperty());
pane.getChildren().add(moviePlayer);
player.play();
}
Scene scene = new Scene(pane, 300, 300);
stage.setScene(scene);
stage.show();
}
}
This code works with AnchorPane as well so I guess there is something else wrong with your code if you still have the issue or I haven't understand what you need. Make a simple runnable program to demonstrate the issue.
Try to add this Action-Listener for rescaling the size:
MediaView.getParent().layoutBoundsProperty().addListener(new ChangeListener<Bounds>() {
#Override
public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
mediaView.setFitHeight(newValue.getHeight());
mediaView.setFitWidth(newValue.getWidth());
}
});
This should be called every time the parent-size got changed or maximized and then the view should be resized to parent, too.

Custom minimize button do not call MouseLeave event

I have a simple stage with StageStyle.TRANSPARENT (no default buttons).
Therefore I tried to create my own custom buttons, represented each by an ImageView with the next events activated: setOnMouseEntered, setOnMouseExited and of course setOnMouseClicked.
Problem is for the Minmized Button. Is a simple implementation like below
ImageView.setOnMouseClicked((MouseEvent event) -> {
stage.setIconified(true);
});
Lets imagine that my ImageView is a White rectangle. On mouse enter event, it changes its color into Black. On mouse exit, it is going back to White color.
When the ImageView is clicked, the window will be minimized, everything perfectly workable until now.
Problem is when the application is restored (maximized), the Minimized custom button is stuck with color Black (the color that represent the button is hovered), instead of White (default color when is not focused).
P.S. it seems that everything like relocate, setImage etc. inside the onMouseClicked handler is cut by the the setInconified(true);
Any help would be most appreciated.
Thank you for your time of reading this.
Updates to clear a bit the question
The normal print-screen image (when it is not hovered)
The hover print-screen (when it is hovered)
As you can observe, everything works perfectly. In the moment when "-" button (minimize button) is pressed, when the application is restored, it will remain stuck in hover mode, until the mouse cursor will hover again the button (then everything comes back to normal). Sadly neither CSS approach or event listeners on image view dose not seems to solve this issue.
Update code loaded
This is a simple one source file with just a button that call minimize
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
private Scene scene;
private Stage stage;
#Override
public void start(Stage stage) {
try {
this.stage = stage;
stage.initStyle(StageStyle.TRANSPARENT);
stage.setAlwaysOnTop(true);
stage.setFullScreen(true);
stage.setFullScreenExitHint("");
createScene(stage);
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
private void createScene(Stage stage) {
Pane layer = new Pane();
layer.setPickOnBounds(false);
scene = new Scene(layer, 800, 600);
scene.getStylesheets().add("application/application.css");
layer.getChildren().add(buildMinimizeImage());
}
private ImageView buildMinimizeImage() {
ImageView imv = new ImageView();
int width = 43 ;
int height = 36;
imv.setId("myImage");
imv.setFitWidth(width);
imv.setFitHeight(height);
imv.setOnMouseClicked((MouseEvent event) -> {
stage.setIconified(true);
});
imv.relocate(100, 100);
return imv;
}
public static void main(String[] args) {
launch(args);
}
}
And the application.css is very simple as well
#myImage
{
-fx-image: url("minimize.png");
}
#myImage:hover
{
-fx-image: url("minimizeIn.png");
}
Issue is reproducible on Ubuntu 14.04 and Windows 10. I do not think is an OS problem
RESOLVED
Please find enclose the Harry Mitchel solution (thank you one more time for it). It is perfectly workable.
If you want to fix the code from above I by adding the setOnMousePressed event.
imv.setOnMousePressed((MouseEvent event) -> {
imv.setImage(image);
});
You can listen to the maximized property of the Stage class. Inside the changed() method, set the ImageView's image.
stage.maximizedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
//Display the desired icon here.
}
});
Here is a custom minimize button. You provide the two images and the stage as parameters. When the mouse is not over the button, it will show the image referenced in the constructor's first parameter. When the mouse is over the button, it will show the image referenced in the constructor's second parameter. When you click the image the stage will be minimized.
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
public class MinimizeButton extends Button {
/**
*
* #param img the image when the button is NOT selected
* #param imgHover the image when button is selected
* #param stage the stage that will be minimized
*/
public MinimizeButton(Image img, Image imgHover, Stage stage) {
ImageView imgView = new ImageView(img);
this.setGraphic(imgView);
this.addEventHandler(MouseEvent.MOUSE_ENTERED, (MouseEvent e) -> {
imgView.setImage(imgHover);
});
this.addEventHandler(MouseEvent.MOUSE_EXITED, (MouseEvent e) -> {
imgView.setImage(img);
});
this.setOnAction((ActionEvent event) -> {
stage.setIconified(true);
imgView.setImage(img);
});
}
}
Here is an example app that uses the MinimizeButton class.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class CustomMinimize extends Application {
#Override
public void start(Stage stage) {
Image imgWhite = new Image(getClass().getResourceAsStream("imgWhite.png")); //your image here
Image imgGreen = new Image(getClass().getResourceAsStream("imgGreen.png")); //your hover image here
MinimizeButton btnMinimize = new MinimizeButton(imgWhite, imgGreen, stage);
btnMinimize.setStyle("-fx-background-color: black;");
btnMinimize.setPrefSize(50, 50);
Button btnExit = new Button("X");
btnExit.setMinSize(50,50);
btnExit.setOnAction((ActionEvent event) -> {
System.exit(0);
});
btnExit.setStyle("-fx-background-color: black;");
HBox hBox = new HBox();
hBox.setSpacing(2);
hBox.getChildren().addAll(btnMinimize, btnExit);
AnchorPane anchorPane = new AnchorPane();
anchorPane.getChildren().addAll(hBox);
AnchorPane.setRightAnchor(hBox, 5.0);
AnchorPane.setTopAnchor(hBox, 5.0);
Scene scene = new Scene(anchorPane);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Your question is not very clear (not that it is very unclear though), so I will attempt to solve your problem.
I am assuming that your color change is done through ImageView.setOnMouseEntered() and ImageView.setOnMouseExited(). If this is so, you should instead use CSS.
.myImageView
{
-fx-image: url("my_white_image.png");
}
.myImageView:hovered
{
-fx-image: url("my_black_image.png");
}
For the things in your "PS" section, I couldn't understand, so I would not be able to give any advice on that.

Why is my object not displaying in JavaFX?

This should be a relatively simple problem, but it is driving me insane. I am trying to create Mine Sweeper in JavaFX (mostly just for practice) but I can not get even a simple rectangle to display. I had the game running once before, but I am trying to make the game more abstract, and hence easier to code, but I am running into the issue of nothing being displayed.
I eliminated all extraneous code so it is as simple as possible. I am basically trying to create a Rectangle with a certain color and size called Box, add the box to the pane, and display the pane. In order to make Box a node that can be displayed on the pane, I made the Box class extend Rectangle, so that a Box would have the same properties as a Rectangle. But when I run the code, it gives just an empty pane with no box in it.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Minesweeper extends Application {
#Override
public void start(Stage stage) {
Pane pane = new Pane();
Box box = new Box();
pane.getChildren().addAll(box);
// Create the scene
Scene scene = new Scene(pane);
stage.setTitle("Minesweeper");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
public class Box extends Rectangle {
public Box() {
Rectangle box = new Rectangle(100, 100, 100, 100);
box.setFill(Color.BLUE);
}
}
I realized if I put the code from Box into the main Minesweeper class, it will display the box. But Box will have a ton of other properties and therefore needs to be a class on its own.
What am I doing wrong that does not allow the box to be displayed?
Thanks in advance for your help and consideration.
You create a new Rectangle in your Box class. This Rectangle is not added to any Parent container, so it's not visible.
Change your code to:
public Box() {
super(100, 100, 100, 100);
setFill(Color.BLUE);
}

Categories