Is there a way in ActionScript to force an IMMEDIATE update of the stage, _not_ after an event? - actionscript-3

I know the method MouseEvent.updateAfterEvent() or KeyboardEvent.updateAfterEvent() which will force a re-render of the stage just after the event is handled rather than waiting for the next frame.
However, I need a method to force an immediate render at the very moment I call it. Is there such a method?
Actually my problem comes from the demential design of ActionScript's printing API (PrintJob). Inconsistent with the whole ActionScript architecture, when you call PrintJob.start(), everything is completely frozen while the printing dialog is shown until the user clicks the print or cancel button. Execution of any code after the PrintJob.start() call is resumed after that.
Among a lot of other much worse issues coming from this gigantic design flaw, there is mine:
public function someMouseOrKeyboardEventHandler() {
somethingThatUpdatesTheDisplayList();
var somePrintJob=new PrintJob();
somePrintJob.start();
//...
somePrintJob.send();
}
When this handler of mine is called, the changes made to the display list will not be visible until after the printing dialog has been closed, so I can't, for example, show something on the screen just before I open the print dialog.
updateAfterEvent() won't help a bit (already tried it). It won't change a thing, since it only forces rendering after the event handler code is executed.
Is there any updateRightNow()-like thing?

Nope, you unfortunately can't force an update in the middle of your code.
You can, however, wait until the next frame to call start() on the PrintJob; this will give Flash time to update the stage before everything freezes.

Related

Strategy for finding a missing mouse event in AS3

Will make this brief, I have a game map with units on it and had finalized a fully interactive minimap where the units on the minimap have event listeners for rollover/rollout (displays a small popup unit data summary) and click (selects the "real" unit on the main game map and scrolls the viewpoint to that location). All done, tested, working.
I then implement an interactive scrollable unit list with more status summary data and dozens of objects with rollover/rollout/click listeners. All tested and working fine.
Then I go back and look at my minimap, and the listeners on the mini-ships aren't working anymore. Things tried:
Debug code to make sure listeners still being added
Debug to watch the one place where I remove those listeners to make sure that ain't happening unexpectedly
Debug to watch all the places I refresh that dialog to make sure every iteration adds the listeners back
Can't see that there is any transparent object on top intercepting
Checked mini-ship parents to make sure I didn't turn off mouseChildren or something like that somewhere
No added stage-level listener, in fact I killed all of them temporarily to test this
What happens when I debug with a breakpoint on the mini-ship listener handler is nada. It's no longer receiving mouse events. So either something I haven't thought of has stopped them from listening or something I don't know of is intercepting.
So what is the strategy here? How can I find the break in the chain?
Well knowing what the actual problem was certainly gives us the advantage of hindsight... that being said, you could have detected the error by adding a trace call inside your function that adds the listener and another one inside your function that removes it. Then you would have seen that it isn't getting re-added. Or you could set break points there.

Pause UI in WinRT 8.1

I can't for the life of me get the following functionality to work:
User taps item
Item's image becomes visible via changing visibility property of image
After a short period of time image becomes invisible again (with no user input) via changing the
visibility property
Or, more simply:
Make visible UI change
Pause so user can see UI change
Reverse step 1's UI change
Step 2 happens before steps 1 and 3 regardless of where the code is because the UI is not updating until the logic finishes (I assume).
I am setting the visibility of the image via data binding with INotifyPropertyChanged. All works as expected except when I'm trying to introduce the pause.
I'm trying to pause with this simple method:
private void Pause()
{
new System.Threading.ManualResetEvent(false).WaitOne(1000);
}
It does pause, but the UI changes wait until after that pause even though a change to the bound data happen befores the pause is called, and the other change after.
I have tried using the dispatcher, but it doesn't change anything, and I don't understand it enough:
await dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
{
clickedCard.IsFaceDown = false; // makes the image visible via data binding
}
);
Pause();
I think I need to do something with threading, but I am going in circles.
Any ideas?
You should never do something like this inside the UI thread of your app:
new System.Threading.ManualResetEvent(false).WaitOne(1000);
There are various reasons for not doing it, but in your particular case the problem is that XAML only re-draws once your event-handler completes. So basically this happens:
The item is invisible
Your event handler is called
You set it to visible (but the UI doesn't refresh yet)
You freeze the thread for a second
You set it to invisible again
The event-handler completes
Now the UI updates based on the current value (which is invisible)
I suggest you look at building a Storyboard to do this - Blend can help. See here.

Handling a keyboard event in one place for the whole program

I'm creating a little developer console for an AS3 AIR application, I'm wanting F12 to add the toggle the display of the console screen but I don't want to litter my program with a bunch of calls to the Console to show or hide it, I also don't really want to be re-creating the console on different screens of my application.
I'm wondering if there's a way or a place I can put my keyboard event to toggle the display that will handle it across the entire application? At the moment I've tried putting it into my Main class which calls the first screen in the hopes that would be able to handle it but as soon as I click on another screen my eventListener isn't called.
Any ideas?
You could add your event listener to FlexGlobals.topLevelApplication instead of specific views, this would achieve the reduction you require
For true application level keyboard handling, attach the listener on the NativeApplication.nativeApplication object.
NativeApplication.nativeApplication.addEventListener(KeyboardEvent.KEY_DOWN, toggleDevConsole,false,0,true);
Attaching the listener to the stage will only work when that particular stage (window) has the focus. This will become an issue if your application has multiple windows that require interaction.
For single window applications, either will work.
Woops, I'm not quite with it today!
For future reference I added the event listener to the Stage in my Main function and it's being picked up every time.
stage.addEventListener(KeyboardEvent.KEY_DOWN, toggleDevConsole, false, 0, true);

Flash/AS3 "Shutdown" or "close" event?

I am making a Flash puzzle game. When the user loads the game, it needs to ask whether to resume the game from the last state (if it exists). I have a serialization system in place, but I need to ensure that the loaded state is definitely the last state.
One solution is to save the state to a SharedObject every time the state changes (when the player makes a move). However, the game state sometimes includes a countdown, so I'd have to be constantly (or periodically) saving the state in order to retain it. I guess this is acceptable, but it seems kludgey.
Is there any event which is fired when the swf is closed? Or anyone else have another elegant solution to this?
(I'm not using AIR, but solutions requiring AIR are appreciated.)
Edit: Another important point is that I may not have control over the embedding HTML for the game, as it may be syndicated to many sites. So solutions involving javascript aren't ideal.
If your Flash is hosted on a HTML page, you can use the 'Window is closing' event notification to fire a message into your Flash object either using old-skool GetVariable() or new-stylee FlashCall() mechanisms.
Whether you'll actually be able to persist state before your Flash object is destroyed is another question... you could always do the (evil) 'Are you sure you want to close/navigate away from this window?' alert that some sites use.
Handling DOM Events in Flex
HTML 5 events
The on-close event sounds the right solution, but I wonder if you could 'split' your serialisation? i.e. save the full puzzle state on each move, but also have a secondary 'lightweight' state for your countdown (or anything similar) which could be updated each time the countdown changes.
That may be easier than trying to catch the close event and save before the page is destroyed (especially as browsers are not consistent in this area).
this one should help you

symbols placed on the timeline become undefined if stepping backwards

I am using the frames in the timeline of a .swf as pages in a flash app. The user can advance to the next page by clicking a button that takes her to the next frame. Similarly, it is possible to navigate to the previous frame/page as well.
Most of the content is placed on the stage (i.e. created by dragging an instance of a library symbol to the stage) but properties of those instances, such as .visible might be changed via actionscript. Also, some objects are loaded from external flash files and displayed programmatically with addChild / addChildAt.
The problem is, if I am on Frame N+1 and there is an object displayed on the stage programmatically (i.e. with addChild, not by having it placed on the stage) and navigate to Frame N where there is an object that is placed on the stage (i.e. dragged from the library),
then the instance of that object is undefined/null and throws an error if I try to set its properties (like .visible).
The error does not occur if I am moving to the NEXT frame, only if I am moving to the PREVIOUS one. Therefore I assume that some kind of initialization is not getting called while going one frame back.
I was also thinking that the objects would just not "live" to the next timeframe, that is, their value would be lost and re-initialized because of scope, but if there is no dynamically created object on the stage, I can navigate back and forth just fine.
Is there a way to ensure that the objects created on the stage do not disappear while navigating back to the previous frame?
The first, and more useful, part of the answer is this: timeline keyframes and scripts can give conflicting information about display objects - whether they should exist, where they should be, and so on. For example, when you add an item by playing into its frame, and then delete it with script, and then play into its frame again. When this happens, there's no unambiguously correct thing for Flash to do, so it tends to be unpredictable. I believe what generally happens is that once you fiddle with a given object via script, it's considered to no longer pay attention to the timeline - but your mileage will vary.
Having said that, the reason things are different when you play backwards is the second and more arcane part of the answer. Internally Flash functions differently when seeking forward and backwards on the timeline. Flash internally treats keyframes as changes to be applied in the forward direction, so as you play forward, it applies those changes in sequence. When you move backwards, however, from frame N+X to frame N, it doesn't scan through the intervening X frames reversing those changes - it jumps back to frame 1 and fast-forwards along to frame N. Normally, it amounts to the same thing and you don't need to worry about it, but when you get into the twitchy area where scripts and the timeline have a different idea of what should be on the stage, you're liable to see things behave differently depending on which way you jump (as you are now).
The super-short version is, for things to work predictably, try to ensure that any given object gets added, updated, and removed the same way - either all via script, or all via the timeline. When that seems impossible, fiddle with your content structure - usually, the best solution is to change your object into two nested ones, so that the things you want to do with script occur one level higher or lower than the things you want to do with the timeline.
I'm not sure I got your question right, but as3 does not instantiate elements on the timeline as soon as you gotoAndSomething, but later that frame.
That is, you can't
this.gotoAndPlay(10)
this.elementOnTimelineFrame10.DoSomething()
without errors.
I remember using this chunk of code in the past to work around this problem. It uses the Stage.Invalidate() function to wait for an Event.RENDER before trying to access and children, more info (although vague as hell) is here
private function init():void
{
stage.addEventListener(Event.RENDER, stage_renderHandler);
}
private function stage_renderHandler(evt:Event):void
{
// Run your code here
updateChildren();
}
private function enterFrameHandler(evt:Event):void
{
// triggers the RENDER event
stage.invalidate();
}
This also might me very costly (performance wise). I would strongly advise against dynamically adding/removing objects to an existing timeline, is there any way in which you can place an empty Sprite above the timeline animation and use that for all your dynamic content?
Hope this helps