How to automatically run a code from javafx new Scene - javafx

I am completely new to Java and I am learning it while developing an app for a school project.
Image Link
I want to code the above program. In it ,
The user will click Ready button in screen 1.
Then screen two will appear and an image of a butterfly will be shown in a order given by me[Preset using a CSV file] Like shown in screen 2 and 3.
Finally, a button set will appear in the grid and user has to select the buttons in the order of the butterfly appearance.
I am stuck in finding a way to start screen 2 and automatically play the butterfly sequence.
I tried putting the image.setimage() on the initialize() block in my screen 2 controller with a delay in-between each setimage() . but it dosent work.
Anyone can suggest me a way to handle this kind of task? Thank a lot in advance.

The issues often seen with this kind of code for beginners are doing sleep or some other long-running operation on the application thread to do some animation. However blocking the javafx application thread results in the scene not being updated resulting in a freeze of the gui.
You either need to move the long-running parts of this animation to a background thread and use Platform.runLater for any GUI updates or use something designed for this exact purpose. There are multiple classes that could be useful in the javafx.animation package, but the most convenient of them seems to be Timeline:
Store the sequence of movements in a suitable data structure and use the Timeline to trigger an event handler in regular intervals to update the gui:
List<FieldIndices> fieldIndices = ...
final Iterator<FieldIndices> iterator = fieldIndices.iterator();
final Timeline timeline = new Timeline();
timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(1), evt -> {
if (iterator.hasNext()) {
moveButterfly(iterator.next());
} else {
removeButterfly();
timeline.stop();
}
}));
timeline.setCycleCount(Animation.INDEFINITE); // repeat until stop is called
timeline.play();
Now all that's left for you to implement is reading the data to a list and implementing the logic of moving the butterfly to a new position.
Note that I do not actually recommend using more than 2 scenes: The user will expect the same position for the buttons and the "fields" showing the butterfly. If you design 2 fxmls any adjustment to one of the scene would require you to do the same adjustments to the other scene. This makes the layout hard to maintain. The alternative requires you to create the scene in java code, but the repetitive nature of the scenes makes this a good idea anyways. (The alternative is injecting 16 fields to the controller and collecting them into a suitable data structure; This is error prone and any change of one of the buttons would probably require 16 changes in the fxml. Use a nested for loop and you need to write the logic for creating a button only once storing the buttons in e.g. a nested array can be done at the same time...)

As I understand, you wanna play butterfly sequence once 2nd stage is shown...To achieve that, you could try something like:
List positions = new ArrayList(); //places to show butterfly (e.g. table cells)
secondStage.setOnShown(windowEvent -> {
// update UI with Pltform.runLater()
// moveButerflyTo() is your method to place butterfly on given place
positions.forEach(position -> Platform.runLater(() -> moveButerflyTo(position)));
});
I didn't try this but it do the job...

Related

Qt Test Simulated MouseEvent not forwared to child widget

I did some survey, if it might be possible to use QtTest to test some of my custom Qt Widgets.
I was able to build and run tests and I was also able to simulate events and check them with QSignalSpy.
The widgets I'm going to tests are not revealing their internal subwidgets, so that I have to simulate the positions of my mouse clicks relative to their parent widget.
For some reason I'm failing with this approach. The following snippet shows what I'm trying to achieve.
auto button=new QPushButton("Hello");
auto grpBox = new QGroupBox("Group Box");
grpBox->setLayout(new QVBoxLayout);
grpBox->layout()->addWidget(button);
QSignalSpy spy(button, &QPushButton::clicked);
grpBox->show();
QTest::mouseClick(button, Qt::MouseButton::LeftButton);
QTest::mouseClick(grpBox, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier, QPoint(250,70));
QCOMPARE(spy.count(), 2); // 1!=2
The first click is considered correctly, whereas the second one vanishes somehow. Why is that?
I'm wondering, if I really understood how to use the framework correctly, as dealing with mouse positions, seems to be too tedious and fragile for a practical test framework.
Revision:
It's obvious that using coordinates in a GUI test are very fragile. Hence, I found a solution utilizing findChild that actually does the same thing.
auto button=new QPushButton("Hello");
button->setObjectName("PushButton");
auto grpBox = new QGroupBox("Group Box");
grpBox->setLayout(new QVBoxLayout);
grpBox->layout()->addWidget(button);
QSignalSpy spy(button, &QPushButton::clicked);
grpBox->show();
QTest::mouseClick(button, Qt::MouseButton::LeftButton);
if (auto btn = grpBox->findChild<QPushButton*>("PushButton")) {
QTest::mouseClick(btn, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier);
} else {
QVERIFY(false);
}
QCOMPARE(spy.count(), 2);
This combines two advantages. Firstly, it is no longer necessary to deal with coordinates and secondly you still doesn't need to touch the code of the widgets you are going to test.
For this approach it seems to be advantageous, if every gui element has a unique objectName() supporting an easy search mechanism.

How to listen to visible changes to the JavaFX SceneGraph for specific node

We created a small painting application in JavaFX. A new requirement arose, where we have to warn the user, that he made changes, which are not yet persisted and asking him, if the user might like to save first before closing.
Sample Snapshot:
Unfortunately there are a lot of different Nodes, and Nodes can be changed in many ways, like for example a Polygon point can move. The Node itself can be dragged. They can be rotated and many more. So before firing a zillion events for every possible change of a Node object to the canvas I`d like to ask, if anyone might have an idea on how to simplify this approach. I am curious, if there are any listeners, that I can listen to any changes of the canvas object within the scene graph of JavaFX.
Especially since I just want to know if anything has changed and not really need to know the specific change.
Moreover, I also do not want to get every single event, like a simple select, which causes a border to be shown around the selected node (like shown on the image), which does not necessary mean, that the user has to save his application before leaving.
Anyone have an idea? Or do I really need to fire Events for every single change within a Node?
I think you are approaching this problem in the wrong way. The nodes displayed on screen should just be a visual representation of an underlying model. All you really need to know is that the underlying model has changed.
If, for example, you were writing a text editor, the text displayed on the screen would be backed by some sort of model. Let's assume the model is a String. You wouldn't need to check if any of the text nodes displayed on screen had changed you would just need to compare the original string data with the current string data to determine if you need to prompt the user to save.
Benjamin's answer is probably the best one here: you should use an underlying model, and that model can easily check if relevant state has changed. At some point in the development of your application, you will come to the point where you realize this is the correct way to do things. It seems like you have reached that point.
However, if you want to delay the inevitable redesign of your application a little further (and make it a bit more painful when you do get to that point ;) ), here's another approach you might consider.
Obviously, you have some kind of Pane that is holding the objects that are being painted. The user must be creating those objects and you're adding them to the pane at some point. Just create a method that handles that addition, and registers an invalidation listener with the properties of interest when you do. The structure will look something like this:
private final ReadOnlyBooleanWrapper unsavedChanges =
new ReadOnlyBooleanWrapper(this, "unsavedChanged", false);
private final ChangeListener<Object> unsavedChangeListener =
(obs, oldValue, newValue) -> unsavedChanges.set(true);
private Pane drawingPane ;
// ...
Button saveButton = new Button("Save");
saveButton.disableProperty().bind(unsavedChanges.not());
// ...
#SafeVarArgs
private final <T extends Node> void addNodeToDrawingPane(
T node, Function<T, ObservableValue<?>>... properties) {
Stream.of(properties).forEach(
property -> property.apply(node).addListener(unsavedChangeListener));
drawingPane.getChildren().add(node);
}
Now you can do things like
Rectangle rect = new Rectangle();
addNodeToDrawingPane(rect,
Rectangle::xProperty, Rectangle::yProperty,
Rectangle::widthProperty, Rectangle::heightProperty);
and
Text text = new Text();
addNodeToDrawingPane(text,
Text::xProperty, Text::yProperty, Text::textProperty);
I.e. you just specify the properties to observe when you add the new node. You can create a remove method which removes the listener too. The amount of extra code on top of what you already have is pretty minimal, as (probably, I haven't seen your code) is the refactoring.
Again, you should really have a separate view model, etc. I wanted to post this to show that #kleopatra's first comment on the question ("Listen for invalidation of relevant state") doesn't necessarily involve a lot of work if you approach it in the right way. At first, I thought this approach was incompatible with #Tomas Mikula's mention of undo/redo functionality, but you may even be able to use this approach as a basis for that too.

progressBar for large function

I have a function that when called takes about 10 seconds to run. I’d like to add a simple progress bar to show the user something is happening but the progressBar doesn’t run until the function is finished
btn.addEventListener("click",bigFunction);
private function bigFunction(event:Event):void{
var progress:ProgressBar = new ProgressBar();
progress.indeterminate = true;
progress.validateNow();
mainPanel.addChild(progress)
// do massive loop
}
Is there a way to force the progress bar to run before the rest of the function is completed. Cheers
The execution model for Flex/Actionscript is single threaded. You have to take some tricky approach to handle this.
http://blogs.infosupport.com/flex-4-a-multi-threading-solution/
Take a look at this example.
I doubt this is possible. Why? because Flash (Flex does nothing) is single-threaded, a 10 second function will just cause the display (and hence the browser, if you are displaying it in a browser) to freeze. Even so, you can try the following:
Force a refresh on the progressbar using
progress.invalidateDisplayList();
after the addChild
This will add the progressbar to the redraw list
In Flash, to repaint anything, you need a new frame to be processed by swf (Event.ENTER_FRAME). Your 10-second function should be split to shorter calls, or it indeed just hangs the Flash player. If you're processing something large, do it in limited portions. You can use getTimer() function to control portion size.

Editing A Library Symbol From ActionScript

In the Flash authoring environment I can edit a library symbol and all on-stage instances based upon it reflect the changes. How can I do the same thing in ActionScript? There seems to be no way to address a library symbol.
For example:
Inside Flash CS3, I have created a Square.swf file that has 100 instances of the library symbol Square.
Now, Square.swf is loaded into another file BlueSquare.swf and I want to change the Square symbol into a blue square so that all instances of Square become blue.
How do I do this using Actionscript?
Thanks for the help.
What's in a clip's library symbol is the author-time definition of that object - you can't change it at runtime. Instead the normal approach would be to dynamically change the contents (not definitions) of the clips you want to change, which can be done in various ways, but all the good ways of doing that involve making the dynamically-changing clip understand how to update its appearance. So you need to be able to re-author the changing clips to suit your needs.
If you're loading in an animation that somebody else made, and trying to go through and replace all instances of object A with object B, the only way to achieve that is to traverse through the content's display list looking for A, and when you find one, remove its children and replace them with the the contents of a B. Mind you, for animations that may not really solve your problem, since animations normally add and remove clips frequently, so at any given point you could replace all the "hand" clips with "hand2", but then a frame later new "hand" clips might come into existence. But short of opening up the SWF and changing the binary data inside, there's no other way to dynamically change all of a given object to something else unless the object knows how to change its contents.
If it is only about making sure that the square you are attaching is blue you could use the colorTransform to change its appearance:
var someSquare:Square = new Square();
someSquare.transform.colorTransform = new ColorTransform(0,0,0,1,0x00,0x00,0xff,0x00 );
addChild( someSquare );
Of course this does not change the color of all instances that you have already attached.
If you really wanted to change the actual SWF symbol in Actionscript the only way I see is to parse the swf with as3swf ( https://github.com/claus/as3swf/wiki ), find the shape tag of the symbol, change it and then load the ByteArray that contains the swf via loader.loadBytes() - but that's admittedly quite a complicated way and you can achieve the same result by simply putting some colorizing code into the shape symbol itself and then trigger the color change via an Event that is broadcasted by your main app.
Of course, if you make custom component, when you change it changes will appear on all instances of that component/class. Here's the example: http://livedocs.adobe.com/flex/3/html/intro_3.html
On the other hand, if you use modules whey pretty much do the same as swf-s you used in Flash, when you rebuild-recompile them changes will reflect on your main application which uses them. Here's th eexample for modules: http://blog.flexexamples.com/2007/08/06/building-a-simple-flex-module/
So MXML/AS component/class are your "symbols" which you can create or drop on stage on fly.
Modules are "movies" you can load and they run on their own with possibility to communicate to main movie.
The closest way of achieving this is to use Bitmaps. If you update the bitmapData they display, they will all update automatically.
However this approach is not good at all. You should maintain application state separately in an object model, and have the visualisation update, if the state changes.
What you want to do, is to misuse a feature for changing graphic appearence at design time, to change application state at runtime. In generally, ideas like these can be thought off as bad.
For example if you take the time to separate the state model and the visualisation layer, it will become fairly easy to save the game state on a server or to synchronize it with other clients to achieve multiuser features.
greetz
back2dos
If you are trying to build an Avatar and user can customize your Avatar parts e.g. hands, legs, face etc. and you want all these assets to be kept in separate swf file, that is pretty straightforward. You keep all the assets, in separate swf or one large swf file and load them at runtime. Now, maintain your Avatar object instance and place the child objects, which are chosen by the user.
You can create inside your class a static List with references all the created instances and then apply a change with static methods. For example:
package
{
import flash.display.MovieClip;
import flash.geom.ColorTransform;
public class Square extends MovieClip
{
public static var instances:Array = new Array();
public function Square():void
{
Square.instances.push(this); // This is the trick. Every time a square is created, it's inserted in the static list.
}
// This property gets the color of the current object (that will be the same of all others because the setter defined below).
public function get color():ColorTransform
{
return this.transform.colorTransform;
}
public function set color(arg:ColorTransform):void
{
// Sets the color transform of all Square instances created.
for each(var sqr:Square in Square.instances)
{
sqr.transform.colorTransform = arg;
}
}
}
}

Forcing Flex to update the screen?

This may be a bit of a beginners question, but I can't for the life of me figure it out.
I'm using flex to develop a GUI for a large project, specifically a status bar along the bottom. Within my StatusBar class is a ProgressBar, which other classes doing work can tell to update(change bar completion and label) as they progress. The problem I'm encountering is that flex won't update whats shown on the screen until it's too late, for example
ProgressBar initialized, 0% done
some class sets the ProgressBar to be 12% done
some class does some work
some class sets the ProgressBar to be 56% done
Whats happening is the 12% done is never displaying, it just hangs at 0% during the work, then skips right to 56% done. I've tried to understand the lifecycle of a flex component (invalidation and validation), and I think I understand it and am applying it correctly, but it's not working at all. I need to tell flex to redraw my StatusBar (or at least the ProgressBar within) after some class sets it to be 12% done, but before some class starts doing its work. How do I do this?
As mentioned in other answers, the flash player is single threaded, if you don't break up your work into discrete chunks that can be executed in separate "frames", you're going to see jumps and stutters in the ui, which is effectively what you're seeing.
If you really must see that 12% message, then it's not enough to invalidate the display list, as the display list isn't getting a chance to update until after the 56% work has completed, you must explicitly interrupt the natural event cycle with a call to validateNow() after your message has been set.
This however is not the best way to do things if performance is of concern. You might get by with judicial usage of callLater() to schedule each chunk of work in turn, as this will allow the player to potentially complete a frame cycle (and update the display list) before attempting the next step in your process.
Glenn,
That is not at all how the threading in Flex works whatsoever. Like many UIs it has a message pump on the main UI thread (they do it in frames). When you call callLater() it places the passed in function pointer at the end of the message pump queue (on the next frame) and returns immediately. The function then gets called when the message pump has finished processing all of the messages prior (like mouse clicks).
The issue is that as the property change causes UI events to be triggered, they then place their own messages on the pump which now comes after your method call that you placed there from callLater().
Flex does have multiple threads but they are there for Adobe's own reasons and therefore are not user accessible. I don't know if there is a way to guarantee that a UI update will occur at a specific point, but an option is to call callLater a number of times until the operation occurs. Start off with a small number and increase until the number of iterations produces the result you want. Example:
// Change this to a number that works... it will probably be over 1, depending on what you're doing.
private const TOTAL_CALL_COUNT:int = 5;
private var _timesCalled:int = 0;
//----------------------------------------------------------------
private function set Progress( progress:int ):void
{
progressBar.value = progress;
DoNextFunction();
}
//----------------------------------------------------------------
private function DoNextFunction():void
{
if( _timesCalled >= TOTAL_CALL_COUNT )
{
_timesCalled = 0;
Function();
}
else
{
_timesCalled++;
callLater( DoNextFunction );
}
}
Try calling invalidateDisplayList() after each changes to your progress bar. Something like :
Class StatusBar
{
public function set progress(value:uint):void
{
progressBar.value = value;
progressBar.invalidateDisplayList();
}
}
Flex has an invalidation cycle that avoid screen redrawing everytime a property changes. As an example, if a property's value changes 3 times in a single frame, it will render only with the last value set. You can force a component to be redrawn by calling invidateDisplayList() which means updateDisplayList will be immediatly executed instead of waiting the next frame.
Actionscript in Flash player, like Javascript in the browser, is pseudo-multithreaded. That is, they're single threaded, but they have multiple execution stacks. This means you can't "sleep" in a particular thread, but you can spawn a new execution stack that gets deferred until a later time. The flex way of doing this is the "callLater" function. You can also use the setTimeout/setInterval functions. Or you can use a timer object built into the flash player. Or even "ENTER_FRAME" event listener. All of these will essentially allow you to do what you need, if I'm correct about the cause of your problems.
It sounds like you have one "thread" doing most of your work, never stopping to allow other execution stacks (threads*) to run.
The problem could be what PeZ is saying, but if that doesn't help, you might want to try some deferred calls for worker classes. So your process might look like this now:
Progress initialized.
Do some work.
Update progress bar to 12. (invalidate display list)
setTimeout(doMoreWork, 100);
Update progress bar to 52.
(if your worker is a UIcomponent, you can use uicomp.callLater(...), otherwise, you need to use setTimeout/timers/enter_frame for pure AS3 classes).
Sometimes its necessary set to zero before assign another value.
progressBar.setProgress(0, progressBar.maximum);
progressBar.setProgress(newValue, progressBar.maximum);
I'm using Flash Builder 4.6 and I also have a problem for the display of my progress bar. I open a new window where I start a new multiloader class (39 Mo of content). The new window is opened in background and the main window display a progress bar until the multiloader class has finished his work. However the opening window is blocking the animation of my main window. I know it's not the multiloader class cause I saw it running correctly.
But I will try to find some new ways of doing it.
The main purpose of my post is the complexity adobe has build around flash.
When you seek ressources for your own application or answers for your questions, it's a real pain to find the good ressource. There is a total mix up (at adobe side and at user side) between AS3, Flex, Flash CS, Flash Builder, AiR, ... If you try to develop in AS3, you will find that some examples won't work for you because it is not implemented in your SDK. You have more and more forums giving you the "best practice" or ironic answers based on experiences on different developping platform.
By example, just here above, I see progressBar.value = value; With my experience, I can say that in Flash Builder 4.6, this property is read-only. But It might be a custom class made by the user but who can tell.

Resources