How to delay the execution of a task in JavaFX - javafx-2

I have got the following function on my program that runs perfectly. I am only updating some text on 3 labels on my GUI as the code shows and that is working fine. However, I want to put a 1-second delay/pause after each label update so that I can have label1 updated then after 1 second label2 gets updated and after 1 second again label3 updates. I have tried to use Thread. I would really appreciate it if someone can help me.
Thank you.
private void displayData()
{
DataHelper datahelper = new DataHelper(data1, data2, data3);
myThread = new Service<DataHelper>()
{
#Override
protected Task<DataHelper> createTask()
{
return new Task<DataHelper>()
{
protected DataHelper call() throws Exception
{
return new DataHelper(myData1, myData2, myData3);
}
};
}
};
myThread.setOnSucceeded(event ->
{
label1.textProperty().unbind();
labe2.textProperty().unbind();
label3.textProperty().unbind();
});
label1.textProperty().bindBidirectional(datahelper.text1Property());
label2.textProperty().bindBidirectional(datahelper.text2Property());
label3.textProperty().bindBidirectional(datahelper.text3Property());
myThread.restart();
}

If you want to do the binding with delay of 1 second in each execution, you can use Timeline.
Timeline tl = new Timeline(new KeyFrame(Duration.seconds(1), ae -> lbl1.textProperty().bindBidirectional(data.text1Property())),
new KeyFrame(Duration.seconds(2), ae -> lbl2.textProperty().bindBidirectional(data.text2Property())),
new KeyFrame(Duration.seconds(3), ae -> lbl3.textProperty().bindBidirectional(data.text3Property())));
tl.setCycleCount(1);
tl.play();

Related

How to make animations with java fx without stops or lag

I'm developing a system with the JFoenix library, and I'm using some buttons with wave animation. But when I use a button to open a new window, or load a list for example, the animation "stops" briefly while the screen loads, or the list loads. I would like to know how to run the animation before loading the list, or something like that. Do not let the animation crash. I've tried to use Threads to load the list, however, because the function that calls the thread gets inside the click function of the button, the animation locks in the same way.
Another example is when I use a JavaFX transition animation to open a new AnchorPane, while its elements are loading, the animation hangs briefly, and that takes away all the quality of the application
Example, when I click the "add" button shown in the image below, it generates a waveform on the button, then performs a function to open the AnchorPane and a transition function to move the panel to the x = 0 position. And it also carries a simple DropDownList with some elements.
The code executed when the button is clicked:
#FXML
public void btnAddClique(ActionEvent event) {
if (telaAtual != 3) { //caso a tela de cadastro nao esteja aberta
PaneAdd add = new PaneAdd();
FXMLLoader loader = new FXMLLoader(getClass().getResource("PaneAdd.fxml"));
loader.setController(add);
try {
if (paneAtual == 1) {
paneFundo2.getChildren().setAll((Node)loader.load());
paneAtual = 2;
} else {
paneFundo.getChildren().setAll((Node)loader.load());
paneAtual = 1;
}
} catch (IOException e){
System.out.println("Erro ao alterar tela, função 'btnAddClique', classe FXMLDocumentController: " + e.toString());
}
telaAtual = 3;
new Thread(new RunAnimacaoAbertura()).start();
add.init(this.listView);
}
}
After that, it runs the Animation Thread:
public class RunAnimacaoAbertura implements Runnable {
public void run() {
TranslateTransition tran = new TranslateTransition();
TranslateTransition tran2 = new TranslateTransition();
tran.setDuration(Duration.seconds(0.250));
tran2.setDuration(Duration.seconds(0.250));
tran.setNode(paneFundo);
tran2.setNode(paneFundo2);
if (paneAtual == 1) {
tran2.setFromX(0);
tran2.setToX(515);
tran.setFromX(-515);
tran.setToX(0);
} else {
tran.setFromX(0);
tran.setToX(515);
tran2.setFromX(-515);
tran2.setToX(0);
}
tran2.play();
tran.play();
}
}
And finally, it performs the function of loading the list:
public void init(JFXListView<Label> listView) {
listViewControler = listView;
cbGerentePA.setItems(arquivo.pegarListaString(1, 0));
date.setPromptText("Nascimento");
date.setEditable(false);
date.setDefaultColor(Color.web("#1abc9c"));
date.getStylesheets().add("agenda/style.css");
hBoxFundoDate.getChildren().setAll(date);
}

Why does my RotateTransition throw errors after it runs for the first time?

Warning: This is my first time using threads and my first time trying out an animation. Please bear with me.
I want to rotate an ImageView. I set up a thread for it:
public class ThreadAnimation extends Thread
{
private ImageView iv;
private RotateTransition rt;
public ThreadAnimation(ImageView iv)
{
this.iv = iv;
}
#Override
public void run()
{
while (true)
{
RotateTransition r = new RotateTransition();
r.setToAngle(360);
r.setCycleCount(1);
r.setDuration(Duration.millis(300));
r.setNode(iv);
r.play();
try
{
sleep(100);
} catch (InterruptedException e)
{
return;
}
}
}
}
I call this inside my controller class, upon pressing a Button.
animation.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle (ActionEvent abschicken)
{
ThreadAnimation thread = null; //ANIMATION PIZZA
if (thread == null)
{
thread = new ThreadAnimation(olivenview);
thread.start();
}
}
});
My ImageView olivenview will rotate just like I wanted it to. However it takes quite a long time until it seems to stop (I can see it because the button triggering it still looks triggered for a while) and when I go ahead to press it a second time afterwards, I get a nonstop error stream with a lot of null pointer exceptions. I am very clueless, can anyone help me out? Is this due to my Thread Setup or does the problem lie somewhere else (in code that I didn't post here)?
I believe you do not need threads for this. Notice the .play() method returns immediately and the animation will run in the background.
That being said, try this.
...
//Create your rotation
final RotateTransition r = new RotateTransition();
r.setToAngle(360);
r.setCycleCount(1);
r.setDuration(Duration.millis(300));
r.setNode(iv);
//When the button is pressed play the rotation. Try experimenting with .playFromStart() instead of .play()
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent action) {
r.play();
}
});
...
On an other note I recommend switching to java 8 so that you can use lambda expressions instead of the anonymous class!

NullReferenceException Fire Ball

I'm working on this game breakout-game
And i'm trying to make the ball fire and collide with the wall bouncing, to do that I did what he said, I added a script and put this code:
public class BallMove : MonoBehaviour {
private Rigidbody rb;
public float ballVelocity = 800f;
private bool isMove;
// Use this for initialization
void awake() {
rb = GetComponent<Rigidbody> ();
}
// Update is called once per frame
void Update () {
if (Input.GetButtonDown ("Fire1") && isMove == false) {
transform.parent = null;
isMove = true;
rb.isKinematic = false;
rb.AddForce (new Vector3(ballVelocity,ballVelocity,0));
}
}
}
I understand every line of this code, but when I try to play this, I got a nullReferenceException ,I can run the game but when I press the key I'm getting a error,someone know why? and what happens?
You should use Awake(), not awake(). In your case, you are using a "customized" function, and not the "official" one used by the Unity engine.
So, the engine cannot start that function by itself, and rb stills null when used in the Update().
Example:
void Awake() {
rb = GetComponent<Rigidbody> ();
}

JavaFX Popup needs to be called from javaFX GUI thread?

I've got this Controller connected to a FXML-file with several buttons, labels, a table, etc.
I've got some popups that get initialized and shown when different buttons get clicked and that works fine.
I've got another popup that I'd like to 'pop up' when something goes wrong, so this is called when an event get's handled that has been sent from java-code in another class.
This message pop-up get's called, but the code within the Platform.runLater() isn't executed, actually freezing the GUI.
There's one distinction I've found that seems to cause this and that is that a Platform.isFxApplicationThread() that I call right before the Platform.runLater() returns false in this message pop-up where it returns true when one of the other pop-ups get called from a button-click.
As I've also tried one of those pop-ups that's normally called from a button-click and that also doesn't work when it's called from the code that get's executed because of the incoming event, I'm pretty sure this is the problem, but Platform.runLater states "This method, which may be called from any thread, will post the Runnable to an event queue and then return immediately to the caller." and that seems not true for me, so I'm kinda puzzled if this actually is the problem ...
Has anyone encountered this before and / or does anyone know what I'm doing wrong?
This works fine:
#FXML
private void btnCashClicked(ActionEvent event) {
screensController.getCashTransactionController().addCashTransactionListener(this);
labelToPay = new Label(eurosToPay + " euro");
sealbagTextField = new SealbagTextField();
PopupUtils.showCashPaymentPopup(btnSealbag, btnCashOk, labelPaid, labelSealbag, labelToPay, lblExchange,
labelExchange, labelReturnValue, eurosToPay, btnCash, this, sealbagTextField);
screensController.getMainController().startTransaction(amountInCents, PaymentType.Asap);
}
This code in the same controller class doesn't show a pop-up:
#Override
public void showErrorOnScreen(String message) {
// temporary usage of label and textfield
labelToPay = new Label(eurosToPay + " euro");
sealbagTextField = new SealbagTextField();
PopupUtils.showCashPaymentPopup(btnSealbag, btnCashOk, labelPaid, labelSealbag, labelToPay, lblExchange,
labelExchange, labelReturnValue, eurosToPay, btnCash, this, sealbagTextField);
//PopupUtils.showMessagePopup("Error", message, "Close", 374, 250, btnCancel);
}
I'm on Windows and using jre1.8.0_60
The code of the cashPopup:
public static int showCashPaymentPopup(Button btnSealbag, Button btnCashOk, Label labelPaid, Label labelSealbag, Label labelToPay, Label lblExchange, Label labelExchange, Label labelReturnAmount, int amount, Node node, PayScreen parent, SealbagTextField sealbagTextField) {
int paid = 0;
logger.debug("cashPopup is on GUI thread: " + Platform.isFxApplicationThread());
Platform.runLater(new Runnable() {
#Override
public void run() {
cashPopup.getContent().clear();
Rectangle rectangle = new Rectangle();
rectangle.setArcHeight(20);
rectangle.setArcWidth(20);
rectangle.setFill(Color.LIGHTBLUE);
rectangle.setWidth(466);
rectangle.setHeight(311);
rectangle.setStroke(Color.DARKBLUE);
rectangle.setStrokeType(StrokeType.INSIDE);
...
cashPopup.getContent().addAll(rectangle, textArea, headerLabel, lblDesc, lblAmount, labelAmount, lblPaid, labelPaid, lblToPay, labelToPay, btnCashOk, lblSealbag, labelSealbag, lblExchange, labelExchange, labelReturnAmount, btnSealbag, btnCancel);
cashPopup.show(node, 150, 164);
}
});
return paid;
}
And the showMessagePopup:
public static void showMessagePopup(String title, String text, String buttonText, int posX, int posY, Node parent) {
logger.debug("messagePopup is on GUI thread: " + Platform.isFxApplicationThread());
Platform.runLater(new Runnable() {
#Override
public void run() {
logger.debug("0");
messagePopup.getContent().clear();
Rectangle rectangle = new Rectangle();
rectangle.setArcHeight(20);
rectangle.setArcWidth(20);
rectangle.setFill(Color.LIGHTBLUE);
rectangle.setWidth(500);
rectangle.setHeight(300);
rectangle.setStroke(Color.DARKBLUE);
rectangle.setStrokeType(StrokeType.INSIDE);
Label headerLabel = new Label(title);
headerLabel.setStyle("-fx-font-size: 18; -fx-font-family: Arial;");
headerLabel.setLayoutX(15);
headerLabel.setLayoutY(10);
TextArea textArea = new TextArea();
textArea.setStyle("-fx-font-size: 14; -fx-font-family: Arial;");
textArea.setLayoutX(10);
textArea.setLayoutY(35);
textArea.setMaxWidth(480);
textArea.setMinHeight(190);
textArea.setMaxHeight(190);
textArea.setEditable(false);
textArea.setWrapText(true);
textArea.setText(text);
Button btnClose = new Button(buttonText);
btnClose.setLayoutX(180);
btnClose.setLayoutY(235);
btnClose.setPrefSize(120, 54);
btnClose.setStyle("-fx-font-size: 18; -fx-font-family: Arial; -fx-text-fill:white; -fx-background-color: linear-gradient(#8b9aa1, #456e84), linear-gradient(#c5dde7, #639fba), linear-gradient(#79abc1, #639fba); -fx-background-insets: 0,1,2; -fx-background-radius: 6,5,4;");
btnClose.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
messagePopup.hide();
}
});
messagePopup.getContent().addAll(rectangle, headerLabel, btnClose, textArea);
messagePopup.show(parent, posX, posY);
}
});
}
logger.debug("0") isn't even executed ...
Found it, by running in debug mode and suspending the Java FX thread to see what it is doing.
There's this 'other thread' that gets started from the main program and which needs to get started before the process can continue. This other thread looks like this:
pinPadAsSlaveThread = new Thread(pinPadAsSlave);
pinPadAsSlaveThread.start();
while (!pinPadAsSlave.isRunning()) {
// wait for pinPadAsSlave to be running
try {
Thread.sleep(10);
} catch(InterruptedException ie) {
// ignore
}
}
Normally this takes about 50 ms, but as the pin pad is unavailable on the network this becomes an infinite loop. That on itself should be handled of course, by letting this loop only try it for 50 times or so.
But the real problem is that this thread that is put to sleep for 10 ms all the time is the Java FX thread. I don't know why the Java FX thread is doing the setting up of the communication, as it shouldn't (and I didn't ask for that by putting it inside a platform.runLater or something alike), but the fact is: it is ...

issue with lwuit right-to-left label ticker

I was trying to set ticker on a Label with lwuit 1.5, faced this issue:
if I set label.setRTL(true) and then call
label.startTicker(UIManager.getInstance().getLookAndFeel().getTickerSpeed(), true);
ticker just shows first 21 characters of the label's text and ignores the rest.
I've tried:
label.setRTL(false);
label.startTicker(UIManager.getInstance().getLookAndFeel().getTickerSpeed(), true);
it shows up OK, the text goes from left to right, but when I set this in a FocusListener (cause ticker should start when the label receive focus and stop after it loosed focus) it just change direction (goes from right to left).
here's what i do:
Label test = new Label();
Container c1 = new Container(new FlowLayout());
test.setText("1234567890ABCDEFGHIJ1234567890");
test.setFocusable(true);
test.setRTL(false);
test.addFocusListener(new FocusListener (){
public void focusGained(Component cmpnt) {
((Label)cmpnt).setRTL(false);
((Label)cmpnt).startTicker(UIManager.getInstance().getLookAndFeel().getTickerSpeed(), false);
}
public void focusLost(Component cmpnt) {
((Label)cmpnt).stopTicker();
}
});
c1.addComponent(test);
Look at setLabelFor, it will ticker the label for test when test gains focus. You should probably set RTL globally in the look and feel class.
I found the problem. wrong direction happens because I've implemented focusListener before adding the label to container (c1). so I just did this:
c1.addComponent(test);
test.addFocusListener(new FocusListener (){
public void focusGained(Component cmpnt) {
((Label)cmpnt).setRTL(false);
((Label)cmpnt).startTicker(UIManager.getInstance().getLookAndFeel().getTickerSpeed(), false);
}
public void focusLost(Component cmpnt) {
((Label)cmpnt).stopTicker();
}
});
and it simply worked.
in fact I got the idea from Label class source code (lines 149 ~ 153):
// solves the case of a user starting a ticker before adding the component
// into the container
if(isTickerEnabled() && isTickerRunning() && !isCellRenderer()) {
getComponentForm().registerAnimatedInternal(this);
}
this part does not work, but I don't know why. just hope someone fix this bug.

Resources