How to firing Zoomevent in Javafx 8 - event-handling

I'm working on a very simple program. I have an ImageView and I want to firing to this ImageView a ZoomEvent that I created. In Javafx 8 there 2 constructor that I can use to create ZoomEvent. But the listeners doesn't catch the event.
StackPane root = new StackPane();
final ImageView img = new ImageView(url);
img.setOnZoom(new EventHandler<ZoomEvent>() {
#Override
public void handle(ZoomEvent t) {
System.out.println("Zoom!");
}
});
img.setOnZoomStarted(new EventHandler<ZoomEvent>() {
#Override
public void handle(ZoomEvent t) {
System.out.println("Zoom Started!");
}
});
img.setOnZoomFinished(new EventHandler<ZoomEvent>() {
#Override
public void handle(ZoomEvent t) {
System.out.println("Zoom finished!");
}
});
ZoomEvent evt = new ZoomEvent(ZoomEvent.ANY, 200,200,200,200,false,false,false,false,false, false, 5.0,5.0, null);
root.getChildren().add(img);
Scene scene = new Scene(root, 600, 600);
primaryStage.setTitle("Zoom Sample");
primaryStage.setScene(scene);
primaryStage.show();
This is my code so far and I can't figure out what is wrong. There isn't any output.

You never fired the event with ZoomEvent.fireEvent(target, event) or stage.fireEvent(event).
You created the wrong type of event (create a ZoomEvent.ZOOM, not a ZoomEvent.ANY).
You didn't set the event screen co-ordinates correctly.
Working sample:
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.input.ZoomEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Zoom extends Application {
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage stage) {
final ImageView img = new ImageView(
"http://icons.iconarchive.com/icons/kirei-kaze/kikis-delivery-service/256/jiji-icon.png" // image license: License: Free for non-commercial use. The products or characters depicted in these icons are © by Studio Ghibli. Linkback: http://www.iconarchive.com/artist/kirei-kaze.html
);
img.setOnZoom(e -> System.out.println("Zoom!"));
StackPane layout = new StackPane(img);
stage.setScene(new Scene(layout, 600, 600));
stage.show();
Point2D screenCoords = layout.localToScreen(300, 300);
ZoomEvent evt = new ZoomEvent(
ZoomEvent.ZOOM,
300, 300,
screenCoords.getX(), screenCoords.getY(),
false,false,false,false,false, false, 5.0,5.0, null
);
ZoomEvent.fireEvent(img, evt);
}
}

Related

Javafx Stage is blank for a few seconds before showing elements

I am trying to create a game with JavaFX. I have created 2 stages, one is for the splashscreen, the second one is for the actual game itself. This is my first ever JavaFX program, i am a student learning JavaFX. The problem i am having is that when i hide the first stage and show the second one, the second stage stays blank for a few seconds and then continues to show all element(s). For now, there is only a gif showing in the stage with some music(which is not delayed in loading, because it is an instance variable). I don't want to create many instance variables for each of the elements i wish to put into the stage. Below is the code, where only the necessary code is shown to understand the problem:
import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.File;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
Dimension window = Toolkit.getDefaultToolkit().getScreenSize();
private double screenWidth = window.getWidth();
private double screenHeight = window.getHeight();
private boolean fullscreen = false;
private boolean music = false;
private double value = 0;
private Group root, root2;
private Image start;
private Image startHover;
private ImageView startViewer;
private Stage stage;
private boolean firstWindowExists = true;
private CheckBox full;
private CheckBox sound;
private Slider slider;
private Image BG;
private ImageView BGView;
private String path = "bin/Audio/8_bit_march.mp3";
private Media media;
private MediaPlayer player;
public static void main(String[] args) {
launch();
}
private void run() {
Image title = new Image("Title.png", 300, 0, true, true);
ImageView titleView= new ImageView();
titleView.setX(200);
titleView.setY(10);
titleView.setImage(title);
add(titleView);
start = new Image("Start1.png", 200, 0, true, true);
startHover = new Image("Start_Hover1.png", 200, 0, true, true);
startViewer= new ImageView();
startViewer.setX(250);
startViewer.setY(300);
startViewer.setOnMouseEntered(mouseEnter);
startViewer.setOnMouseExited(mouseExit);
startViewer.setOnMouseReleased(mouseReleased);
startViewer.setImage(start);
add(startViewer);
if (!firstWindowExists) {//this code works
Image title2 = new Image("BG.gif", (screenWidth/1.25) + 4, (screenHeight/1.25)+4, false, true);
ImageView titleView2= new ImageView();
titleView2.setX(-2);
titleView2.setY(-2);
titleView2.setImage(title2);
add2(titleView2);
}
}
EventHandler<ActionEvent> event = new EventHandler<ActionEvent>() {
public void handle(ActionEvent e)
{
if (sound.isSelected()) { // the checkbox is checked to be enabled
slider.setVisible(true);
}
else {
slider.setVisible(false);
}
}
};
EventHandler<MouseEvent> mouseEnter = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) { // irrelevant for this problem
startViewer.setImage(startHover);
}
};
EventHandler<MouseEvent> mouseExit = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
startViewer.setImage(start);
}
};
EventHandler<MouseEvent> mouseReleased = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
stage.hide(); //hide first window
firstWindowExists = false;
Stage stage2 = new Stage(); // creating a new stage
root2 = new Group(); //creating new group
Scene scene2 = new Scene(root2, Color.WHITE);// creating a scene and adding the newly created Group
Canvas canvas2 = new Canvas(screenWidth/1.25, screenHeight/1.25); // creating a canvas for the screen
root2.getChildren().add(canvas2); // adding canvas to the group (window)
stage2.setTitle("Game"); // setting the title of the window
stage2.setScene(scene2); // Adds scene to the stage
stage2.setFullScreen(fullscreen);
stage2.show(); //after showing the screen here, it stays blank and then adds the title2 gif
stage2.centerOnScreen();
if (music) { //plays music
player.play();
player.setVolume(value);
player.setCycleCount(MediaPlayer.INDEFINITE);
}
run(); // runs the method with heavy lifting stuff
}
};
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> {
}));
private void add(Node node) {
if (firstWindowExists) {
root.getChildren().add(node);
}
}
private void add2(Node node) {
root2.getChildren().add(node);
}
#Override
public void start(Stage stage) throws Exception { // main method which creates the first window
this.stage = stage;
stage.setTitle("Test GUI");
root = new Group();
Scene scene = new Scene(root, Color.DARKGRAY);
Canvas canvas = new Canvas(700, 350);
root.getChildren().add(canvas);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
stage.centerOnScreen();
root.requestFocus();
run();
media = new Media(new File(path).toURI().toString());
player = new MediaPlayer(media);
}
}

My circles won't show. What am I missing here?

In Javafx, I am trying to create a pane where I can add points through a mouse click event. When you click on the pane a circle should appear at your mouse position. The circles are being created, as I am tracking them in the console, but they are not showing in the graphics.
I did a similar program to this that auto drew an image that resized with the stage/window, I am using all the same techniques but that project didn't include event handling.
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.paint.Color;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
public class ClickToShape extends Application {
private ClickPane clickPane = new ClickPane();
#Override
public void start(Stage primaryStage) throws Exception {
Pane clickPane = new ClickPane();
clickPane.setOnMouseClicked(new ClickHandler());
// create the scene
Scene clickScene = new Scene(clickPane, 500, 500);
// set up the window/stage
primaryStage.setTitle("Click To Draw");
primaryStage.setScene(clickScene); // add the scene to the stage
primaryStage.show(); // fire it off
}
public static void main(String[] args) {
launch(args);
}
class ClickHandler implements EventHandler<MouseEvent> {
#Override
public void handle(MouseEvent e) {
System.out.println("MouseEvent occured");
clickPane.addPoint(e.getX(), e.getY());
}
}
}
class ClickPane extends Pane{
private ArrayList<Circle> points = new ArrayList<Circle>();
private Color color1 = Color.BLACK;
public void addPoint(double x, double y) {
System.out.println("A new point function ran");
Circle newPoint = new Circle (x, y, 300, color1 );
System.out.println(newPoint.toString());
points.add(newPoint);
getChildren().clear();
getChildren().add(newPoint);
}
}
There are no error messages.
the problem is that you instantiated two ClickPane objects, one outside the start method, and another inside the start method, you added the second one to the scene but used the first one to add points, and that's why points aren't showing in your scene
what you can do about this is delete the first line in your start method, so the application will be using the same instance to fire events as to add to the scene, the code would look like this
import java.util.ArrayList;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
public class ClickToShape extends Application {
private ClickPane clickPane = new ClickPane();
#Override
public void start(Stage primaryStage) throws Exception {
clickPane.setOnMouseClicked(new ClickHandler());
// create the scene
Scene clickScene = new Scene(clickPane, 500, 500);
// set up the window/stage
primaryStage.setTitle("Click To Draw");
primaryStage.setScene(clickScene); // add the scene to the stage
primaryStage.show(); // fire it off
}
public static void main(String[] args) {
launch(args);
}
class ClickHandler implements EventHandler<MouseEvent> {
#Override
public void handle(MouseEvent e) {
System.out.println("MouseEvent occured");
clickPane.addPoint(e.getX(), e.getY());
}
}
}
class ClickPane extends Pane{
private ArrayList<Circle> points = new ArrayList<Circle>();
private Color color1 = Color.BLACK;
public void addPoint(double x, double y) {
System.out.println("A new point function ran");
Circle newPoint = new Circle (x, y, 10, color1 );
System.out.println(newPoint.toString());
points.add(newPoint);
getChildren().setAll(newPoint);
}
}

JavaFX - move window with effect

I have undecorated non-fullscreen window, which I like to move outside screen boundaries when mouse leaves it's area, but do so smoothly. I found some JavaFX functionality to do so - Timeline, but KeyValue for that Timeline doesn't supports stage.xProperty - because this property is readonlyProperty. Is there way to move my window smoothly using JavaFX functions?
You can setup proxy properties that you manipulate via KeyValues in a Timeline. A listener on the proxy can modify the actual stage location.
import javafx.animation.*;
import javafx.application.*;
import javafx.beans.property.*;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.TextAlignment;
import javafx.stage.*;
import javafx.util.Duration;
public class StageSwiper extends Application {
private static final int W = 350;
private static final Duration DURATION = Duration.seconds(0.5);
#Override
public void start(Stage stage) throws Exception {
Label instructions = new Label(
"Window will slide off-screen when the mouse exits it.\n" +
"Click the window to close the application."
);
instructions.setTextAlignment(TextAlignment.CENTER);
final StackPane root = new StackPane(instructions);
root.setStyle("-fx-background-color: null;");
DoubleProperty stageX = new SimpleDoubleProperty();
stageX.addListener((observable, oldValue, newValue) -> {
if (newValue != null && newValue.doubleValue() != Double.NaN) {
stage.setX(newValue.doubleValue());
}
});
final Timeline slideLeft = new Timeline(
new KeyFrame(
DURATION,
new KeyValue(
stageX,
-W,
Interpolator.EASE_BOTH
)
),
new KeyFrame(
DURATION.multiply(2)
)
);
slideLeft.setOnFinished(event -> {
slideLeft.jumpTo(Duration.ZERO);
stage.centerOnScreen();
stageX.setValue(stage.getX());
});
root.setOnMouseClicked(event -> Platform.exit());
root.setOnMouseExited(event -> slideLeft.play());
stage.setScene(new Scene(root, W, 100, Color.BURLYWOOD));
stage.initStyle(StageStyle.UNDECORATED);
stage.show();
stage.centerOnScreen();
stageX.set(stage.getX());
}
public static void main(String[] args) {
launch(args);
}
}

Drag and Drop vbox element with show snapshot in javafx

I want drag an element in vbox as a parent and show node moving during drag and drop of element, how can do this with The slightest change.
Just register mouse listeners with the elements of the VBox. You want to call startFullDrag() on the node on a dragDetected event, and rotate the child nodes of the VBox on a dragReleased event. You can use the dragEntered and dragExited events if you want to give visual hints to the user about the drag.
See the API docs for more.
Simple example (code is way cleaner in JavaFX 8, btw):
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
final VBox root = new VBox(5);
final ScrollPane scroller = new ScrollPane();
scroller.setContent(root);
final Scene scene = new Scene(scroller,400,200);
for (int i=1; i<=20; i++) {
final Label label = new Label("Item "+i);
addWithDragging(root, label);
}
// in case user drops node in blank space in root:
root.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
int indexOfDraggingNode = root.getChildren().indexOf(event.getGestureSource());
rotateNodes(root, indexOfDraggingNode, root.getChildren().size()-1);
}
});
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
private void addWithDragging(final VBox root, final Label label) {
label.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
label.startFullDrag();
}
});
// next two handlers just an idea how to show the drop target visually:
label.setOnMouseDragEntered(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
label.setStyle("-fx-background-color: #ffffa0;");
}
});
label.setOnMouseDragExited(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
label.setStyle("");
}
});
label.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
label.setStyle("");
int indexOfDraggingNode = root.getChildren().indexOf(event.getGestureSource());
int indexOfDropTarget = root.getChildren().indexOf(label);
rotateNodes(root, indexOfDraggingNode, indexOfDropTarget);
event.consume();
}
});
root.getChildren().add(label);
}
private void rotateNodes(final VBox root, final int indexOfDraggingNode,
final int indexOfDropTarget) {
if (indexOfDraggingNode >= 0 && indexOfDropTarget >= 0) {
final Node node = root.getChildren().remove(indexOfDraggingNode);
root.getChildren().add(indexOfDropTarget, node);
}
}
public static void main(String[] args) {
launch(args);
}
}
This is an addendum to #James_D's excellent answer
This shows how to add an image preview to the draggable node as #James_D suggests in his comment:
private void addPreview(final VBox root, final Label label) {
ImageView imageView = new ImageView(label.snapshot(null, null));
imageView.setManaged(false);
imageView.setMouseTransparent(true);
root.getChildren().add(imageView);
root.setUserData(imageView);
root.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
imageView.relocate(event.getX(), event.getY());
}
});
}
private void removePreview(final VBox root) {
root.setOnMouseDragged(null);
root.getChildren().remove(root.getUserData());
root.setUserData(null);
}
Call addPreview() in label.setOnDragDetected(). Call removePreview() in label.setOnMouseDragReleased() and root.setOnMouseDragReleased().
There is a much better solution that is far cleaner now.
// Root is the node you want to drag, not the scene root.
root.setOnDragDetected(mouseEvent -> {
final ImageView preview = new ImageView(root.snapshot(null, null));
final Dragboard db = root.startDragAndDrop(TransferMode.ANY);
db.setContent( // Set your content to something here.
);
db.setDragView(preview.getImage());
mouseEvent.consume();
});

Align a jFreeChart (setAlignmentX and Y?)

I am trying to align the whole chart within a JFrame but the normal component codes that I know do not work for JChartPanels. Initially I tried to setAligmentX and Y on the JChartPanel but that didn't work. I then tried to add the JChartPanel to a JPanel then setAlignment but once I add the JChartPanel to a JPanel the graph is no longer visible.
The code below creates a graph within a JFrame at the default top left location. I need to align the graph- use any values as I will change them later to fit my purpose.
The contained code without any of the attempts(errors) mentioned above:
import java.awt.*;
import javax.swing.*;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class ChartTest extends javax.swing.JFrame {
public ChartTest() {
XYSeries Goals = new XYSeries("Goals Scored");
Goals.add(1, 1.0);
Goals.add(2, 3.0);
Goals.add(3, 2.0);
Goals.add(4, 0.0);
Goals.add(5, 3.0);
XYDataset xyDataset = new XYSeriesCollection(Goals);
JFreeChart chart = ChartFactory.createXYLineChart("Goals Scored Over Time", "Fixture Number", "Goals", xyDataset, PlotOrientation.VERTICAL, true, true, false);
JPanel jPanel = new JPanel();
jPanel.setLayout(new BoxLayout(jPanel, BoxLayout.PAGE_AXIS));
jPanel.setVisible(true);
jPanel.setSize(300, 300);
ChartPanel CP = new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
CP.setMouseWheelEnabled(true);
add(CP);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
initComponents();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ChartTest().setVisible(true);
}
});
}
The result is just an empty window.
I suspect that your GUI editor's implementation of initComponents() is at fault. You'll have to examine the generated code to see. Here's a complete working example form for reference:
Minimal, Complete, Tested and Readable Example:
import java.awt.Dimension;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class ChartTest extends javax.swing.JFrame {
public ChartTest() {
XYSeries Goals = new XYSeries("Goals Scored");
Goals.add(1, 1.0);
Goals.add(2, 3.0);
Goals.add(3, 2.0);
Goals.add(4, 0.0);
Goals.add(5, 3.0);
XYDataset xyDataset = new XYSeriesCollection(Goals);
JFreeChart chart = ChartFactory.createXYLineChart(
"Goals Scored Over Time", "Fixture Number", "Goals",
xyDataset, PlotOrientation.VERTICAL, true, true, false);
JPanel jPanel = new JPanel();
jPanel.setLayout(new BoxLayout(jPanel, BoxLayout.PAGE_AXIS));
jPanel.setVisible(true);
jPanel.setSize(300, 300);
ChartPanel CP = new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
};
CP.setMouseWheelEnabled(true);
add(CP);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ChartTest().setVisible(true);
}
});
}
}