Reading up on ComboBox component → Link
The last code example has this line request.url = ComboBox(evt.target).selectedItem.data;
What does ComboBox(evt.target) mean? Type casting? Why would you type cast?
For curiosity reasons, I replaced the last line of changeHandler() with it too: ComboBox(evt.target).selectedIndex = -1;. It works. Does it make the handler function more flexible, since I'm not referencing aCb instance?
you are casting the trigger of the event as a ComboBox. You do this to explictly say that this variable is of this type. You don't have to most of the times but when you do you get these advantages
When you are checking what the type is
You get all of the methods in the type Class (In this case Combo Box) as autocomplete options in your IDE
Will throw an error if evt.target is not of type ComboBox after all
Also is a visual indicator of what variable it is. Very helpful when revisiting code
Related
I want to pass to function object, const of type MouseEvent.CLICK and function to trigger. In my case:
my class Assistant:
public static function addEventListenerTo(obj:Object, MouseEventConst:String, functinToTrigger:Function) {
obj.addEventListener(MouseEventConst, functinToTrigger:Function);
}
and my class Engine which invokes
Assistant.addEventListenerTo(deck,"MouseEvent.CLICK",showObject);
Please give me advice how to make it work. Thanks.
In the code you provide there is one compiler error (the one Tahir Ahmed pointed to in his second comment).
Fixing this by removing the second :Function in the first code block:
public static function addEventListenerTo
(obj:Object, MouseEventConst:String, functinToTrigger:Function)
{
obj.addEventListener(MouseEventConst, functinToTrigger);
}
will let the code compile. (I wrapped the Method signature to avoid the scrollbar, this is not required to make it compile.)
The other major problem is a configuration error (or maybe a typo): the one about MouseEvent.CLICK. (the one Tahir Ahmed pointed to in his first comment)
Looking at the documentation it is defined to have the value "click" (a String literal following the AS3 convention of the lowercase constant name). So to pass it to your method you can either put in a reference to the constant by writing MouseEvent.CLICK (without the "s around it) or reach the same goal with passing its value by writing "click".
As using the reference will prevent mistyping because the compiler checks it, the first approach should be preferred.
So calling the Method should look like this:
Assistant.addEventListenerTo(deck, MouseEvent.CLICK, showObject);
If you want to know why your version didn't work you should read a simple introduction to AS3 Events and EventDispatchers. As a short hint: if deck would dispatch an Event that has its type property set to "MouseEvent.CLICK" your listener would get fired.
While you are at it, you could improve the quality of your code by to major things:
the first one is about avoiding getting runtime Errors and prefering compile time errors: Not every instance of type Object has a method called addEventListener. In your current code, when you pass an instance to Assistant.addEventListenerTo as first parameter, that doesn't have this method (e.g. {} or an instance of type Array), the error will get thrown while your swf is displayed and it might stop displaying anything and might show an error message to the user.
If the type of the parameter is IEventDispatcher instead, the compiler will already tell you that you passed an incompatible instance.
The second one is about names and conventions, which helps other developers to read your code (an having more fun helping you).
what you called MouseEventConst is called an event type in AS3, which provides a better name for a parameter, as it being a String nobody stops anybody from passing contants of other event types like Event
the functionToTrigger is what is called a listener (or event listener)
the first letter of parameter names should be lower case
So if I would have written the static method it would look like this:
import flash.events.*;
public class Assistent{
public static function addEventListenerTo
(dispatcher:IEventDispatcher, eventType:String, listener:Function)
{
dispatcher.addEventListener(eventType, listener);
}
}
This book seems to suggest every that an event is an instance of an event case class.
"For instance, pressing a button will create an event which is an instance of the following case class:
case class ButtonClicked(source: Button)"
1) Applyin this logic, does this mean that pressing the mouse will create an event which is an instance of the following case class?:
case class MousePressed(source: Component, point: java.awt.Point, modifiers: Modifiers, clicks: Int, triggersPopup: Boolean)(peer: java.awt.event.MouseEvent)
2) To do pattern matching on the object to detect whether a specific Component has been pressed by the mouse, is this code correct?:
listenTo(mouse.clicks)
reactions += {
case MousePressed(nameOfComponent,_,_,_,_) => //some code you want to execute in response to that component being pressed //
}
3) and am I also right in thinking that the other arguments can be checked as well, say for example
case MousePressed(nameOfComponent,point,modifier,3,true)
makes for a very specific pattern: a specific component at a specific point with a certain modifier, on its third click, and triggers pop up? (it's probably not very practical)
4) What does the Modifier argument do?
1) It will create an instance of scala.swing.event.MousePressed. As I said in the comment, it doesn't matter what constructor is used during initialization, it will be the same class with the same field. The only difference is that you have a pattern available that corresponds to the primary constructor, since it's a case class.
2) Yes, and no. Formally you're correct - specifically in this case you say:
"for this component",
"capture any MousePressed event, and give me access to the component field through nameOfComponent (I don't care about the rest)."
Practically your code won't work as you expect, since event handlers in Swing are registered per component, and it seems Scala Swing follows that pattern. That means unless you say explicitly, you will only get events from the components mouse module you've used listenTo on - and no other component, not even it's children.
So, if you would e.g. want to listen on the component itself and its direct children (not children of children), you would add:
contents.foreach(child => listenTo(child.mouse.clicks))
This is of course standard Scala code - I'll leave it to you to adapt it to your needs.
And finally for this point - usually it's best to define a pattern match for specific events for specific components, instead of a "general" handler - the latter solution is useful only in a minority of cases, like making custom components.
3) Correct, here you say "I want to match MousePressed, give me access to the component, point and modifier fields through variables nameOfComponent,point, and modifier, and I want the matched event to have clicks == 3 and triggersPopup == true". The last two are called constant patterns.
4) This is really a separate question, but I'll bite, this time. They're the same thing as in Java's Swing - it's a special field for storing flags related to the event. They're even the same type as in Java - Modifiers is a type alias for Int. Basically, those are numbers which convey additional info about the event. For example, if you want to check whether this was a left click, you would use:
import java.awt.event.{InputEvent => AWTEvent} //so that we don't confuse it with the Scala class
...
case MousePressed(_,_,AWTEvent.BUTTON1_DOWN_MASK,_,_) => ...
You can use the following code to print a line telling you where the mouse clicked.
listenTo(mouse.clicks)
reactions += {
case e:MousePressed => println("press "+e.point)
}
I'm learning flex/flash and I'm lost on this one. I have used the "data" in a bunch of views and it works fine. For some reason it isn't working here.
I set a field to a string here:
function LoginLoaded (e:Event):void {
trace(e.target.data);
var ServerReturn:String;
ServerReturn = new String(e.target.data);
data.UserCommonReturnData = ServerReturn;
navigator.pushView(CommonPlaces, data);
}
and here in the common places view I try to load it back:
var CommonPlacesData:String = new String();
var CurrentSelect:String = new String();
CommonPlacesData = new String(data.UserCommonReturnData);
This gives the error "Access of undefined property data" I don't get it because calling on something like data.PickUpTime (also a string) works fine in other views.
The data begins in the first view like this:
[Bindable] public var User:ObjectProxy = new ObjectProxy();
User.ID = "2314084";
navigator.pushView(TaxiNowOrLaterView, User);
then in later views I call on it like this: (works fine)
var PickUpString:String = new String(data.ID);
Any help would be great!! Thanks!!!
There are few things about your code. First, you really should make it a habit to name the identifiers as appropriate to the language. Identifiers that start with the capital letter and subsequently use minuscule letters for the rest of the logical part of the word (system alternatively known as PascalCase) is employed to only name classes. The rest of identifiers should use camelCase (similar to PascalCase, but the first letter isn't capitalized)**. This greatly reduces the effort at understanding your code. A seasoned AS3 programmer would interpret your code as follows:
// Static constant (!) ID of the class User is assigned (?) a value of "2314084"
User.ID = "2314084";
// invoke a method pushView of a local variable navigator with arguments
// of which first is the class TaxiNowOrLater, the second is the class User
navigator.pushView(TaxiNowOrLaterView, User);
while, perhaps, you didn't mean it.
new String();
In the context of AS3 makes no sense at all. Strings are never references, are immutable and have literal syntax the majority of programmers agreed upon. The code above is identical to "". In the similar way, new String(anotherString) has exact same effect as anotherString.
Your question: event.target may be many different things, some of them may have property called "data" and some may not. The general approach to this problem is that you need to cast the value of event.currentTarget or event.target to the type you expect to dispatch the event. Suppose you are expecting an event from an instance of a Button class, then:
private function clickHandler(event:MouseEvent):void {
if (Button(event.currentTarget).enabled) // do things
}
This will not protect you from an error, if the same event was dispatched by an object, which is not a button, but will make the error reporting more conscious, because it would tell you what class was it trying to cast to what other class, when it failed.
If your program logic requires that the handler be aware of events it shouldn't handle (why?) you could then write it like this:
private function clickHandler(event:MouseEvent):void {
var button:Button = event.currentTarget as Button;
if (button && button.enabled) // do things
}
event.target vs event.currentTarget - very-very rarely you would need the event.target, most of the time you need the currentTarget. I'm not saying it is wrong, but, it looks like it might be the problem. target is the object that was the first cause of the event. Events may bubble, which means they may travel the display list hierarchy up and down, first from the parent to child, then in reverse direction. In the example below, suppose there was a label on the button, which was clicked once the event was generated - in such case, even if you added a listener to the button, event.target would be the button label, not the button. currentTarget is, on the contrary, the immediate object which dispatched the event into the handler.
Few more things: ObjectProxy is an idiotic class, you probably shouldn't use at any event. It serves no purpose and, perhaps, buggy, but very few cared to discover its bugs so far. In a nutshell, what it does is as follows: it creates an object, which "watches" dynamic creation, assignment and removal of its properties and dispatches events when these events happen. This behavior is prone to a lot of errors and implicit bugs. For example, is foo.bar = "baz"; foo.bar = "baz"; a reassignment of the same property or not? Is foo.bar.baz = "fizzbuzz"; a modification of foo.bar? What if property name is not a sting? And so on.
Why you shouldn't use it: there is always a better way to treat your data. A more transparent, easier to debug, more efficient. This class is a prototype, which had never really worked. Besides having the behavior described above, it is huge in terms of lines of code that were used to write it. Debugging the errors that happen inside of it requires a lot of time and patience, which are certainly not worth it.
If you need an object to represent a user, define a class, with properties you expect the user to have and just use that class - this will make debugging and understanding your code much easier.
[Bindable] metadata is evil. I can't tell you you should avoid it, because it is used too often, but, I will. You should avoid it as much as possible. I didn't yet encounter an instance of when the use of this meta would be justified. Much in the similar spirit as ObjectProxy it is a prototype, something designed for lazy programmers w/o much consideration for either performance or corner cases. This is, again, a source of a lot of implicit bugs, typically difficult to spot due to the code generated around this meta "swallowing" the errors. The alternative to this meta is plain addEventListener(...) code with custom events.
Unfortunately, a lot of tutorial will use this kind of code to have you quickly started with the language + framework...
** there are some exceptions to this rule: constants are all upper-case and namespace names use underscores to separate the logical part of the word, but never use uppercase letters.
I have a base class called Room and a subclass called Attic, and another called Basement.
I have a controller class that has an attribute called CurrentLocation which is type Room. The idea is I want to be able to put Attic or Basement in that property and get it back, then cast that to whatever type it is.
So if on the controller the content is of type Attic, I'm trying to figure out how to explicitly cast it. I thought I knew but its not working... Here's what I thought it would be, borrowing from Java:
var myAttic:Attic = (Attic) Controller.CurrentLocation;
This gives me a syntax error:
1086: Syntax error: expecting semicolon before instance.
So how do you cast implicitly? Or can you? I could swear I've done this before as as3.
Here are your options for casting in ActionScript 3:
Use as.
var myAttic:Attic = Controller.CurrentLocation as Attic; // Assignment.
(Controller.CurrentLocation as Attic).propertyOrMethod(); // In-line use.
This will assign null to myAttic if the cast fails.
Wrap in Type().
var myAttic:Attic = Attic(Controller.CurrentLocation); // Assignment.
Attic(Controller.CurrentLocation).propertyOrMethod(); // In-line use.
This throws a TypeError if the cast fails.
I narrowed the causes of an AS3 compiler error 1119 down to code that looks similar to this:
var test_inst:Number = 2.953;
trace(test_inst);
trace(test_inst.constructor);
I get the error "1119: Access of possibly undefined property constructor through a reference with static type Number."
Now if I omit the variable's type, I don't get that error:
var test_inst = 2.953;
trace(test_inst);
trace(test_inst.constructor);
it produces the expected output:
2.953
[class Number]
So what's the deal? I like explicitly typing variables, so is there any way to solve this error other than not providing the variable's type?
ok, this is a little hard to explain ... first of all, here is how it works:
var test_inst:Number = 2.953;
trace(test_inst);
trace((test_inst as Object).constructor);
to my understanding, this comes from the fact, that the property constructor comes from the ECMAScript-nature of ActionScript 3. It is an ECMAScript property of Object instances and is inherited through prototypes. From the strictly typed world of ActionScript 3 (which also uses a different inheritance mechanism), this property is thus not available.
greetz
back2dos
http://www.kirupa.com/forum/showpost.php?p=1951137&postcount=214
that has all the info you need :)
basically, trace(test_inst["constructor"]) will work.
Object(someobject).constructor will achieve the same thing -- and you don't have to deal with compiler issues.
Object(someinst) === someclass works as well.
dh