JavaFX 2 dynamic dot loading - javafx-2

I wanna create some loading dots like this:
At 0 second the text on the screen is: Loading.
At 1 second the text on the screen is: Loading..
At 2 second the text on the screen is: Loading...
At 3 second the text on the screen is: Loading.
At 4 second the text on the screen is: Loading..
At 5 second the text on the screen is: Loading...
and so forth until I close the Stage.
What is the best / easiest way to make that in JavaFX? I've been looking into animations/preloaders in JavaFX but that seems to complex when trying to achieve this.
I've been trying to create a loop between these three Text:
Text dot = new Text("Loading.");
Text dotdot = new Text("Loading..");
Text dotdotdot = new Text("Loading...");
but the screen stays static...
How can I make this work correctly in JavaFX? Thanks.

This question is similar to: javafx animation looping.
Here is a solution using the JavaFX animation framework - it seems pretty straight forward to me and not too complex.
import javafx.animation.*;
import javafx.application.Application;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
/** Simple Loading Text Animation. */
public class DotLoader extends Application {
#Override public void start(final Stage stage) throws Exception {
final Label status = new Label("Loading");
final Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new EventHandler() {
#Override public void handle(Event event) {
String statusText = status.getText();
status.setText(
("Loading . . .".equals(statusText))
? "Loading ."
: statusText + " ."
);
}
}),
new KeyFrame(Duration.millis(1000))
);
timeline.setCycleCount(Timeline.INDEFINITE);
VBox layout = new VBox();
layout.getChildren().addAll(status);
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
stage.setScene(new Scene(layout, 50, 35));
stage.show();
timeline.play();
}
public static void main(String[] args) throws Exception { launch(args); }
}

Have you considered to use a Progress Indicator or a Progress Bar? I think they can be a good solution to show an animation and avoid problems.
I've been able to do it in JavaFX, not with Animations, but using the concurrency classes from JavaFX.
I let you the code here in a gist. I think it isn't very intuitive, because I prefer a progress indicator. And maybe it isn't the best solution, but maybe this will help you.
Cheers

Related

Generating a receipt in JavaFX?

I want to know if my approach is correct. I am trying to display a receipt as it is being generated (You can also think of it as a dynamic text). I can only think of displaying using a 'Label'. Is there a better way? Plus, when the added text goes beyond the label size, it should become "scrollable". I tried using a 'ScrollPane' but my text just went without the scollbar "activating". I can only find 'Image's being made "scrollable" and not 'Label's or 'TextArea's. Any help or suggestion is welcome.
PS: I just started learning JavaFX 8 by trying out this application and I am unable to proceed without handling this.
I would recommend you to make a html template with nice styling for your receipt and use spans with unique ids .
Then using jsoup place your label text in that span and show that html in a webview.
One more benefit is that you can then print that receipt using javafx8 webview printing
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public class HtmlReceipt extends Application{
String htmlTemplate = "<html>"
+ "<head>"
+ "<style>"
+ "body {background-color: yellow;}"
+ "#label1 {"
+ "background-color:red;"
+ "border:1px solid #000"
+ "}"
+ "</style>"
+ "</head>"
+ "<body>"
+ "<span id = 'label1'></span>"
+ "</body></html>";
#Override
public void start(Stage primaryStage) throws Exception {
AnchorPane rootpane = new AnchorPane();
Scene scene = new Scene(rootpane);
WebView webView = new WebView();
webView.setPrefHeight(400);
webView.setPrefWidth(300);
webView.getEngine().loadContent(getReceipt("MyName"));
rootpane.getChildren().add(webView);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public String getReceipt(String labelText){
Document doc = Jsoup.parse(htmlTemplate);
Element span = doc.select("span#label1").first();
span.text(labelText);
return doc.html();
}
}

JDialog doesn't size correctly with wrapped JTextArea

While making a program, I noticed a bug with the JOptionPane.showMessageDialog() call. I use a button to create a JTextArea that wraps and then display a dialog containing this text area.
If the text area is too large, however, the dialog does not size itself correctly to the height of the JTextArea. The Dialog cuts off the OK button in this example.
I replicated the bug in the following code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DialogBug {
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final String text = "looooooooooooooooooooooong text looooooooooooooooooooooooooooooooooooooong text";
JButton button = new JButton();
button.setPreferredSize(new Dimension(30, 30));
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JTextArea area = new JTextArea(text, 0, 50);
area.setEditable(false);
area.setLineWrap(true);
area.setWrapStyleWord(true);
area.append(text);
area.append(text);
area.append(text);
JOptionPane.showMessageDialog(frame, area, "why does it do this", JOptionPane.WARNING_MESSAGE);
}
});
frame.add(button);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I would post a picture, but I don't have enough reputation...
Is there a way to fix this without having to use a JScrollPane?
Here's a screenshot:
If you run the pack command on the dialog (a function in the Window class) it will resize based on subcomponents. For your case you will have to rewrite without using the showMessageDialog() to get the resize to work (so make the dialog first, add the text, pack, then show it)
Dialog b = new Dialog();
// add stuff
b.pack();
For my test code it worked perfectly to get the dialogs to be the right sizes
Without pack()
With pack()

Adding space between buttons in VBox

I have a collection of buttons:
VBox menuButtons = new VBox();
menuButtons.getChildren().addAll(addButton, editButton, exitButton);
I want to add some spacing between these buttons, without using a CSS style sheet. I think there should be a way to do this.
setPadding(); is for the Buttons in the VBox.
setMargin(); should be for the VBox itself. But I didn't find a way for the spacing between the buttons.
I'm glad for any ideas. :)
VBox supports spacing out of the box:
VBox menuButtons = new VBox(5);
or
menuButtons.setSpacing(5);
Just call setSpacing method and pass some value.
Example with HBox (it's same for VBox):
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.HBoxBuilder;
import javafx.stage.Stage;
public class SpacingDemo extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
stage.setTitle("Spacing demo");
Button btnSave = new Button("Save");
Button btnDelete = new Button("Delete");
HBox hBox = HBoxBuilder.create()
.spacing(30.0) //In case you are using HBoxBuilder
.padding(new Insets(5, 5, 5, 5))
.children(btnSave, btnDelete)
.build();
hBox.setSpacing(30.0); //In your case
stage.setScene(new Scene(hBox, 320, 240));
stage.show();
}
}
And this is how it looks:
Without of spacing:
With spacing:
If you're using FXML, use the spacing attribute:
<VBox spacing="5" />
As others have mentioned you can use setSpacing().
However, you can also use setMargin(), it is not for the pane (or box in your words), it is for individual Nodes. setPadding() method is for the pane itself. In fact, setMargin() takes a node as a parameter so you can guess what it's for.
For example:
HBox pane = new HBox();
Button buttonOK = new Button("OK");
Button buttonCancel = new Button("Cancel");
/************************************************/
pane.setMargin(buttonOK, new Insets(0, 10, 0, 0)); //This is where you should be looking at.
/************************************************/
pane.setPadding(new Insets(25));
pane.getChildren().addAll(buttonOK, buttonCancel);
Scene scene = new Scene(pane);
primaryStage.setTitle("Stage Title");
primaryStage.setScene(scene);
primaryStage.show();
You could get the same result if you replaced that line with
pane.setSpacing(10);
If you have several nodes that should be spaced, setSpacing() method is far more convenient because you need to call setMargin() for each individual node and that would be ridiculous. However, setMargin() is what you need if you need margins(duh) around a node that you can determine how much to each side because setSpacing() methods places spaces only in between nodes, not between the node and the edges of the window.
The same effect as the setSpacing method can also be achieved via css:
VBox {
-fx-spacing: 8;
}

JavaFx 2.x : Stage within a TabPane

I need to display one or more stage(s) within a TabPane by clicking on a button, such as the picture below
My target is to have a situation similar to JInternalFrame in Swing: how to accomplish this?
I am not able to add stage as children to the tab pane.
If this is not possible, what could be other solutions? I would like to have SplitPanes on the stage.
Thanks
PS I am using Win7, NetBeans 7.4 Beta (Build 201307092200), SceneBuilder 1.1
Edit: here is how it looks after some VFXWindows css changes
There's one thing worth notice: I have had to add a node ( in my case an HBox with prefSize(0,0), otherwise I can't move o resize the first window plotted, only the first one.
As last, I can't find a way to set windows full screen (maximize).
Here I put an example of windows from jfxtras inside of Tabs, I just modify the example.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.Stage;
import jfxtras.labs.scene.control.window.CloseIcon;
import jfxtras.labs.scene.control.window.MinimizeIcon;
import jfxtras.labs.scene.control.window.Window;
public class WindowInTab extends Application {
private static int counter = 1;
private void init(Stage primaryStage) {
TabPane tabPane = new TabPane();
Tab tab = generateTab("Windows...");
Tab anotherTab = generateTab("More Windows");
tabPane.getTabs().addAll(tab, anotherTab);
primaryStage.setResizable(true);
primaryStage.setScene(new Scene(tabPane, 600, 500));
}
private Tab generateTab(String tabName) {
Tab tab = new Tab(tabName);
final Group root = new Group();
tab.setContent(root);
Button button = new Button("Add more windows");
root.getChildren().addAll(button);
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
// create a window with title "My Window"
Window w = new Window("My Window#"+counter);
// set the window position to 10,10 (coordinates inside canvas)
w.setLayoutX(10);
w.setLayoutY(10);
// define the initial window size
w.setPrefSize(300, 200);
// either to the left
w.getLeftIcons().add(new CloseIcon(w));
// .. or to the right
w.getRightIcons().add(new MinimizeIcon(w));
// add some content
w.getContentPane().getChildren().add(new Label("Content... \nof the window#"+counter++));
// add the window to the canvas
root.getChildren().add(w);
}
});
return tab;
}
public double getSampleWidth() {return 600;}
public double getSampleHeight() {return 500;}
#Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) {launch(args);}
}
I don't know if this was exactly what you were looking for. Hope it helps!

How to play clean audio loops and one-shot sounds in parallel in JavaFX 2.0?

I'm trying to play background audio in a loop in a JavaFX 2.0 application using JavaFX SDK 2.0.1. I decided to use a MediaPlayer created by the following piece of code:
MediaPlayerBuilder
.create().media(BACKGROUND_MEDIA)
.cycleCount(MediaPlayer.INDEFINITE);
This basically works, but when a new cycle starts there is a tiny (latency?) gap between the end and the start of the audio. So it's not a working option for me since it's not playing a clean loop.
I decided to build a new MediaPlayer object and start playback everytime Media ends. This works fine so far. Additionally, I use a button playing a short AudioClip when clicked.
I discoverd that frequent and fast clicking this button leads to interrupts in the background audio. I created an example to reproduce this behaviour by inifinitely playing an AudioClip with volume 0 when the button is clicked once. The example is not self contained, since the required audio files are missing. It requires to place 2 audio files in the project's source directory:
click.wav (a really short click sound ~300ms)
background.wav (~5 seconds of audio)
How do I achieve playing a clean audio loop in background without these interrupts when other one-shot audio sounds are played? Is it just a performance issue?
Example:
package mediatest;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.media.AudioClip;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayerBuilder;
import javafx.stage.Stage;
public class MediaTest extends Application {
private static final AudioClip CLICK_AUDIOCLIP = new AudioClip(MediaTest.class.getResource("/click.wav").toString());
private static final Media BACKGROUND_MEDIA = new Media(MediaTest.class.getResource("/background.wav").toString());
private MediaPlayerBuilder builder;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Scene scene = new Scene(root, 300, 250);
this.builder = MediaPlayerBuilder
.create()
.media(BACKGROUND_MEDIA)
.onEndOfMedia(new Runnable() {
public void run() {
MediaPlayer player = MediaTest.this.builder.build();
player.play();
}
});
MediaPlayer player = this.builder.build();
player.play();
Button btn = new Button();
btn.setText("Repeat playing short audio clip");
btn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
//Simulation of many button clicks
MediaTest.CLICK_AUDIOCLIP.setCycleCount(AudioClip.INDEFINITE);
MediaTest.CLICK_AUDIOCLIP.play(0);
}
});
root.getChildren().add(btn);
primaryStage.setScene(scene);
primaryStage.show();
}
}
have you looked into ExecutorService? You would then have a number of predefined threads like so:
ExecutorService service = Executors.newFixedThreadPool(4);
where 4 is the number of threads it makes.
It will improve performance because it uses already made threads rather than making a new one each time you want to run something.
You would create a Runnable and execute it with the service like so:
Runnable r = new Runnable() {
#Override
public void run() {
playSound();
}
};
service.execute(r);
Not only would this improve performance but it automatically assigns the job to a not-currently-busy thread in its thread pool.
Also look at this: Playing sound loops using javafx which I believe solves your small latency problem.
EDIT: damn sorry, I didn't know this post was that old. It was a top result in google.
Using another thread at
public void handle(ActionEvent event) {
Platform.runLater(new Runnable()
{
#Override
public void run()
{
//Simulation of many button clicks
MediaTest.CLICK_AUDIOCLIP.setCycleCount(AudioClip.INDEFINITE);
MediaTest.CLICK_AUDIOCLIP.play(0);
}
});
}
});
May solve the problem of the interruption

Resources