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.
Related
I need to load a large file to parse and draw with OpenGL. The whole process is very time-consuming. So I want to realize a prompt dialog box before parse. But the code as following is not work.
void parseFile()
{
QMessageBox* msgbox = new QMessageBox();
msgbox->setModal(false);
msgbox->setWindowTitle(tr("message box"));
msgbox->setText("Please wait patiently......")
msgbox->show();
/* parse file and draw */
......
}
But it shows like also be frozen:
How to realize it?
show() does not actually show the content of the dialog. It only tells the event loop to show the dialog ASAP. But since you call more code after immediately after show(), the evnt loop does not have a chance to do its work.
The easiest way to solve this is to call QCoreApplication::processEvents() after msgbox->show(). This will force the event loop to do the work immediately.
If this does not work then try this parameter QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents)
Another option would be to move the heavy calculation to a function and than show the dialog and then schedule the calculation using a timer.
...
msgbox->show();
QTimer::singleShot(0, &doHeavyWork);
This would first handle all events related to showing the dialog and only after that it will start the heavy work (i.e. parsing the file).
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...
I can't seem to find the answer to what I would have thought was a common problem.
What I want to do this is:
1. Show the Open File Dialog
2. Process the file selected
3. During processing the file, report progress to the User
I have a file defined, and am using the browseForOpen and AddEventListener:
public var fileInput:File = new File();
fileInput.browseForOpen("Open file",[filter]);
fileInput.addEventListener(Event.SELECT, onFileSelect);
// Step 2 - function gets called to process the file
private function onFileSelect(e:Event):void
{
// Step 3 - do some processing, and at intervals report progress to the screen
}
My issue is - any changes to the screen within the event listener do not get done until the function is complete.
Any help would be appreciated,
Thanks
Start a timer perhaps and let it check status of a variable(that denotes processing progress) as a separate running function it would not be predisposed to waiting on the parent function.
[ to be clear Im saying call a sperate function from the timer.]
But I am inclined to agree with Flextras.com in that most times I have done this the processing was milliseconds so just didnt get seen.
In Step 3, if you are doing some cpu intensive job(like huge xml parsing), then you might be seeing this NOT updating problem. As Flex is single threaded, you better make use of Green threading concept.
You can read about Green Threading here.
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.
Currently I'm working on an application (Flex) which heavily uses external SWFs.
I'd like to create a static method which takes a filename as an argument and returns SWF wrapped in some other class.
public static function getSWFWrapperFromFile(path:string):SWFWrapper {
var loader:SWFLoader = new SWFLoader();
loader.addListener(Event.COMPLETE, onLoad);
loader.load(path);
// If I create new SWFWrapper object here and try to assign it the loader.content I get null reference
}
However, with this approach I'm not able to encapsulate logic in one function, because of non-blocking load() and the need of onLoad handler. Is there possibility to force a delay after calling load method? Or mayber there is another, better way?
Thank you,
Alonzo
The display list is well-designed for asynchronous loading. You'll notice that Loader is a DisplayObject-derived class and thus can be placed directly in the display list. When its content is loaded it will be a child of the Loader. Thus, if SWFWrapper is DisplayObject-derived, you can simply do the following at the end of your code:
var wrapper:SWFWrapper = new SWFWrapper();
wrapper.addChild(loader);
return wrapper;
You need to wait until your Loader object has completed. Try adding in an event handler. Yes, the whole thing gets murky after a point of time when you have multiple loaders and and have to wait till the last one has completed. But that's the way it is if you are going to use SWFLoader.
In flash you cannot block in a method - you always have to use the onLoad handler for loading data. (The as3 execution model is single threaded, if you block in a method the rest of the program will not get executed)
Like others said, you can't do that. However, take a look at the BulkLoader AS3 library, which takes the burden of managing multiple loaders simultaneously and waiting for their completion, off your shoulder. It is well documented, and requires only a few lines to use.