Having read many tutorials, articles and questions, I am still have confusions about updating the GUI. Plus there are numerous related questions here on this website and still no luck - even though I think my problem is very simple.
Basically, I have a JFrame that has a JLayeredPane as its root container. And I have some layers of JPanels inside it.
The main issue is with updating a particular JPanel in this JLayeredPane. And for this particular Panel, I have implemented an update method that changes the contents inside it.
updatePanel(int para)
//doesn't remove this panel
//removes some existing labels and replaces it with new ones
Once I create the whole Frame, obviously just calling this method won't show any change displayed the frame.
private void static main (String[] args){
WindowFrame frame = new WindowFrame()//WindowFrame extends JFrame
frame.updatePanel(2);
.....
.....
}
And that's where I am stuck. I want to update the contents as the frame is displayed.
I saw these methods mentioned by people but due to nature of problems, I couldn't fully grasped the concepts. Plus the documentation on these methods isn't really helping - at least to me.
revalidate()
validate()
repaint()
How/when should these methods should be called? Or is this not the right way of what I should be doing, given these methods and the problem I am trying to solve?
Thank you for your time.
Basically you need two methods:
revalidate()
This method does the same as invalidate() but in AWT event dispatching thread (i will just call it Swing thread later on)). It updates container and all of its ancestors (parent containers in which this one is placed) layouting.
Basically if you either move something inside this container or place/remove components inside of it you should call this method (or invalidate in case you are performing it in Swing thread, for example inside any Mouse/Action listener body or just inside).
repaint()
This method forces component, all its sub-components (if it has them) and parent container (basically if this component is NOT opaque) to update what they are "painting".
Usually you don't need this method since all standard Swing components know when to repaint themselves and they do it on their own (that ofcourse depends on components UIs and some other things). This method might be useful in case you have your own specific components with some unique painting-way (for e.g. some custom selection over the components) and in some rare problematic cases with standard components.
Also the way this method acts depends on the components placement (due to some Swing painting optimizations) - if you have some massive repaints rolling you'd better optimize them to repaint only those parts (rects) that you actually need to repaint. For example if you change the component bounds inside any container the best choice is either to repaint its old bounds rect and new bounds rect OR repaint rect that contains both of those bounds, but not the whole container to avoid repainting uninvolved in the action components.
So, basically in your case after some changes with panels you should call revalidate on their container (or invalidate) followed by repaint (in case revalidate leaves some visual artefacts) again for the container.
Guess i didn't miss anything and i hope that now you know the basic meaning of those methods.
revalidate at the end of your update method like so .
updatePanel(int para){
.....
.....
this.revalidate(); //of course this refer to the panel
parent.revalidate(); // parent refer to the window
}
Related
I have a UI object that, of course, should always be kept in front of all other objects. To do that, I decided to destroy and add it again each frame, like this:
removeChild(UI_Indicator)
addChild(UI_Indicator)
But nevertheless, objects that are created in it’s area still come on top of it. How is this even possible? I also tried the common
UI_Indicator.parent.setChildIndex(UI_Indicator,UI_Indicator.parent.numChildren - 1)
But it doesn’t work too. Any suggestions?
You are not destroying anything with removeChild(), you just stop displaying it. removeChild() isn't even necessary here. addChild() happily takes a DisplayObject that is already a child of the DisplayObjectContainer you called it on and re-adds the child again (to the top)
Instead of doing this readdChild()ing every frame, place your
allways-on-top DisplayObject on the display list once, then create
a DisplayObjectContainer, say a Sprite for example and add it
behind your indicator. Now add all your other DisplayObjects to
that container. This has the disadvantage of requiring you to add
everything to the container. The functionality breaks as soon as you
accidentally addChild() the regular way. This thought process
leads to the second solution below.
In your subclass of DisplayObjectContainer that includes the
indicator, override the methods that interact with the display list
(add/remove children, etc.) All those that could cause something to
get on top of your indicator. This puts you in full control of
what's going on when something is added to this container. You can
either incorporate solution 1 for simplicity's sake: delegate all
method calls to the inner container Sprite or, if you don't like
to have an internal container, do it without it and make sure that
no other child than your indicator is ever assigned the top most
index. You'd create an additional method to add the always-on-top child, like addTopChild() for example.
I have been writing a game in timeline code. I want the different frames (rooms) in the game to be able to share information between each other. Of course, timeline code is limited to the frame it is written in.
After doing quite a bit of reading ("Foundation Game Design with Flash" and a number of articles, tutorials, forums etc) I decided to employ a document class. This did not work either. It seems it only works for frame one but not the rest of the frames (I have four).
How can I have frame four respond to something that happpened in frame one? For example, if the player achieves something in frame one, I want a movie clip in frame four to be visible.
If You are writing your code on the timeline, My suggestion would be to create two layers in the timeline, one for 'frame-actions' - in this layer you insert the code specific to a single frame (will work when the movieclip is stopped on that particular frame).. And also create one more layer called global-actions (for the entire timeline). Only the first frame will be a key frame and there should be empty frames till the end of the timeline.
In this layer actions write the code that you want to access from any keyframe in the same timeline.
If you define a variable in the actions which are written for the whole timeline (global-actions) then that will be available on all the frames.
Now if you want to go to a different frame based on some action, just write some functions in the layer which contains global actions and call that particular function through the frame actions. To go to a different frame use the 'gotoAndStop(frameNumber)' function of flash.
I want to tell you that while it will work, I would not recommend using it in this way.
HTH.
You can use static variables - these are variables which are linked to a class, rather than an instance of it.
Suppose your document class was called Document.as, and you wanted a variable, playerLives, to be visible from any part of the program.
Declare it inside Document.as:
public static var playerLives:int = 3;
You can then reference this directly from anywhere else in your code with:
Document.playerLives
(note that the variable is a member of the class itself, not an instance of it).
You could use a dedicated Statics class to hold these variables if you want to keep your document neat, or attach them to the relevant classes (eg Player.lives)
I've not used timeline/frames for some years but I believe this is how I used to do it!
NB Statics will be fine for your purposes but they are, in some ways, an equivalent to the _global variable in AS2 (at least, they can be used in the same manner) - many would not approve of their use, or over-use, as they are freely accessible from anywhere in your program (thus anathema to the OO concept of encapsulation), but personally I try not to worry about it in small cases - the most important thing to know about the rules of any design pattern is when they can be broken!
They are also slightly slower to access than instance members, but you won't notice this unless you are constantly accessing/changing them (making things like player velocity, which will need to be referenced/changed every frame, static, is not a good idea).
Hope this helps.
You may find the simplest way to link everything with the document class is to move your four frames into a movieclip together and have that on the first frame, then interact with that movieclip.
E.g. in the document class, where the movieclip instance on the timeline is called 'game'.
game.gotoAndStop(4);
game.objectToDisplay.visible = true;
If you encounter reference errors in the IDE then you can avoid these by using [] notation to refer to the properties of game, e.g. game["objectToDisplay"].visible = true;
Note that it's not really best practice to do this, but it will at least help you to finish that first game which is really more important at this stage in your learning. Afterwards, if you want to learn more then I'd recommend "The Essential Guide to Flash Games" by Jeff Fulton from 8bitrocket.com - it will teach you how to use the document class effectively.
I have a menu with five buttons. Menu is visible all the time. there is click event for each menu item. which slides corresponding movie clip from left to right. each movie clip has different nature events and respective animation and activity. for example tab 1 brings the video page. and within that movie clip I have video events like play pause volume and on complete etc. events and code. tab 2 has button group for Time and another button group Features. depending on user selection code will calculate and show value on a animated counter. tab 3 has button group for Time and button group Source. as per the user selection it will calculate and show the values as animated graph. and so on.
Right now I have all the individual tab movie clip has its own time line code for its own events. and some crossover variables and references with other tabs. Everything is working as expected. No problem. I know time line code is not the best way to do any complex project.
So, I would like to get the entire coding as one class or more classes if that is the correct way.
I am beginner as far as class logic. I have already created Main as document class and could control the general navigation of tabs and their initial look. But stuck at tab specific button events and other such unique events for the specific tab.
Any help is greatly appreciated. Thanks in advance.
any similar example or suggestions.
First of all, thanks a lot for a prompt response. It seems like I am not even a beginner. I need to read a lot and probalbly grasp all fundamental concepts thoroughly. I have gone through both the links suggested in your comments. I am trying to digest the stuff slowly. I do not have any formal informal education regarding OOP or any sort of programming. To be honest, I have hard time understanding the code you have suggeted. Not because of your code but because of my level of caliber. I will have to spend some time to make myself clearer regarding events and sequence etc. different tab contents are as movieclips to main timeline and already placed on stage. It comes and goes to its corresponding tab button click event. I am not marking your answer as yes because I still need to my own homework based on your suggestion. Thanks a lot once again. I am sure I will ask few more questions later.
This is how I would design it:
I'd have a Menu Class, which only contains the buttons and "converts" clicks on them into more specific events. That might look something like this:
public Class Menu extends Sprite {
protected var buttons:Vector. = new Vector.();
public function Menu() {
super();
var loops:int = numChildren;
for (var i:int=0; i<loops; i++) {
var button:SimpleButton = getChildAt(i) as SimpleButton;
if (button) {
buttons[buttons.length] = button;
button.addEventListener(MouseEvent.CLICK, broadcastMenuEvent);
}
}
}
public function broadcastMenuEvent(e:Event):void {
var button:DisplayObject = e.currentTarget as DisplayObject;
dispatchEvent(new Event(button.name, true));//bubbling, can catch at any level
}
}
The way this is built, you can change the events that are being dispatched simply by changing the name you give the instance of the button on stage. Note that you need to apply Menu as the Base Class and not the Class for this to work if you have "declare instances automatically" unchecked, because doing it that way allows the compiler to generate those instance names for you in a way your base Class doesn't have to know about.
At this point, you can then deal with those events in another place--whether it's your main document Class or whether you have a separate Controller.
I would define each of the Views you described as a separate Class as well. If you have objects coming and going on the stage, you can use one of the techniques described here to handle that. Otherwise, it's fairly straightforward to address your timeline instances from the base Class instead of timeline code. Again, you can listen for those events in the main document Class or a dedicated Controller--the main point is to make sure your Views are not making any important decisions and usually they should not be editing data.
You can choose to have your Main Document orchestrate how the tabs get added and removed (I'm a big fan of using the timeline with goToAndStop, but not everyone shares this preference), or, again, you can separate this logic out to a dedicated Controller. I would suggest that if it's possible to generalize how your Views work to have them implement a single Interface. That way, you can give them a single instance name and manage them all with the same getter/setter pair (assuming you go the timeline route).
Note the Flash compiler isn't terribly sophisticated in this regard, so if you do this and your Views extend different parent Classes, you'll get compiler warnings. Just ignore these--they don't mean anything.
The thing you shoud try to root out of your code completely is the part where Views are referencing each other. The only time it's acceptable for one View to know about another is when it's a parent knowing about its child. Even then, try to have as little specific knowledge as possible. Notice in the Menu View I wrote as an example, the parent only knows there may be some SimpleButtons, but it has no specific knowledge of where they are on stage, what, specifically, is in them, or even what there instance names are.
Instead of having your Views know about one another, have a third party (which, again, you can choose to use the main Document Class for or not) that transfers requests for state changes (in the form of events) from one to another.
There was many discussions about this problem, but I want to pay attention on the situations that IMHO seems not so clear:
Yes the general rules are:
Remove chachedAsBitmap
Stop movieClip if playing
Remove events
Delete references
etc.
But let's look:
First Example:
I have nested sprite (ex: mainSprite), it contains other sprites with dynamic textFields in it (and are chached as bitmaps), just textFileds and MovieClips with event listeners on it (with weak reference).
When I need to remove this sprite I need first to remove all it's nested content via loops or just
removeChild(mainSprite);
mainSprite=null;
is just enough?
Second Example:
I have some sprite in which I'm loading bitmap and manipulating with bitmapData, later I'm just replacing content of this sprite with another bitmap, is allocated memory for older bitmap automatically erases and is overwritten or it still exists?
Third example:
I have some "graphics template" MovieClip (in library with Export for Actionscript property set on it) which I'm adding on the stage and filling with dynamic data (and adding event listeners), let's say that it's one scene of the app, on another scene I need same MovieClip with other dynamic data, but inbetween need to clear my stage (need something like transition animation which is also library MovieClip), what's the best way: to set this MovieClip visible property to false (while transition animation is plays) and then reuse it, or just remove it with removeChild and then add when add with addChild once more?
All I wrote is more about Air Mobile, cause in most cases for the desktop these situations aren't so problematic, but in case of mobile development they are.
You can visually monitor memory usage along with fps etc using this lib: http://code.google.com/p/flash-console/
hope that helps.
P.S. gc in flash is always a weird thing :)
First example: removing mainSprite from display list is enough if there are only weak listeners on its children.
Second example: I'd advice reusing the same object with visible = false. Recreating the same object is more resource expensive plus you get another instance of the same thing being in memory before it gets gc'ed.
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