I posted yesterday about how to communicate to one class from another that I wanted to delete an instance of it, and I got the dispatcher working today. However, I think I’ve painted myself into a corner. Even though the dispatcher is working, I A:feel like it’s running through too many functions on the way to actually deleting the object, and B: still can’t manage to get it to actually delete. I don’t have any formal CS training, so it’s one of those situations where my mind is going in circles and I can’t “see” what I’m doing wrong. I figure if I post my classes here, at the very least people can have a chuckle at my amateur code, and if I’m lucky, some kind soul will point out what I’m doing wrong. So here goes:
Background.as:
//Background class. Singleton? Sets up/maintains the application.
package pc_mockup {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class Background extends flash.display.MovieClip {
private var slate:MovieClip;
private var slateBounds:Rectangle = new Rectangle(100,-260,0,280);
private var _toolbox:MovieClip;
private var _elementArray:Array = new Array();
public function Background() {
//attach movieclips to stage
slate = new mc_slate();
slate.x = 100;
slate.y = 20;
addChild(slate);
_toolbox = new Toolbox();
_toolbox.x = 750;
_toolbox.y = 20;
addChild(_toolbox);
//set draggables
//slate.addEventListener(MouseEvent.MOUSE_DOWN, dragSlate);
//slate.addEventListener(MouseEvent.MOUSE_UP, releaseSlate);
slate.addEventListener(MouseEvent.MOUSE_UP, dropNewElement);
}
private function dragSlate(event:MouseEvent) {
slate.startDrag(false, slateBounds);
}
private function releaseSlate(event:MouseEvent) {
slate.stopDrag();
}
private function dropNewElement(event:MouseEvent) {
var _elementType:String = _toolbox.currentTool;
var _x:Number = event.target.x;
var _y:Number = event.target.y;
var _newElement:MovieClip;
var _latestIndex:Number;
//case switch to choose element based on _elementType
//add new element to stage
_newElement = new PageElement(_elementType, event.localX, event.localY);
_latestIndex = _elementArray.push(_newElement);
_newElement.addEventListener("closeWindow", deleteElement);
slate.addChild(_newElement);
}
private function deleteElement(event:Event) {
trace("trying to remove element.");
slate.event.target.removeChild(_elementArray[0]);
}
}
}
Toolbox.as:
//Toolbox class.
package pc_mockup {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class Toolbox extends flash.display.MovieClip {
private var _toolboxback:MovieClip;
private var _tool01:MovieClip;
private var _tool02:MovieClip;
private var _tool03:MovieClip;
private var _tool04:MovieClip;
private var _tool05:MovieClip;
private var _currentTool:String = 'none';
public function Toolbox() {
_toolboxback = new ToolboxBack();
_toolboxback.x = 0;
_toolboxback.y = 0;
_toolboxback.alpha = .5;
addChild(_toolboxback);
_tool01 = new TextTool();
_tool01.x = 10;
_tool01.y = 10;
addChild(_tool01);
//_tool01.addEventListener(MouseEvent.MOUSE_DOWN, dragTool);
_tool01.addEventListener(MouseEvent.MOUSE_UP, switchTool);
_tool02 = new ImageTool();
_tool02.x = 10;
_tool02.y = 54;
addChild(_tool02);
_tool02.addEventListener(MouseEvent.MOUSE_UP, switchTool);
}
private function dragTool(event:MouseEvent) {
event.target.startDrag(false);
}
private function releaseTool(event:MouseEvent) {
event.target.stopDrag();
}
private function switchTool(event:MouseEvent) {
_currentTool = event.target.toolname;
//trace(_currentTool);
}
public function get currentTool():String{
return _currentTool;
}
}
}
Tool.as (any class with “Tool” at the end of it simply extends this class and adds a name)
//Tool class.
package pc_mockup {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class Tool extends flash.display.MovieClip {
private var _toolname:String;
public function Tool(toolname) {
_toolname = toolname;
}
public function get toolname():String{
return _toolname;
}
}
}
PageElement.as:
//Page element class.
package pc_mockup {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
public class PageElement extends flash.display.MovieClip {
private var _elementname:String;
private var _elementback:MovieClip;
private var _elementmenu:MovieClip;
private var _title:TextField;
private var _formatter:TextFormat = new TextFormat();
public function PageElement(elementname, x, y) {
_elementname = elementname;
_elementback = new ElementBack();
_elementback.x = x;
_elementback.y = y;
_elementback.alpha = .5;
_elementback.addEventListener(MouseEvent.MOUSE_DOWN, dontBubble);
_elementback.addEventListener(MouseEvent.MOUSE_UP, dontBubble);
_elementmenu = new ElementMenu();
_elementmenu.x = x + _elementback.width - 5;
_elementmenu.y = y - 5;
_elementmenu.addEventListener(MouseEvent.MOUSE_OVER, showElementMenu);
_elementmenu.addEventListener(MouseEvent.MOUSE_OUT, retractElementMenu);
_elementmenu.addEventListener(MouseEvent.MOUSE_DOWN, dragElement);
_elementmenu.addEventListener(MouseEvent.MOUSE_UP, releaseElement);
_formatter.font = "Helvetica";
_formatter.size = 10;
_title = new TextField();
_title.text = elementname;
_title.x = x;
_title.y = y;
_title.textColor = 0xffffff;
_title.setTextFormat(_formatter);
addChild(_title);
addChild(_elementback);
addChild(_elementmenu);
}
public function get elementname():String{
return _elementname;
}
public function set elementTitle(newTitle) {
}
public function showElementMenu(event:MouseEvent) {
_elementmenu.expandMenu();
}
public function retractElementMenu(event:MouseEvent) {
_elementmenu.retractMenu();
}
public function hideElementMenu() {
_elementmenu.alpha = 0;
}
private function dragElement(event:MouseEvent) {
event.target.parent.parent.startDrag(false);
event.stopPropagation();
}
private function releaseElement(event:MouseEvent) {
event.target.parent.parent.stopDrag();
event.stopPropagation();
}
private function dontBubble(event:MouseEvent) {
event.stopPropagation();
}
}
}
DeleteBack.as:
//Element menu back class.
package pc_mockup {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class DeleteBack extends flash.display.MovieClip {
public function DeleteBack() {
}
public function closeElement(event:MouseEvent) {
dispatchEvent(new Event("closeWindow", true));
trace("event dispatched.");
}
}
}
ElementMenu.as:
//Element menu class.
package pc_mockup {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import caurina.transitions.Tweener;
public class ElementMenu extends flash.display.MovieClip {
private var _elementmenuback:MovieClip;
private var _deletebutton:MovieClip;
public function ElementMenu() {
_elementmenuback = new ElementMenuBack();
_elementmenuback.x = 0;
_elementmenuback.y = 0;
_elementmenuback.width = 100;
_elementmenuback.height = 5;
_elementmenuback.alpha = .5;
addChild(_elementmenuback);
_deletebutton = new DeleteBack();
_deletebutton.x = -5;
_deletebutton.y = 10;
_deletebutton.width = 10;
_deletebutton.height = 10;
_deletebutton.alpha = .2;
_deletebutton.visible = false;
addChild(_deletebutton);
_deletebutton.addEventListener(MouseEvent.MOUSE_DOWN, closeElement);
}
public function expandMenu() {
Tweener.addTween(_elementmenuback, {height:30, time:.2, transition:"easeOutBack"});
_deletebutton.visible = true;
}
public function retractMenu() {
Tweener.addTween(_elementmenuback, {height:5, time:.1, transition:"easeInBack"});
_deletebutton.visible = false;
}
public function closeElement(event:MouseEvent) {
//check that the user really wants to close the element before sending the destroy signal
//perform any closing animations
//this.parent.destroy();
_deletebutton.closeElement(event);
}
}
}
That’s it for the meaningful classes. Anything else is either an empty class that’s only in there to help make the library object accessible to ActionScript, or a trivial extension of something else.
The code puts a new element onto the stage, gives it a cool little dropdown menu that makes it draggable and has a delete button on it, and should link that button to a function that closes the element.
I’ve got everything but the closing.
General code criticism also very welcome. Like I said, I have no training, I’ve been figuring this stuff out for myself, and feedback of any kind from people who know what they’re doing is valuable.
Thanks!
SS
PS. In response to Daniel’s comment, here are the steps the code takes:
- The Background class puts everything on the stage and creates the toolbox.
- The toolbox creates the tools, which are like Photoshop’s tools. You click on them to select an element you want to add to the stage, then you click inside the “slate” to drop a new instance of that object on top of it. The background creates the instance and saves it in an array of all instances created at runtime.
- The new element makes its own dropdown menu, which is the draggable portion of the element and holds the delete button. This menu places an eventListener on the delete button.
- When the delete button is clicked, the eventListener placed on it by its parent class calls an event dispatcher inside the delete button class itself.
- This dispatched event is caught by the background class (I figured the best class to remove the element is the same class that made it, right?) and triggers the actual code to remove the element.
- This code, “deleteElement,” is where I’m stuck. I have all the instances in an array, but the event has gone through so many intermediary classes, the MouseEvent, and thus, I suspect, the MouseEvent target, has fallen by the wayside. So the only way to know which element to delete is to find its array index. I have no idea how this would work. Any ideas?
let’s do this a bit at a time…
slate.event.target.removeChild(_elementArray[0]);in background.aswhy are you using
slate.event?you are passing an
eventobject to the function, but looks like you’re using a different event’s target, which I don’t know where it’s coming from or why it’s not giving you an error.it should just be
event.target, which should give you the PageElement(formerly known as _newElement)what I don’t know also is why you are removing a child from it which is _elementArra[0] – which really is another PageElement and likely itself if you only have one.
so it looks to me that there are a bunch of things that should have thrown errors. What are you using to compile your code? What about debugger? are you using any?
If you look at your previous question, I added some code there about how to get the parent. So I adjusted it a bit
however the problem is that you’re not passing a MouseEvent but a blank event
dispatchEvent(new Event("closeWindow", true));in DeleteBack.asso this will not pass anything under target, and you can’t get it. (target is read only, so
new Event(etc)will always have a null target. So essentially that’s a bit of a lost cause.you could set an onject in your singleton and pass which mc is to be deleted, and then the deleteElement would just grab that object. The other option is to look into the signals class which will let you do some better/more efficient event handling.
finally (sort of, there’s more but for now) I’d say look into using CASAlib, in particular, use CasaMovieClip instead of MovieClip for extending, as it will delete your movie clips better. If you have a lot of event listeners and you don’t clear them properly, they’ll end up staying in memory even after you delete them.
of course looking into other frameworks like RobotLegs is a good idea too, it gets you into better practices.
GL
Edit …
frameworks/micro-architectures:
http://www.robotlegs.org/
http://swizframework.org/
http://puremvc.org/
and many more
I think the important thing is to not get stuck on a framework (though I mention the word often). And the best framework is the framework that is best for you, and to me that means offering a good communication backbone for the app and staying out of the way.
My setup for writing code is this:
FlashDevelop with the Flex Compiler. FlashDevelop is for PC only so if you’re on Mac you might want to consider other options like flex. FlashDevelop and the Flex compiler(the compiler only) are both free so you can’t go wrong, and once you start using it you won’t want to go back to coding in Flash – guaranteed!!
debugging:
Trace is the simplest form of debugging, and it can be quite difficult to understand the problem.
You can use the flash debugger by pressing
Ctrl-Shift-Enterto compile and run. You will need to set the break points ahead though.FlashDevelop has a debugger that works just like the Flash and Flex debuggers and I use it quite often.
But my favorite debug tool has to be de monster debugger
it takes a bit to more to implement, and you need to add some code, but it found issues for me that I couldn’t get to using the default debugger only. Definitely worth a look.