Hok's Macromedia Flash Blog

macromedia flash actionscript scripting, php, remoting, webservices, c#, javascript

MovieClip-Extension: onDoubleClick

I think that is an old-one, but maybe there is
someone who need it.
It is an onDoubleClick-Handler for MovieClips.
The code is little spaghetti-like...;-) But for this
job it is OK.
I had some problems with side-effekts because
i wanted to use: onPress as helper for the new
event. The concrete Problem is that we can't
define the onPress-Handler after the onDoubleClick-
Handler.
What do you think, is there an way to get arround
this Problem?
view(code);
get(code);

Posted by hOk at May 26, 2003 01:43 PM

traceMessages: revised

If you want to know which method is called in which
order. And you also want to know who is the caller
of the current method. Than you normally have to
populate your Script with many traces.




I think we have know an good solution for this problem.
I have revised the traceMessages-method, and now
we can solve the problem really easy.
We simply include the traceMessages.as and put the
following line in our script:
#include "traceMessages.as"
traceMessages(_root);

And now we get informed, when an method is called
like this:


[call] scrollIt (called by startUpScroller)
[call] getScrollPosition (called by scrollIt)
[call] setScrollPosition (called by scrollIt)
[call] executeCallBack (called by setScrollPosition)
[call] executeCallBack (called by executeCallBack)
[call] onScrollBarChangeRight (called by executeCallBack)
[call] getScrollPosition (called by onScrollBarChangeRight)

In this case we used _root as base for the treeTrace-method,
but we can also use any other object which aggregated methods
we like to observe.
view
download

Posted by hOk at May 15, 2003 11:08 PM

Scite|Flash: Mini-Tip - highlightning single-quoted strings

Hi normally single-quoted-strings are not highlighted in
Scite|Flash. But you can simply add the following line
into the flash.properties-file:
style.flash.7=fore:#009933

Posted by hOk at May 15, 2003 03:03 PM

Object.registerClass - one linkage and many classes

I do not know if that is something new. But i allways have thought,
that i can use one libary-linkage with only one class, but the solution
is more than logically...;-)



MovieClip.prototype.attachMovieWithClass = function (pStrLinkage, pStrName, pIntDepths, pObjInit, pFuncClass) {
   Object.registerClass(pStrLinkage, pFuncClass);
   //
   mc = this.attachMovie(pStrLinkage, pStrName, pIntDepths, pObjInit);
   //
   Object.registerClass(pStrLinkage, null);
   return mc;
}
ASSetPropFlags(MovieClip.prototype, null, 1, 0);

// test
MoveRightClass = function () {}
MoveRightClass.prototype.onEnterFrame = function () {
   this._x += 10;
}
MoveDownClass = function () {}
MoveDownClass.prototype.onEnterFrame = function () {
   this._y += 10;
}
this.attachMovieWithClass('mcBall', 'mcBall1', 1, null, MoveRightClass);
this.attachMovie('mcBall', 'mcBall2', 2);
this.attachMovieWithClass('mcBall', 'mcBall3', 3, null, MoveDownClass);

Posted by hOk at May 14, 2003 05:16 PM

Scite|Flash: Mini-Tip

If youre using the Scite|Flash-Editor you can get an
autocomplete for your own variables when you press
Ctrl + Enter, oh man it so cool to prevent typos
this way...;-)
Has anyone an Idea how we get this automaticly?

Posted by hOk at May 13, 2003 05:11 PM

Flair-Patter: real-world example textFieldAutoComplete

So, after wrangling around with the Flair-Patter,
i have created an Autocomplete-Flair, based on
the autocomplete-code of brandon halls and
samual wans book.
view
download




In compare with the State-Patter the Flair-Patter,
is faster to implement and the target-object did not
need to know anything about his flair. The consequence
is that the target-object must have broadcaster,
to that the Flair-Object can listen to.
If youre target-object do not have a broadcaster
mostly the State-Patter is the better choice, to implement
the behaviour of dynamic changing the class(state-change).
Where did you see the pros and cons of these two patterns?

//
// ::: namespace :::
if (TextFlair == undefined) {
   _global.TextFlair = new Object();
}
//
// ::: constructor :::
TextFlair.AutoComplete = function (pTxtTarget) {
   this.init(pTxtTarget);
}
//
// ::: flair-static-methods :::
TextFlair.AutoComplete.snapOn = function (pTxtTarget) {
   pTxtTarget.$flairAutoComplete = new this(pTxtTarget);
   //
   pTxtTarget.addListener(pTxtTarget.$flairAutoComplete);
}
//
TextFlair.AutoComplete.snapOff = function (pTxtTarget) {
   pTxtTarget.removeListener(pTxtTarget.$flairAutoComplete);
   //
   delete pTxtTarget.$flairAutoComplete;
}
//
// ::: object-methods :::
o = TextFlair.AutoComplete.prototype;
//
o.init = function (pTxtTarget) {
   this.INT_MAX_STORAGE = 10; // configure
   //
   this.txtTarget = pTxtTarget;
   this.strLastText = this.txtTarget.text;
   this.lso = null;
   this.hashAutoComplete = this.getAutoCompleteHash();
}
//
o.onChanged = function () {
   if (this.txtTarget.text == this.strLastText) {
      return;
   }
   //
   this.strLastText = this.txtTarget.text;
   //
   this.processAutoComplete();
}
//
o.processAutoComplete = function () {
   var strText = this.txtTarget.text;
   var intCaretIndex = Selection.getCaretIndex();
   //
   if (Key.getCode() == Key.BACKSPACE || Key.getCode() == Key.DELETEKEY) {
      this.txtTarget.text = strText.substr(0, intCaretIndex);
   } else {
      for (var p in this.hashAutoComplete) {
        if (p.indexOf(strText.substr(0, intCaretIndex)) == 0) {
           this.txtTarget.text = p;
           Selection.setSelection(intCaretIndex, p.length);
        }
      }
   }
}
//
o.getAutoCompleteHash = function () {
   this.lso = sharedobject.getLocal(this.txtTarget._name, _url);
   //
   if (this.lso.data.hashAutoComplete == undefined) {
      this.lso.data.hashAutoComplete = new Object();
   }
   //
   return this.lso.data.hashAutoComplete;
}
//
o.saveHints = function () {
   this.hashAutoComplete[this.txtTarget.text] = 1;
   //
   this.deleteOverFlow();
}
//
o.deleteOverFlow = function () {
   var i = 0;
   for (var p in this.hashAutoComplete) {
      i++;
      if (i > this.INT_MAX_STORAGE) {
        delete this.hashAutoComplete[p];
      }
   }
}
//
delete o;

//
// test
// add flair
TextFlair.AutoComplete.snapOn(txtName);
TextFlair.AutoComplete.snapOn(txtCountry);
// saves input-text as hints
saveHints = function () {
   txtName.$flairAutoComplete.saveHints();
   txtCountry.$flairAutoComplete.saveHints();
}
// setup the button
btnSend.setClickHandler('saveHints');

Posted by hOk at May 12, 2003 06:46 PM

Runtime extending with flair

Brandon Hall and Samual Wan developped the
Flair-Pattern. It is a realy good technik
to add beaviours to allready existing objects.




The Flair-Object is simply copied into the
object which we would extend.
The Flair Pattern is similary to the state-pattern
because our subject aggregates the flair-object.
This is quit usefull because we can change, remove
and add functionality add runtime. This look of
our object can completly change, like as our object
changed the class.
Hence, let us look to my interpretation of the flair-
patter with example code.
//
// > Now we create our first flair-class
//

// First we setup a namespace for our flair-classes
if (CarFlair == undefined) {
   _global.CarFlair = new Object();
}

// ===============================
// Now setup our first flair-class
// ===============================
CarFlair.SoundFlairFuelEmpty = function () {}

// =============================================================
// Setting up the standard-methods that belongs to flair-classes
// =============================================================
// This class-method is needed to add the flair to a car
CarFlair.SoundFlairFuelEmpty.addFlair = function (pObjCar) {
   //
   // Now let us copy the Flair into the carObject. We
   // modify the car-object, because we add a property.
   pObjCar.$objSoundFlair = new this();
   //
   // Our flair needs a reference to the car-Object
   pObjCar.$objSoundFlair.objCar = pObjCar;
   //
   // Well, now our soundflair-object need to know if the,
   // if the fuel status changed, so we let it listen to
   // the cars broadcaster
   pObjCar.addListener(pObjCar.$objSoundFlair);
}
//
// Method to remove a the flair
CarFlair.SoundFlairFuelEmpty.removeFlair = function (pObjCar) {
   pObjCar.removeListener(pObjCar.$objSoundFlair);
   //
   delete pObjCar.$objSoundFlair;
}

// ========================================
// Setup the specific methods of this flair
// ========================================
CarFlair.SoundFlairFuelEmpty.prototype.onFuelFilled = function () {
   //
   // our tank was filled, so we can change the flair
   CarFlair.SoundFlairFuelEmpty.removeFlair(this.objCar);
   CarFlair.SoundFlairFuelFilled.addFlair(this.objCar);
}
//
CarFlair.SoundFlairFuelEmpty.prototype.onEngineStart = function () {
   trace('put....pt...p....');
}

//
// > Ok, know lets create another flair that should be used
//
//
// class
CarFlair.SoundFlairFuelFilled = function () {}
//
// flair-class-methods
CarFlair.SoundFlairFuelFilled.addFlair = function (pObjCar) {
   pObjCar.$objSoundFlair = new this();
   pObjCar.$objSoundFlair.objCar = pObjCar;
   pObjCar.addListener(pObjCar.$objSoundFlair);
}
//
CarFlair.SoundFlairFuelFilled.removeFlair = function (pObjCar) {
   pObjCar.removeListener(pObjCar.$objSoundFlair);
   delete pObjCar.$objSoundFlair;
}
//
// flair-object-methods
CarFlair.SoundFlairFuelFilled.prototype.onFuelEmpty = function () {
   CarFlair.SoundFlairFuelFilled.removeFlair(this.objCar);
   CarFlair.SoundFlairFuelEmpty.addFlair(this.objCar);
}
//
CarFlair.SoundFlairFuelFilled.prototype.onEngineStart = function () {
   trace('bruuummm, broouuhhmm, brruuemmm');
}

//
// > And know create the car-class
//

//
// class
Car = function () {
   // we need our car to be an Broadcaster for the
   // events: onEngineStart, onFuelEmpty, onFuelFilled
   ASBroadcaster.initialize(this);
   //
   // ok let us assume that our tank is filled
   CarFlair.SoundFlairFuelFilled.addFlair(this);
   //
   //ASSetPropFlags(this,null,0,1);
}
//
// methods
Car.prototype.startEngine = function () {
   this.broadcastMessage('onEngineStart');
}
//
Car.prototype.onFuelFilled = function () {
   this.broadcastMessage('onFuelFilled');
}
//
Car.prototype.onFuelEmpty = function () {
   this.broadcastMessage('onFuelEmpty');
}

//
// > Now testing the complete
//
objCar = new Car();
objCar.startEngine(); // bruuummm, broouuhhmm, brruuemmm
objCar.onFuelEmpty();
objCar.startEngine(); // put....pt...p....
objCar.onFuelFilled();
objCar.startEngine(); // bruuummm, broouuhhmm, brruuemmm

The Flair has did the change by them self, sometimes
it is better to let your object do the change.
The coupling with events is mostly a flexible way, but
it is also possible to call direct the flair-methods,
then the object must know thair flair-objects and we have
nearly exactly the state-patter.
I like the flexibility of flair, also it is very
good to use for extending Textfield-objects, like Brandon
and Wan did it in there book.

Posted by hOk at May 11, 2003 01:38 PM

Debugging: treeTrace

I have written a treeTrace-method, the functionality
is good the code looks not so good.




Ralf Bokelberg and i have
refactored the code into little peaces, mainly
this can be good practice, because a method-call is
often more easy to understand than on big method.
If you want to read an good code example for this technic,
read ralfs Prealoader-Class, it is fantastic to read.
The Problem with treeTrace was the complexity of the
allgorithm which was after refactoring cut into many small
Peaces. The Allgorithm is not easy, because it implements,
an multidemensional depths search with depths-control
without using recursive-method-calls. Therefore it would
be more easy to read it in one Method.
#include "treeTrace.as"

// Test
obj = new Object();
obj.a1 = 42;
obj.a2 = new Array();
obj.a2[0] = new LoadVars();
obj.a2[1] = new Sound();
obj.a3 = 'test';
obj.a4 = 'test';
obj.a5 = new Object();
obj.a6 = 'test';
obj.a7 = function () {};
obj.a8 = 'test';
obj.a9 = new Object();
obj.a9.b1 = new Object();
obj.a9.b2 = 'test';
obj.a10 = new Object();
obj.a10.b1 = new Object();
obj.a10.b1.c1 = new Object();
obj.a10.b1.c1.d1 = new Object();
obj.a11 = new Object();
obj.a11.b1 = 'test';
obj.a12 = 'test';
obj.a13 = obj; // backreference-test
obj.a14 = new Object();
obj.a14.b1 = obj.a14; // backreference-test
obj.a15 = new Object();
obj.a15.b1 = new Object();
obj.a15.b2 = new Object();
obj.a15.b3 = new Object();

treeTrace(obj, 'obj');

// Output:
/*
----------------------------------------------------
__[obj:[object refers #0] = [object Object]]
|__[a1:[number] = 42]
|__[a2:[array #1] = ,[object Object]]
| |__[0:[loadvars #2] = ]
| |__[1:[sound #3] = [object Object]]
|__[a3:[string] = test]
|__[a4:[string] = test]
|__[a5:[object #4] = [object Object]]
|__[a6:[string] = test]
|__[a7:[function #5] = [type Function]]
|__[a8:[string] = test]
|__[a9:[object #6] = [object Object]]
| |__[b1:[object #7] = [object Object]]
| |__[b2:[string] = test]
|__[a10:[object #8] = [object Object]]
| |__[b1:[object #9] = [object Object]]
|   |__[c1:[object #10] = [object Object]]
|    |__[d1:[object #11] = [object Object]]
|__[a11:[object #12] = [object Object]]
| |__[b1:[string] = test]
|__[a12:[string] = test]
|__[a13:[object refers #0] = [object Object]]
|__[a14:[object #13] = [object Object]]
| |__[b1:[object refers #13] = [object Object]]
|__[a15:[object #14] = [object Object]]
|__[b1:[object #15] = [object Object]]
|__[b2:[object #16] = [object Object]]
|__[b3:[object #17] = [object Object]]
----------------------------------------------------
*/

//treeTrace(_global, '_global', true);

Look at the result for this:
treeTrace(_global, '_global', true);
Get the as-File


Posted by hOk at May 8, 2003 08:48 PM

Debugging: __resolve two points to use it in your classes

Ok, first let us look the example:
MyClass = function () {}
MyClass.prototype.__resolve = function (pStrMethodName) {
   return function () {
      trace('ERROR: "' + pStrMethodName + '" does not exist!');
      trace('\tArguments:');
      for (var i in arguments) {
        trace('\t\t' + arguments[i] + '(' + typeof(arguments[i]) + ')');
      }
   }
}

obj = new MyClass();
obj.strangeMethodName('param1', 'param2');
// output:
// ERROR: "strangeMethodName" does not exist!
//  Arguments:
//   param2(string)
//   param1(string)

So the first point is that you can use it
to determine that you have called an non
existing method.

The second point is that you can proposed
write an type into you method-call to observe
the correctness of your arguments. I think
thats an good an easy way for getting a quick
watch.

Oh, man i feel that my english is totally wrong,
hope you understand me, anyhow...;-)

Posted by hOk at May 5, 2003 11:09 PM

Debugging: assertDefined

Ralf Bokelberg just has written about the assert concept
on his blog.
I think this technique is quiet usefull, because you get only
informed if errors happens.
I have written an little function that checks if an object exists,
if not we get an error-message and the player will stop.
If you use the assert-method as argument of a trace-call,
you can simple export without traces and no debugging
code will be published.



trace(String(_global.assertDefined = function (pStrPath) {
   if (eval(pStrPath) == undefined) {
      trace('ERROR: "' + pStrPath + '" is undefined!\n');
      var f = function () { f(); };
      f();
   }
   return '';
}).substr(0,0));

a = {};
a.b = {};
a.b.c = {};
trace(assertDefined('a.b.c')); // Newline in output-window, else happens nothing
trace(assertDefined('a.b.s')); // Output: ERROR: "a.b.s" is undefined!

Posted by hOk at May 3, 2003 03:11 PM

New Place