I then have a LoadURL class to take the appropriate array data (represented by the string imgURL) and load the image.
package com.carmstrong.portfolio{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
import flash.display.Loader;
public class LoadURL extends Sprite {
// --------------------------------------------------
// Private members
// --------------------------------------------------
// --------------------------------------------------
// Constructor
// --------------------------------------------------
public function LoadURL(imgURL:String) {
super();
var req:URLRequest = new URLRequest(imgURL);
var ldr:Loader = new Loader();
ldr.load(req);
var img:DisplayObject = ldr;
addChild(img);
}
// --------------------------------------------------
// Init / uninit
// --------------------------------------------------
// --------------------------------------------------
// Private methods
// --------------------------------------------------
// --------------------------------------------------
// Event handlers
// --------------------------------------------------
}
}
I've just put this one together, and I'm guessing Iv structured it badly, since all the script is within the constructor?
fatbuoy1- 04-10-2008
Then I have the Photo class, which basically creates the frame, sticks the Image on top of it, and gives it a shadow and drag and drop functionality. This script is basically a (badly) adapted version of what you gave me to start with.
package com.carmstrong.portfolio{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import fl.transitions.Tween;
import fl.transitions.easing.*;
import flash.filters.DropShadowFilter;
import com.carmstrong.portfolio.LoadURL;
public class Photo extends Sprite {
public static var PHOTO_WIDTH:int=600;
public static var PHOTO_HEIGHT:int=400;
private static const _scaleUp:Number = 1.1;
private static const _scaleDown:Number = 1;
// --------------------------------------------------
// Private members
// --------------------------------------------------
// --------------------------------------------------
// Constructor
// --------------------------------------------------
public function Photo(imgURL:String):void {
super();
var img:LoadURL = new LoadURL(imgURL);
addChild(img);
drawFrame();
drawShadow();
addEventListener(Event.ADDED_TO_STAGE,this.onInit);
addEventListener(Event.REMOVED_FROM_STAGE,this.onUninit);
}
// --------------------------------------------------
// Init / uninit
// --------------------------------------------------
protected function init():void {
addEventListener(MouseEvent.MOUSE_DOWN,this.onDrag);
}
protected function uninit():void {
removeEventListener(MouseEvent.MOUSE_DOWN,this.onDrag);
removeEventListener(Event.ADDED_TO_STAGE,this.onInit);
removeEventListener(Event.REMOVED_FROM_STAGE,this.onUninit);
}
// --------------------------------------------------
// Private methods
// --------------------------------------------------
private function drawFrame():void {
graphics.lineStyle(30, 0XFFFFFF, 1,true,"normal",null,"round");
graphics.beginFill(0XFFFFFF,1);
graphics.drawRect(-this.img.width/ 2,-this.img.height/ 2,this.img.width,this.img.height);
graphics.endFill();
}
private function drawShadow():void {
var _photoShadow:DropShadowFilter = new DropShadowFilter();
_photoShadow.distance = 2;
_photoShadow.blurX = _photoShadow.blurY = 5;
filters = [_photoShadow];
}
private function photoDrag():void {
startDrag(false);
stage.addEventListener(MouseEvent.MOUSE_UP,this.onDrop);
var liftPhotoX:Tween = new Tween(this, "scaleX", None.easeIn, _scaleDown, _scaleUp, 0.1, true);
var liftPhotoY:Tween = new Tween(this, "scaleY", None.easeIn, _scaleDown, _scaleUp, 0.1, true);
//Bring to front
//var frontIndex:int = (stage.numChildren)-1;
//stage.setChildIndex(this,frontIndex);
}
private function photoDrop():void {
stage.removeEventListener(MouseEvent.MOUSE_UP,this.onDrop);
var dropPhotoX:Tween = new Tween(this, "scaleX", None.easeIn, _scaleUp, _scaleDown, 0.2, true);
var dropPhotoY:Tween = new Tween(this, "scaleY", None.easeIn, _scaleUp, _scaleDown, 0.2, true);
stopDrag();
}
// --------------------------------------------------
// Event handlers
// --------------------------------------------------
private function onDrag(evt:Event):void {
photoDrag();
}
private function onDrop(evt:Event):void {
photoDrop();
}
private function onInit(evt:Event):void {
init();
}
private function onUninit(evt:Event):void {
uninit();
}
}
}
If you look at the constructor on this one, I've added the Image first, and then tried to draw the frame. I'm trying to get the frame to look first at the size of the Image child, then basically add a 20px border on to it... However my attempts so far (in the drawFrame() function) havnt worked.
fatbuoy1- 04-10-2008
Finally, in the main timeline, I have the following code... import com.carmstrong.portfolio.LoadXML;
import com.carmstrong.portfolio.Photo;
import com.carmstrong.portfolio.LoadURL;
var getXML:LoadXML = new LoadXML("portfolio.xml");
getXML.addEventListener(Event.COMPLETE, onXMLLoaded);
function onXMLLoaded(evt:Event) {
removeEventListener(Event.COMPLETE, onXMLLoaded);
var photo:Photo = new Photo(getXML.portfolioData[0].slides[0].url);
addChild(photo);
}
This all works surprisingly well, except for the fact that
a) there's no borders on the images (see above post)
b) There's FOUR photo instances being created... for no reason I can see!
Im guessing you probably didnt mean for me to just lash the whole shebang up here... but anyways :D Im sure you won't read through all of that (although with your speed-code-reading skills who knows!), but Im hoping you'll be able to see any glaring mistakes at a glance :D
bigmac- 04-10-2008
Okay... I just skimmed quickly, but I'd say your problems are these:
1) Your LoadURL class is a little redundant... and generically named. A URL can be anything: data, image, a SWF, a data service, so make your class name reflect WHAT is being loaded. "ImageLoader" would be much more appropriate. Also, the class is a sprite which creates a loader and just adds it to it's display, which is pointless when you can just extend Loader directly and cut out the Sprite middleman. Here, your LoadURL class can be reduced to this:
package com.carmstrong.portfolio
{
import flash.net.URLRequest;
import flash.display.Loader;
public class ImageLoader extends Loader
{
public function ImageLoader(imgURL:String):Void
{
super();
var req:URLRequest = new URLRequest(imgURL);
load(req);
}
}
}
2) The reason the frame isn't drawing to the size of your image is because you're not waiting for the image to load before drawing the frame. add an Event.COMPETE listener to the ImageLoader class, and draw the frame on result.
3) Let me guess, you have four XML data nodes to match the four Photos that are bring created, right? You're getting four Photos is because you've put the LoadXML's COMPLETE event dispatch within the parsing loop. So, each time the loop runs, it's dispatching a COMPLETE event which creates a Photo.
fatbuoy1- 04-10-2008
Thanks, you were right on all 3 accounts (surprise surprise)! :D However, im still having trouble with point 2.
I've changed the Photo class' constructor to
// --------------------------------------------------
// Private members
// --------------------------------------------------
private var _imgURL:String;
// --------------------------------------------------
// Constructor
// --------------------------------------------------
public function Photo(imgURL:String):void {
super();
_imgURL = imgURL;
var img:ImageLoader = new ImageLoader(_imgURL);
img.addEventListener(Event.COMPLETE, onImageLoaded);
addEventListener(Event.ADDED_TO_STAGE,this.onInit);
addEventListener(Event.REMOVED_FROM_STAGE,this.onUninit);
}
So, when 'img' has finished loading, it calls the onImageLoaded function, which is
// --------------------------------------------------
// Event handlers
// --------------------------------------------------
private function onImageLoaded(evt:Event) {
drawImage();
drawFrame();
drawShadow();
img.removeEventListener(Event.COMPLETE, onImageLoaded)
}
The drawImage(); function is the one that actually creates the image instance.
// --------------------------------------------------
// Private methods
// --------------------------------------------------
private function drawImage():void {
img.x = -img.width/2;
img.y = -img.height/2;
addChild(img);
}
Now, my problem is that, as it stands, neither onImageLoaded() or drawImage() can see the img variable, because it only exists within the scope of the constructor function. However, if I make it one of the 'private members', it can't read the imgURL string that is part of the constructor... dont know if that makes any sense at all... if it does, any ideas?
bigmac- 04-10-2008
Yeah, you were right that the img object does not exist outside of the constructor. The fact that the imgURL string won't reference unless it's a property sounds pretty suspicious though. Do this to your constructor:
// --------------------------------------------------
// Private members
// --------------------------------------------------
private var _img:ImageLoader;
// --------------------------------------------------
// Constructor
// --------------------------------------------------
public function Photo(imgPath:String):void {
super();
_img = new ImageLoader(imgPath);
_img.addEventListener(Event.COMPLETE, onImageLoaded);
addEventListener(Event.ADDED_TO_STAGE,this.onInit);
addEventListener(Event.REMOVED_FROM_STAGE,this.onUninit);
}
One thing that might have thrown you off is if you declared the variable as a member of the class, then set it within the custructor preceded by second "var" reference. That doesn't work... you can only declare a variable (with "var") once per scope; otherwise the compiler throws a namespace error when it encounters the same declaration twice.
fatbuoy1- 04-10-2008
Ok thanks, theres no errors now, but it doesnt actually load the image anymore. I put a trace within the onImageLoaded function, which isnt being displayed so
_img.addEventListener(Event.COMPLETE, onImageLoaded);
mustnt be actually calling the function for some reason.
bigmac- 04-11-2008
weird... I dunno why your complete trace wouldn't work, but I can see one reason why your image wouldn't appear: in my revised class I forgot to include an addChild(_img); command.
fatbuoy1- 04-13-2008
Hmm... im just gonna ignore that bit for the moment, I can come back and add dynamic sizing at a later stage. At the moment all the pics are the same size anyway.
Heres a question, whats the best way of making sure flash knows what buttons link to what projects, and which captions link to which images? The way I have been doing it is by giving each button or image an 'objectIndex'... so if I have 3 projects in an array, and Im creating buttons for them, I use a 'for' loop and a projectIndex variable to go through the array and create buttons for each project. As each button is being created, it contains an objectIndex variable, which is made to equal the projectIndex value at the time of the button's creation. So button 1 had a projectIndex of 0, and so will have an objectIndex of 0 too... when I click on button 1, the project index is made to equal that button's objectIndex and load the correct project.
Now.. I dunno if any of that is understandable... it all makes sense to me :D But im guessing theres a far clearer and efficient method of doing this sort of thing?
fatbuoy1- 04-13-2008
Also, im having trouble getting a slide to come to the top when clicked on (picked up). Heres the script I have in the Photo class
private function photoDrag():void {
startDrag(false);
stage.addEventListener(MouseEvent.MOUSE_UP,this.onDrop);
var liftPhotoX:Tween = new Tween(this, "scaleX", None.easeIn, _scaleDown, _scaleUp, 0.1, true);
var liftPhotoY:Tween = new Tween(this, "scaleY", None.easeIn, _scaleDown, _scaleUp, 0.1, true);
//Bring to front
var frontIndex:int = (stage.numChildren)-1;
stage.setChildIndex(this,frontIndex);
and heres the error message I get when I pick up a slide...
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/setChildIndex()
at flash.display::Stage/setChildIndex()
at com.carmstrong.portfolio::Photo/photoDrag()
at com.carmstrong.portfolio::Photo/onDrag()
changing 'stage.setChildIndex(this,frontIndex)' to 'stage.setChildIndex(this.root,frontIndex)' takes away the error message, but doesnt actually do anything either...
bigmac- 04-13-2008
First off... concerning the indexing thing. The way you are doing it is not too bad, but the bottom line is to do what works at your comfort level. Just making it work is awesome for your first project, and you'll discover ways to improve upon in the in future.
The way I'd probably do the index thing would be to set up a simple implementation of a common OOP design pattern known as "Model View Control" or "MVC". MVC patterns isolate a program into three segments: the data (model), the display interface (view), and the control mechanisms that bridge the two. So, I'd create controller object who's job is to read from the data model and create a nav button for each data element. As it creates the buttons, it assigns each button an index value (0, 1, 2). That's all the information that the buttons know about themselves... they're pretty stupid; which is okay. The only script "View" objects need is stuff that governs their appearance (rollover behaviors, display rendering, etc). The controller directly listens for their mouse clicks, at which time it reads the index off the clicked button and handles setting that slideshow display.
In summary: it's best to have the object that assigns index values handle the processing of user input concerning that index. To give a button an index and then let it think for its self as to what to DO with that index creates the evil "D" word: Dependency. The button is dependant on on another object to configure it. With the MVC idea, the buttons don't know or need to know a thing about what their index means or what to do with it. They just need to store the index to feed it back into their controller. Make sense?
And finally, the stage/child issue. I seem to remember we've run into this before, so let me be helpfully succinct: YOU CANNOT ADD OR REMOVE OBJECTS DIRECTLY TO STAGE. :D So, "stage" references the root "Stage" class object that is running the Flash movie. Stage is a special display object that has (and can ONLY have) one child, which is the document class (ie: root timeline of the document). So, don't think of the stage as anything that you can mess with the display of. I find that the "stage" object is really only useful for two things:
A) Reading properties from, like "stage.stageWidth"
B) Subscribing listeners to, given that stage is at the absolute top of the Flash Player DOM so will receive ALL events that transpire within the flash movie.
Anyway, you get a #2025 when you try to run a child-targeting method on an object that is not directly contained by the parent... ie: you're trying to mess with someone else's kid. I find that the safest way to perform these types of operations is to run everything through a referent to the target child's parent, as in:
// your example:
parent.setChildIndex(parent.numChildren-1);
// another common scenario:
targetChild.parent.removeChild(targetChild);
fatbuoy1- 04-13-2008
Ok thanks, like you say I'll just try and get it working to begin with and then start looking at how to do it better. I see your point about dependency though.
And thanks for your succinctness! :D Its all clear now :)
you're trying to mess someone else's kidYou make it sound so... illegal! :D
bigmac- 04-14-2008
Okay, correction to my last post... I checked Stage class documentation this morning given that, the more I thought about it, the more it seemed strange that you couldn't add children to stage given that it's a DisplayObjectContainer. So, I stand corrected: while the stage has several limitations which separate it from other display object types, support for child nodes is not one of them. Commands like "stage.addChild()" and "stage.removeChild()" are valid, however they must still only target children of the stage object its self. As a rule of good form, I wouldn't rely on using the stage to display anything unless it specifically needed to always display on top... like a modal dialogue window or a pulldown selector's menu.
fatbuoy1- 04-14-2008
Ok thanks :)
Im working on my CreateButtons() class, which looks through the XML array, gets the titles of the projects and creates buttons for each of them. Heres what I have so far...
package com.carmstrong.portfolio{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.AntiAliasType;
import com.carmstrong.portfolio.LoadXML;
import com.carmstrong.portfolio.Section;
public class CreateButtons extends Sprite {
// --------------------------------------------------
// Private members
// --------------------------------------------------
private var _i:Number = 0;
private var _menuButton:TextField = new TextField();
private var _menuFormat:TextFormat = new TextFormat();
private var _highlightFormat:TextFormat = new TextFormat();
private var _objectIndex:Number;
private var _section:Section;
private var _getXML:LoadXML = new LoadXML("portfolio.xml");
// --------------------------------------------------
// Constructor
// --------------------------------------------------
public function CreateButtons():void {
_getXML.addEventListener(Event.COMPLETE, onXMLLoaded);
}
// --------------------------------------------------
// Private methods
// --------------------------------------------------
private function createButton() {
_objectIndex = _i;
trace(_getXML.portfolioData[_i].title);
_menuButton.text = _getXML.portfolioData[_i].title;
_menuButton.embedFonts;
_menuButton.antiAliasType = AntiAliasType.ADVANCED;
_menuButton.selectable = false;
_menuButton.width = 100;
_menuButton.height = _menuButton.textHeight + 5;
_menuButton.wordWrap = true;
_menuButton.x = -(_menuButton.width/2);
_menuButton.y = 0+(_i+1)*_menuButton.height +10;// 0 sets distance from top
_menuFormat.align = "left";
_menuFormat.color = 0xffffff;
_menuFormat.font = "Tw Cen MT";
_menuFormat.size = 14;
_menuFormat.underline = false;
_highlightFormat.align = "left";
_highlightFormat.color = 0xffffff;
_highlightFormat.font = "Tw Cen MT";
_highlightFormat.size = 14;
_highlightFormat.underline = true;
_menuButton.setTextFormat(_menuFormat);
addChild(_menuButton);
_menuButton.addEventListener(MouseEvent.ROLL_OVER, menuOver);
_menuButton.addEventListener(MouseEvent.ROLL_OUT, menuOut);
_menuButton.addEventListener(MouseEvent.CLICK, selectSection);
}
// --------------------------------------------------
// Event handlers
// --------------------------------------------------
private function onXMLLoaded(evt:Event) {
_getXML.removeEventListener(Event.COMPLETE, onXMLLoaded);
for (_i = 0; _i<_getXML.portfolioData.length; _i++) {
createButton();
}
}
private function menuOver(evt:MouseEvent):void {
_menuButton.setTextFormat(_highlightFormat);
}
private function menuOut(evt:MouseEvent):void {
_menuButton.setTextFormat(_menuFormat);
}
private function selectSection(evt:MouseEvent):void {
_section = new Section(_objectIndex);
addChild(_section);
}
}
}
Now, the 'trace(_getXML.portfolioData<_i>.title)' successfully returns the list of project titles. However only the LAST one is actually displayed.. and it doesnt have any of the font or colour formating iv given it. Can you spot any glaring errors?
Oh and also, in the main timeline, the actual instance of 'CreateButtons' is added as a child to the menu_mc, which is placed on the main stage. This means addChild(_menuButton) adds each button as a child of menu_mc... however it also means addChild(_section) adds a section of photographs as a child of menu_mc, instead of being placed on the main stage, beneath the menu. I've tried stage.addChild(_section) and parent.parent.addChild(_section), but both cause a severe slowdown for some reason.
fatbuoy1- 04-14-2008
Got the text formatting working (i'd forgotten to apply it to _menuButton), although the Anti Aliasing doesn't seem to be working at all.
Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.