I intend to change the images of birds over the time by adding key frames in a for loop to the timeline object. It turns out that only the first image is displayed. Could someone point out where part I got it wrong. Thanks in advance.
Besides, I noticed that I have to reset the counter "index" to 0 after for loop otherwise it generates java.lang.ArrayIndexOutOfBoundsException.
package application;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.effect.BoxBlur;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
public class Main extends Application
{
int index=0;
#Override
public void start(Stage primaryStage) {
try {
ImageView bgV = new ImageView();
Image img_BG = new Image(Main.class.getResourceAsStream("background.png"));
bgV.setImage(img_BG);
bgV.setEffect(new BoxBlur());
bgV.setOpacity(0.5);
ImageView t1V = new ImageView();
Image img_t1 = new Image(Main.class.getResourceAsStream(
"t1.png"
));
t1V.setImage(img_t1);
ImageView t2V = new ImageView();
Image img_t2 = new Image(Main.class.getResourceAsStream(
"t2.png"
));
t2V.setImage(img_t2);
ImageView t3V = new ImageView();
Image img_t3 = new Image(Main.class.getResourceAsStream(
"t3.png"
));
t3V.setImage(img_t3);
Group foreground = new Group(t1V,t2V,t3V);
t1V.setTranslateX(20);
t1V.setTranslateY(200);
t2V.setTranslateX(300);
t2V.setTranslateY(200);
t3V.setTranslateX(550);
t3V.setTranslateY(200);
foreground.setEffect(new DropShadow());
String[]
birdFiles = {"b1.png", "b2.png", "b3.png", "b4.png", "b5.png", "b6.png"};
double[] ds = { 300, 600, 900, 1200, 1500, 1800};
ImageView birdV = new ImageView(new Image(Main.class.getResourceAsStream(birdFiles[0])));
Group birds = new Group(birdV);
birds.setTranslateX(img_BG.getWidth()-100);
Timeline timeline = new Timeline();
timeline.setCycleCount(
Animation.INDEFINITE
);
KeyFrame[] kframs = new KeyFrame[birdFiles.length];
for( index=0; index<birdFiles.length; index++)
{
EventHandler<ActionEvent>
onFishined = new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent arg0)
{
birds.getChildren().setAll(new ImageView(new Image(Main.class.getResourceAsStream(birdFiles[index]))));
}
};
Duration duration = Duration.millis(ds[index]);
KeyFrame
kf = new KeyFrame(duration, onFishined,null,null );
timeline.getKeyFrames().add(kf);
}//End for i
index = 0;
timeline.play();
Group root = new Group(bgV,foreground,birds);
Scene scene = new Scene(root,img_BG.getWidth(), img_BG.getHeight());
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
you don't have to declare your index-field outside. this also causes your problem: whenever the handle method is called, it will reference your field: index which you set to 0 after your loop.
therefor you can declare a new field as finaland pass it to the handler:
for (int index = 0; index < birdFiles.length; index++) {
final int birdIndex = index;
EventHandler<ActionEvent> onFishined = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
birds.getChildren().setAll(new ImageView(new Image(Main.class.getResourceAsStream(birdFiles[birdIndex]))));
}
};
...
}
Related
I want image slides from right to left then it reverse from left to right using JavaFX image views.
I want this type of slides:
Here is my code, which is not giving me accurate results. It slides from left to right.
Only.java:
package com.valid;
import javafx.animation.FadeTransition;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Only extends Application {
class SimpleSlideShow {
StackPane root = new StackPane();
ImageView[] slides;
public SimpleSlideShow() {
this.slides = new ImageView[4];
Image image1 = new Image(Only.class.getResource("res/Pic1.jpg").toExternalForm());
Image image2 = new Image(Only.class.getResource("res/Pic2.jpeg").toExternalForm());
Image image3 = new Image(Only.class.getResource("res/Pic3.jpeg").toExternalForm());
Image image4 = new Image(Only.class.getResource("res/Pic4.jpeg").toExternalForm());
slides[0] = new ImageView(image1);
slides[1] = new ImageView(image2);
slides[2] = new ImageView(image3);
slides[3] = new ImageView(image4);
}
public StackPane getRoot() {
return root;
}
public ImageView[] getImageView() {
return slides;
}
/*public void start() {
this.root.getChildren().add(slides[0]);
// slide.setOpacity(0);
Timeline timeline = new Timeline();
// TranslateTransition tts= new TranslateTransition(Duration.millis(3000));
slides[0].translateXProperty().set(-1*root.getWidth());
KeyValue kv = new KeyValue(slides[0].translateXProperty(), 0, Interpolator.EASE_IN);
KeyFrame kf = new KeyFrame(Duration.seconds(2), kv);
timeline.getKeyFrames().add(kf);
timeline.setAutoReverse(true);
timeline.setOnFinished(t -> {
this.root.getChildren().addAll(slides[1],slides[2],slides[3]);
});
timeline.play();
}*/
public void leftToRight(){
this.root.getChildren().add(slides[0]);
// slide.setOpacity(0);
Timeline timeline = new Timeline();
// TranslateTransition tts= new TranslateTransition(Duration.millis(3000));
KeyValue kv = new KeyValue(slides[0].translateXProperty(), 0, Interpolator.EASE_IN);
slides[0].translateXProperty().set(-1*root.getWidth());
KeyFrame kf = new KeyFrame(Duration.seconds(2), kv);
timeline.getKeyFrames().add(kf);
timeline.setAutoReverse(true);
timeline.setOnFinished(t -> {
this.root.getChildren().addAll(slides[1]);
});
timeline.play();
/*SequentialTransition st = new SequentialTransition();
for (ImageView sl : slides) {
this.root.getChildren().add(slides[0]);
slides[0].translateXProperty().add(root.getScene().getHeight());*/
}
}
}
/*public FadeTransition getFadeTransition(ImageView imageView, double fromValue, double toValue,
int durationInMilliseconds) {
// SequentialTransition slide = new SequentialTransition();
// slide.setCycleCount(2);
// slide.autoReverseProperty();
// slide.setAutoReverse(true);
FadeTransition ft = new FadeTransition(Duration.seconds(3), imageView);
ft.setFromValue(fromValue);
ft.setToValue(toValue);
return ft;
}
// }
*/
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
SimpleSlideShow simpleSlideShow = new SimpleSlideShow();
Scene scene = new Scene(simpleSlideShow.getRoot());
primaryStage.setScene(scene);
primaryStage.setMaximized(true);
primaryStage.show();
simpleSlideShow.getImageView()[0].translateXProperty().set(scene.getWidth());
//simpleSlideShow.start();
simpleSlideShow.leftToRight();
}
}
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.
Is there anyway I can do a for loop to create multiple textfields. Say I want like 20 text fields...do I have to create them individually?
It's not really clear what your question is. Just write a for loop and create each TextField inside it.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TwentyTextFields extends Application {
#Override
public void start(Stage primaryStage) {
final int numTextFields = 20 ;
TextField[] textFields = new TextField[numTextFields];
VBox root = new VBox(5);
for (int i = 1; i <= numTextFields; i++) {
TextField tf = new TextField();
String name = "Text field "+i ;
tf.setOnAction(e -> {
System.out.println("Action on "+name+": text is "+tf.getText());
});
root.getChildren().add(tf);
textFields[i-1] = tf ;
}
Scene scene = new Scene(new ScrollPane(root), 250, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
package javafx;
import java.util.ArrayList;
import java.util.List;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ImageSlide extends Application {
// Width and height of image in pixels
private final double IMG_WIDTH = 600;
private final double IMG_HEIGHT = 300;
private final int NUM_OF_IMGS = 3;
private final int SLIDE_FREQ = 4; // in secs
#Override
public void start(Stage stage) throws Exception {
//root code
StackPane root = new StackPane();
Pane clipPane = new Pane();
// To center the slide show incase maximized
clipPane.setMaxSize(IMG_WIDTH, IMG_HEIGHT);
clipPane.setClip(new Rectangle(IMG_WIDTH, IMG_HEIGHT));
HBox imgContainer = new HBox();
//image view
ImageView imgGreen = new ImageView(new Image(getClass()
.getResourceAsStream("\\Merged1.pngg")));
ImageView imgBlue = new ImageView(new Image(getClass()
.getResourceAsStream("\\Merged2.png")));
ImageView imgRose = new ImageView(new Image(getClass()
.getResourceAsStream("\\Merged3.png")));
imgContainer.getChildren().addAll(imgGreen, imgBlue, imgRose);
clipPane.getChildren().add(imgContainer);
root.getChildren().add(clipPane);
Scene scene = new Scene(root, IMG_WIDTH, IMG_HEIGHT);
stage.setTitle("Image Slider");
stage.setScene(scene);
startAnimation(imgContainer);
stage.show();
}
//start animation
private void startAnimation(final HBox hbox) {
//error occured on (ActionEvent t) line
//slide action
EventHandler<ActionEvent> slideAction = (ActionEvent t) {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1.5), hbox);
trans.setByX(-IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
//eventHandler
EventHandler<ActionEvent> resetAction = (ActionEvent t) {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1), hbox);
trans.setByX((NUM_OF_IMGS - 1) * IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
List<KeyFrame> keyFrames = new ArrayList<>();
for (int i = 1; i <= NUM_OF_IMGS; i++) {
if (i == NUM_OF_IMGS) {
keyFrames.add(new KeyFrame(Duration.seconds(i * SLIDE_FREQ), resetAction));
} else {
keyFrames.add(new KeyFrame(Duration.seconds(i * SLIDE_FREQ), slideAction));
}
}
//add timeLine
Timeline anim = new Timeline(keyFrames.toArray(new KeyFrame[NUM_OF_IMGS]));
anim.setCycleCount(Timeline.INDEFINITE);
anim.playFromStart();
}
//call main function
public static void main(String[] args) {
launch(args);
}
}
The lines
EventHandler<ActionEvent> slideAction = (ActionEvent t) {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1.5), hbox);
trans.setByX(-IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
should be
EventHandler<ActionEvent> slideAction = (ActionEvent t) -> {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1.5), hbox);
trans.setByX(-IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
Note the only addition ->. Which IDE are you using?
IS there any way to export Stage or some other component like BorderPane with visual components into PDF file? I want when I click a button to export the component into PDF file? IS there any example?
You can use PDFBox libreries in your javafx project . this code take a snapshot from a node , make an image file , then create a pdf file and insert the image in the pdf file . you need this .jar http://www-us.apache.org/dist/pdfbox/2.0.8/pdfbox-app-2.0.8.jar . with pdfbox you can pass strings of javafx to text in pdf , you can do many things ( change font , size .... )
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.control.Button;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
public class NodeToPdf extends Application {
#Override
public void start(Stage primaryStage) {
CategoryAxis xAxis = new CategoryAxis();
xAxis.setLabel("x");
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("y");
BarChart bar = new BarChart(xAxis, yAxis);
bar.setMaxSize(300, 300);
bar.setTitle("Bar node" );
bar.setTranslateY(-100);
Button btn = new Button();
btn.setTranslateY(100);
btn.setText("To Pdf'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WritableImage nodeshot = bar.snapshot(new SnapshotParameters(), null);
File file = new File("chart.png");
try {
ImageIO.write(SwingFXUtils.fromFXImage(nodeshot, null), "png", file);
} catch (IOException e) {
}
PDDocument doc = new PDDocument();
PDPage page = new PDPage();
PDImageXObject pdimage;
PDPageContentStream content;
try {
pdimage = PDImageXObject.createFromFile("chart.png",doc);
content = new PDPageContentStream(doc, page);
content.drawImage(pdimage, 100, 100);
content.close();
doc.addPage(page);
doc.save("pdf_file.pdf");
doc.close();
file.delete();
} catch (IOException ex) {
Logger.getLogger(NodeToPdf.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
root.getChildren().add(bar);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
you can send a node to a printer and save it as pdf with a virtual printer
public class PrinterNodetExample extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("To Printer!");
PrinterJob job = PrinterJob.createPrinterJob();
if(job != null){
job.showPrintDialog(primaryStage);
job.printPage(root);
job.endJob();
}
}
});
primaryStage.setTitle("Printer");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}}
First guess is that you could simply save the Scene root to the image and then include it to the PDF. See Node#snapshot method for details.