dcsimg
A Flash Developer Resource Site

Results 1 to 15 of 15

Thread: Ugg...dynamic drop-down menu from arrays

  1. #1
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930

    Ugg...dynamic drop-down menu from arrays

    I've got 3 arrays (Chapter, Lesson, Page) that I'm trying to build dynamically as an expanding drop-down menu in as3 and I've hit a wall...early on...

    After looking around for an as3 duplicateMovieClip solution, I settled on senocular's duplicateDisplayObject to create the initial Chapter buttons (which, when clicked, will expand to display the Lesson button, and so on for the Page buttons).

    I've got the buttons duplicating, but don't know how to set references up for the buttons, update text within the buttons, call them from other functions to move them, etc...this may not even be the right solution for what I need, but nothing seems straight-forward anymore in as3...

    Here's what I've got so far:

    Code:
    function duplicateClickHandler() {
    	for (var i in chpArray) {
    		var newInstance:DisplayObject=duplicateDisplayObject(mainMenu_mc.menuBtn_mc,true);
    		newInstance.y+=(20*i);
    		newInstance.i+=i;
    		newInstance.title_txt.htmlText=String(chpArray[i]);		
    	}
    }
    The last 2 lines return undefined property errors...

    Using as3 (obviously) and CS4

    Thanks!!
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    First, I don't know why you think you have to duplicate an existing display object. You should create a MenuItem class and create new instances of that.

    But, if you want to continue on your way you will need to cast your new instance to the appropriate class, assuming it is an instance of the right class. I don't know what Senocular's duplicate stuff produces.

    This should work:
    Code:
    function duplicateClickHandler() {
    	for (var i in chpArray) {
    		var newInstance:MovieClip=MovieClip(duplicateDisplayObject(mainMenu_mc.menuBtn_mc,true));
    		newInstance.y+=(20*i);
    		newInstance.i+=i;
    		newInstance.title_txt.htmlText=String(chpArray[i]);		
    	}
    }
    But really, make a class.

    Edit: Also, you should put the new instance on the display list somewhere with addChild.

  3. #3
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930


    You're right, you're right, but I've been able to get along so well just using AS3 without really breaking into the classes & packages...lol...

    Alright...here's where I am, and it's all going well so far...I think...

    In my fla, I have a clip (mainMenu_mc) on the stage. Inside that is a container (menuContainer_mc) that will scroll the menu items. In the library, I have a menuItem movieClip set to Export to AS.

    I set my document class in my fla to MainClass...in the root is a MainClass.as:

    Code:
    package {
    
    	import flash.display.MovieClip;
    	import MenuItem;
    
    	public class MainClass extends MovieClip {
    		var chpArray:Array=new Array("chapter1","chapter2","ch3");
    
    		public function MainClass() {
    			InitMenu();
    		}
    		public function InitMenu() {
    			for (var i in chpArray) {
    				var newInstance:MenuItem=new MenuItem  ;
    			}
    		}
    	}
    	
    
    }
    and I have another class, MenuItem.as:

    Code:
    package {
    	import flash.display.MovieClip;
    	public class MenuItem extends MovieClip {
    		trace('itemCreated ');		
    	}
    
    }
    Now, I would expect "itemCreated" to trace 3 times, but it only traces once...and, to add the actual clip to the menuContainer_mc, how do I reference that? Something like:

    Code:
    addChild(mainMenu_mc.menuContainer_mc.menuItem)
    ??

    And, do I create a unique property for each menu item to be able to reference them later?

    I feel some light spilling over me, but maybe that's just a flashback...

    Thanks for any insight...
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    You're pretty close. You've set up your class correctly, though it doesn't do much yet.

    Your trace runs in the static class rather than in the constructor for an instance of that class. That's why you only see it once.

    Use "for each" rather than "for in" for arrays.
    Code:
    		public function InitMenu() {
    			for each (var i in chpArray) {
    				var newInstance:MenuItem=new MenuItem();
                                    //set newInstance's properties such as x,y
                                    mainMenu_mc.menuContainer_mc.addChild(newInstance);
    			}
    		}
    Since you've created a new class for MenuItem, you can create new methods on it which help you out. Like a method which takes a string and creates a textfield with appropriate content in it.

    Code:
    package {
    	import flash.display.MovieClip;
            import flash.text.TextField;
    
    	public class MenuItem extends MovieClip {
    
                public var tf:TextField;
    
                public function MenuItem(label:String = null){
    		trace('itemCreated ');	
                    tf = new TextField();
                    addChild(tf);
                    if (label != null)[
                       setLabel(label);
                    }
                }	
    
                public function setLabel(label:String):void{
                  tf.text = label;
                }
    	}
    
    }
    And now your set up code could look like this:

    Code:
    		public function InitMenu() {
    			for each (var i:String in chpArray) {
    				var newInstance:MenuItem=new MenuItem(i);
                                    //set newInstance's properties such as x,y
                                    mainMenu_mc.menuContainer_mc.addChild(newInstance);
    			}
    		}

  5. #5
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930
    cool...cool...so you pass the string and use it for the label...more to wrap my mind around...I already have a text field on the stage (title_txt) in the menuItem clip, so I suppose I could just add the text in that, or does it make more sense to do it programmaticly?

    Code:
    title_txt.htmlText = label; //would this be in the MenuItem class?
    Finally, how do I reference the particular button from within another function. For example, I'm thinking, that to create the expanding/contracting list of Lessons and Pages, that, when the user clicks a chapter button, I'll get the number of Lessons, use TweenMax to slide the following chapter buttons down as far as I need to and then use addChild to create the Lesson buttons...and so forth for the pages. It's going to get trickier because some of the lesson titles are going to be multiple lines that will need to wrap and create larger buttons, but I'm going to cross that chasm when I get to it...

    Thanks for you direction on this! I'm working through Keith Peters "AS3.0 Animation" and have Moock's "Essential AS3", but I obviously need to spend more time with them and making practical examples...
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

  6. #6
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    To use the title_txt you should be able to just replace "tf" in the class I had with "title_txt", and remove the new TextField() part. I'm honestly not sure, as I never use the IDE.

    To reference the MenuItems that you create later, you will have to keep a reference to them. Usually for something like this, I'll put them in an Array if I want to process them all generically. If you want to process them in specific ways, you could set the names and use getChildByName, or put them in a Dictionary with an identifier. Or you could forgo the loop and just instantiate each independently and keep them in variables.

  7. #7
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930
    Excellent! Thanks for all the help!
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

  8. #8
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930
    Alright...I've got my menu loading, all the labels coming in, I've got listeners on, but I'm not sure how to reference the item being clicked? I can use currentTarget.name, but that just gives me an instance name. I'd like to be able to get the label (array text) for that item, but don't know if there's a way to assign an object parameter in as3...I'm sure there is...

    Also, how do I reference the clip itself (like in the rollOver/Out)?

    Here's the code:
    Code:
    public function InitMenu() {
    			for each (var i in chpArray) {
    				var newInstance:MenuItem=new MenuItem(i);
    				//set newInstance's properties such as x,y
    				newInstance.addEventListener(MouseEvent.CLICK, menuClick,false,0,true);
    				newInstance.addEventListener(MouseEvent.ROLL_OVER, menuOver,false,0,true);
    				newInstance.addEventListener(MouseEvent.ROLL_OUT, menuOut,false,0,true);
    			        mainMenu_mc.menuContainer_mc.addChild(newInstance);
    				trace("added "+i);//this is what I would like to trace
    			}
    		}
    		public function menuClick(mevt:MouseEvent) {
    			trace("click "+mevt.currentTarget.name);//returns instanceX, but I want it to return the i value above
    		}
    		public function menuOver(mevt:MouseEvent) {
    			mainMenu_mc.menuContainer_mc[mevt.currentTarget].gotoAndStop(2);//I also tried this[mevt.currentTarget].gotoAndStop(2);
    		}
    		public function menuOut(mevt:MouseEvent) {
    			mainMenu_mc.menuContainer_mc[mevt.currentTarget].gotoAndStop(1);
    		}
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

  9. #9
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Add a getLabel method like setLabel in MenuItem so that you can get the text back out of a MenuItem instance.

    You can cast currentTarget to MenuItem, and then call getLabel.
    Code:
    public function menuClick(mevt:MouseEvent) {
      var menuItem:MenuItem = MenuItem(mevt.currentTarget);
      trace("click "+menuItem.getLabel());
    }

  10. #10
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930
    SWEET! Got it...thanks!
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

  11. #11
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930
    What about the rollover event? I would have thought that:

    Code:
    this[mevt.currentTarget.name].gotoAndStop(2);
    would do it?

    Thanks!
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

  12. #12
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    No, the MenuItem probably has a generated name like "instance12". Even if it had a name, don't confuse names with properties. The bracket syntax gets a property by string.

    Instead, use the same cast technique to get the target typed as MenuItem (which I assume is a subclass of MovieClip).

    Code:
    public function menuOver(mevt:MouseEvent) {
      mainMenu_mc.menuContainer_mc[mevt.currentTarget].gotoAndStop(2);//I also tried this[mevt.currentTarget].gotoAndStop(2);
      var menuItem:MenuItem = MenuItem(mevt.currentTarget);
      menuItem.gotoAndStop(2);
    }

  13. #13
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930
    very cool...first time casting...read through Moock and will also check some other online tutorials...good stuff!

    Thanks!

    What about a situation where I have a property (numLines), that I need to check within one class/function (MainClass > InitMenu - because this is where it sets the y of newInstance), but that property is only accessible (as far as I can tell) from another class/function (MenuItem > setLabel - since this is where all the text elements are defined)?

    I tried declaring a variable in the MainClass script (since it imports MenuItem) and then setting that variable from within MenuItem, but that's not working...
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

  14. #14
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    In this particular case, you can probably just use the last MenuItem's y and height values to place the next one, and never have to access the textfield directly.

    If you do need access to a particular property of one class from another, you would have to change that property's scope from 'private' to 'protected' (for access only from classes which inherit from that class) or 'public' (for access from any class).

    Or, you could create a function which returns the values you're interested in, like you did with getLabel.

  15. #15
    anyone else hear that? flashpipe1's Avatar
    Join Date
    Jan 2003
    Location
    Upstate NY
    Posts
    1,930
    Ah, yes, making the function worked...learning slowly, but it's taking shape nicely...thanks for all the help and direction...

    Always different modifying existing code or samples vs. creating everything from scratch...
    Love like you've never been hurt, live like there's no tomorrow and dance like nobody's watching.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center