Why this TLFTextField code works only once? - actionscript-3

I need the text in an input TLF text field to be modified when the user changes it. As for example, I'm trying to make it uppercase every time the user adds or deletes a character:
import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;
var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField);
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 200
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";
var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;
var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();
//--
myTLFTextField.addEventListener(Event.CHANGE, this.onTextFieldChange);
function onTextFieldChange(event:Event):void
{
myTLFTextField.text = myTLFTextField.text.toUpperCase();
}
The code that goes before //-- is taken from the TLFTextField documentation, the very first example on the page.
When I try to edit the text, it does become uppercase, but after that the text field stops responding to any input and the output says
TypeError: Error #1009: Cannot access a property or method of a null
object reference. at
flashx.textLayout.container::TextContainerManager/getController() at
flashx.textLayout.container::TextContainerManager/mouseDownHandler()
When I comment out the addEventListener line, all appears to be working fine.
Does it mean that it's not possible to make changes to the text in a TLF text field on user input event like it is possible with the classic text fields?

Why? Because TLF has got problems. As others have pointed out, changing TLF text inside an Event.CHANGE handler causes the change handler to be called a second time. At that point, things break down.
I had come up with a solution that's similar to the one #Abe posted, but it's more general – it doesn't rely on checking for upper case characters. You listen for TextEvent.TEXT_INPUT, then toggle an Event.CHANGE listener inside the text input handler.
import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;
import flash.text.TextFieldType;
import flash.events.TextEvent;
var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField);
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 500
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";
myTLFTextField.border = true;
myTLFTextField.multiline = true;
myTLFTextField.type = TextFieldType.INPUT;
var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;
var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();
myTLFTextField.addEventListener(TextEvent.TEXT_INPUT, onTextInput);
var selectionIndex:uint;
function onTextInput(e:TextEvent):void
{
trace("onTextInput");
selectionIndex = myTLFTextField.selectionEndIndex;
myTLFTextField.addEventListener(Event.CHANGE, onTextChanged);
}
function onTextChanged(e:Event):void
{
trace("onTextChanged");
myTLFTextField.removeEventListener(Event.CHANGE, onTextChanged);
// Do whatever you need to do here:
myTLFTextField.text = myTLFTextField.text.toUpperCase();
myTLFTextField.setSelection(selectionIndex + 1, selectionIndex + 1);
}

Can't try your code right now so this is a wild guess, but the controllers seem to disappear when you set the text. what happens if you symply do this :
private var m_dontupdate:Boolean;
function onTextFieldChange(event:Event):void
{
if(m_dontupdate) return;
m_dontupdate = true;
myTLFTextField.text = myTLFTextField.text.toUpperCase();
myTLFTextField.textFlow.flowComposer.updateAllControllers();
m_dontupdate = false;
}
? (I can't try it because I use FB 4.7 and TLFTextField is nowhere to be found).

First - you doing infinite loop in event listener! Your code in event handler invokes it selves! TLF.text = VALUE produce event like TLF.dispatch(new Event(Event.CHANGE));
So add event listener to user actions not text change! E.g. for KEY_UP
Second - correct formatting code so it will be applied to new text:
myTLFTextField.text = NEW_VALUE;
myTextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
Edit: For more clarity I add full code:
import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;
import flash.events.KeyboardEvent;
var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField);
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 400;
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";
myTLFTextField.type = "input";
//allow user to wirte in filed
var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;
var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();
//--;
myTLFTextField.addEventListener(Event.CHANGE, wrongHandler);
myTLFTextField.addEventListener(KeyboardEvent.KEY_UP, goodHandler);
myTLFTextField.text = 'TEXT';
//this invoke CHANGE and trace '-' in console
setTimeout(function(){ myTLFTextField.text = 'text';}, 500);
//this invoke CHANGE and trace '-' in console
function wrongHandler(event:Event):void
{
//myTLFTextField.text = myTLFTextField.text.toUpperCase();
//myTextFlow = myTLFTextField.textFlow;
//myTextFlow.hostFormat = myFormat;
// above code will run infinity loop of changing text! test it by uncomment and comment KEY_UP listener!
trace('-'); // to see in console when and how many event was triggered
}
function goodHandler(event:Event):void
{
myTLFTextField.text = myTLFTextField.text.toUpperCase();
myTextFlow = myTLFTextField.textFlow; // reasign formating
myTextFlow.hostFormat = myFormat;
var i:uint = myTLFTextField.text.length;
myTLFTextField.setSelection(i,i); // move carret to last sign
trace('+'); // to see in console when and how many event was triggered
}
Output:
-
-
Output after writing 'a' character in field:
-
-
-
-
+
-
Result on stage:
TEXTA

Related

Is it possible to make looped Movieclip clickable and Session data at the same time?

I am new to AS3, and i am trying to achieve the following situation.
First i receive the JSON data,sort them and put them into boxes . Each box has its set of data, e.g.Box1 (Name1,Location1,Zip1), Box2(Name2,Location2,Zip2) so on.
Boxes are put into another AS file for display, and will be put into a viewport slider.
Trying to make the boxes clickable, and when a box is clicked, it will go to next page and display the details of that specific "Listing".
1st thing is, how to make the movieclip box clickable when it is sitting inside another as file.
2nd thing is, how to pull the data from that box when it is clicked, as it is generated by the looped JSON data. (As i need to use the ID from the listing to parse it to the php to pull the details and display the full detail in the next as file.
Thanks for your time!
AS file where the boxes are generated.
package com.clark
{
import flash.display.MovieClip;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class SearchVectorTest extends MovieClip
{
public function SearchVectorTest(test:Vector.<searchVO1>)
{
super();
for (var j:int = 0; j < test.length; j++)
{
trace(test[j].nobed);
trace(test[j].zip);
trace(test[j].Location);
trace(test[j].price);
}
var len:int = test ? test.length : 0;
listings = new Vector.<Listing8>(len, true);
var currentY:int = 100;
for (var k:int = 0; k < test.length; k++)
{
var Bolder:Listing2 = new Listing2();
Bolder.x=20;
var bf:TextField = new TextField();
var bf1:TextField = new TextField();
var bf2:TextField = new TextField();
var bf3:TextField = new TextField();
bf3.width = 100;
bf.defaultTextFormat = new TextFormat("Arial", 12, 0, null, null, null, null, null, TextFormatAlign.CENTER);
bf.width = 100;
bf.autoSize = TextFieldAutoSize.CENTER;
bf1.width = 100;
bf1.autoSize = TextFieldAutoSize.CENTER;
bf2.autoSize = TextFieldAutoSize.CENTER;
bf3.autoSize = TextFieldAutoSize.CENTER;
bf3.width = 100;
bf1.y= bf.height+5;
bf.text = test[k].nobed;
bf1.text = test[k].zip;
bf2.text = test[k].Location;
bf3.text = test[k].price;
bf.x = (Bolder.height-bf.height)*.2
Bolder.addChild(bf);
Bolder.addChild(bf1);
Bolder.addChild(bf2);
Bolder.addChild(bf3);
Bolder.properties = test[k].nobed;
Bolder.properties = test[k].zip;
// position the object based on the accumulating variable.
Bolder.y = currentY;
addChild(Bolder);
Bolder.mouseChildren = false; // ignore children mouseEvents
Bolder.mouseEnabled = true; // enable mouse on the object - normally set to true by default
Bolder.useHandCursor = true; // add hand cursor on mouse over
Bolder.buttonMode = true;
listings[k] = Bolder;
currentY += Bolder.height + 10;
}
}
}
}
AS file where the VectTest file sits
package com.clark
{
import flash.display.*;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.Stage;
import fl.controls.Button;
public class sresultnologin extends MovieClip {
public var s1:Searchreult = new Searchreult ();
public function sresultnologin(){
addEventListener(Event.ADDED_TO_STAGE, onadded);
function onadded (event:Event):void{
s1.x=-10;
s1.y=10;
addChild(s1);
}
var s3:SearchVectorTest= new SearchVectorTest(new Vector.<searchVO1>);
addChild (s3);
s1.SRhome.addEventListener(MouseEvent.CLICK, fl_ClickToGoTol);
s1.ARsearch.addEventListener(MouseEvent.CLICK, fl_ClickToGosearch);
if( s3.listings.length > 0 )
{
// get the first listing in the listing array
var newListing:Listing8 = s3.listings[0];
newListing.addEventListener(MouseEvent.CLICK, gotoscener);
}
else
{
//
}
}
// private methods
private function fl_ClickToGoTol(event:MouseEvent):void
{
var s9:Account = new Account ();
removeChild(s1);
addChild(s9);
}
private function fl_ClickToGosearch(event:MouseEvent):void
{
var s9:searchVO1 = new searchVO1 ();
removeChild(s1);
addChild(s9);
}
}
}
Edit(Added in SearchVectorTest)
var len:int = test ? test.length : 0;
listings = new Vector.<Listing8>(len, true);
Edit(Added in sresultnologin)
if( s3.listings.length > 0 )
{
// get the first listing in the listing array
var newListing:Listing8 = s3.listings[0];
newListing.addEventListener(MouseEvent.CLICK, gotoscener);
}
else
{
//
}
One
The "other as file" (a class) must be instantiated, and (as a DisplayObject) must be added to the stage for it to become visible.
Consider the following stage layout:
root:MainTimeline ¬
0: background:Shape
1: listingWindow:Slider
And the sresultnologin (when instantiated) looks like this:
this:sresultnologin ¬
0: s3:SearchVectorTest ¬
0: Bolder:Listing2 ¬
0: bf:TextField
1: bf1:TextField
2: bf2:TextField
3: bf3:TextField
1: s1:Searchreult
All you need to do is addChild(sresultnologin) to the stage (or your Slider), and those child elements will appear.
To make it clickable, simply attach the listener to your object via object.addEventListener("mouseUp", listener). This can be done at any point: in the constructor of SearchVectorTest, or sresultnologin, or after it's been added to the stage when your "box is clicked" and the new listing appears. If you wanted to do that from the document code, it might look like this:
var newListing:Listing2 = listingWindow.getChildAt(0).getChildAt(0).getChildAt(0);
newListing.addEventListener("mouseUp", doStuff);
However, that's wholly dependent on DisplayList indexes (which could change wildly). A better solution may be to name these items and use getChildByName("string") instead. That too, however, could be perilous if you have non-unique names for each object. Consequently, if you're adding these new listings from inside one of your classes (such as sresultnologin), you could simply provide a property on the class which points to the current listing, and reference that from document code.
Two
JSON data is no different from any other object structure in AS3. If you want, you could store it as a property of the class, and reference the variable at the appointed time. If you want to store data specific to a particular listing on the particular object which represents it, try adding to Bolder in SearchVectorTest the following:
Bolder.properties = test[k];
Edit:
Remember that the variable name is not the same as the name property on an object. In other words...
var Bolder:Listing2 = new Listing2(); // variable is Bolder, of type Listing2
Bolder.name = "foo" // the name property on Bolder is now "foo"
getChildByName("Bolder") // this should fail since there is no object with that name
getChildByName("foo") // works.
This really isn't complicated as long as you're aware of the differences. Please run the script I gave you (under "Pathing to Objects") which shows you the hierarchy of your stage. After you have the output, it should be self-explanatory what pathing you need to use to reference your variables.

TextField as3 getting the input

i have a problem witch i cant solve, and i wanted to ask what am i doing wrong. The idea should be that when i create the textfield i want to read from it, but it doesnt
function click2(e:MouseEvent):void{
e.currentTarget.removeEventListener(MouseEvent.CLICK, click2);
fx=e.target.x+400;
fy=e.target.y+300;
var i:int;
i=2;
trace(str);
trace(e.target.name);
var line:Shape = new Shape();
line.graphics.lineStyle(1,0xFF0000,2);
line.graphics.moveTo(sx,sy);
line.graphics.lineTo(fx,fy);
this.addChild(line);
var inputField:TextField = new TextField();
inputField.border = true;
inputField.type = TextFieldType.INPUT;
inputField.width = 23;
inputField.height = 18;
inputField.x = (sx+fx)/2;
inputField.y = (sy+fy)/2;
inputField.multiline = false;
inputField.maxChars = 3;
inputField.restrict = "0-9";
str=inputField.text;
addChild(inputField);
}
In this code i create a line, and near it appears a textfield , where you need to input the value of the line, but i can`t get it , when i want to trace the STR value, it is null,the text should be written by the user and i should read it ...
If you want to check the data the user added to the textinput you have to listen for the change-event. After that you can access the provided text.
function click2(e:MouseEvent):void{
...
inputfield.addEventListener(Event.CHANGE, checkInput);
}
function checkInput(e:Event):void {
//receive input value and validate it
var textfield:TextField = e.target as TextField;
var str:String = textfield.text;
...
}

Cannot access null object reference for RadioButtonGroup

Quick version:
When trying to compare 2 RadioButtonGroups with an if statement, if one of the groups does not have a RadioButton selected, I get an error;
Error #1009: Cannot access a property or method of a null object reference.
Long version:
I am creating 2 lists in actionscript that have the same content and have stored them in RadioButtonGroups. The idea is that a user will choose an element from column A and then select an element from column B. This functionality works fine, but when I do validation where the program checks when clicking a button if both columns have been selected, I get:
Cannot access property error (See above).
Here is my code:
import fl.controls.RadioButtonGroup;
import flash.events.MouseEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import fl.controls.RadioButton;
var focus1:RadioButtonGroup = new RadioButtonGroup("Focus 1");
var focus2:RadioButtonGroup = new RadioButtonGroup("Focus 2");
var myXML:XML;
var myLoader:URLLoader = new URLLoader();
var btn1:Array = new Array();
var btn2:Array = new Array();
myLoader.load(new URLRequest("courseLoader.xml"));
myLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void {
myXML = new XML(e.target.data);
for (var i = 0; i < myXML.COURSES.length(); i++) {
var radA:RadioButton = new RadioButton();
var radB:RadioButton = new RadioButton();
// Create left focus column
radA.x = 50;
radA.y = i * 25 + 75;
radA.width = 300;
radA.name = "radA" + i;
radA.label = myXML.COURSES[i].NAME[0];
addChild(radA);
btn1.push(radA);
btn1[i].group = focus1;
// Create right focus column
radB. x = 450;
radB.y = i * 25 + 75;
radB.width = 300;
radB.name = "radB" + i;
radB.label = myXML.COURSES[i].NAME[0];
addChild(radB);
btn2.push(radB);
btn2[i].group = focus2;
}
submit_btn.addEventListener(MouseEvent.CLICK, checkResult);
function checkResult(e:MouseEvent):void {
var tempVar
if (focus1.selection.label == focus2.selection.label) {
feedback.text = "Nope, they're both the same. Try again";
} /* THIS IS WHERE IT STOPS WORKING */ else if (focus1.selection == null) {
feedback.text = "You forgot to choose a focus from the 2nd column!";
} else if (focus1.selection.label == null) {
feedback.text = "You forgot to choose a focus from the 1st column!";
} else if (focus2.selection.label == null) {
feedback.text = "You forgot to choose a focuse from the 2nd column!";
}
}
I've tried using different kinds of properties and methods for comparing both groups and checking if one of them is not selected but I keep getting the same error.
You first are checking for labels, and only THEN you check if selection is null. This is wrong, you have to do it in reverse order.
if (focus1.selection == null) {
feedback.text = "You forgot to choose a focus from the 1st column!";
} else if (focus2.selection == null) {
feedback.text = "You forgot to choose a focus from the 2nd column!";
} else if (focus1.selection.label == focus2.selection.label) {
feedback.text = "Nope, they're both the same. Try again";
}

Actionscript 3 Dynamically created buttons not showing

I am new to Flash and Actionscript. I have a movie that is initiated from a C# program. In the movie I am creating different textfields and passing the data back to the C# program. I also have a hotspot that when it is clicked I want to create a small menu that pops up. I've looked at a number of ways to do this and I decided that the easiest way to do this (or so I thought) would be to create a couple of buttons right under the hotspot. For some reason the buttons do not show up on the stage when I click on the hot spot. I know it is going through the routine that creates the buttons because I display a message. I have posted my code. Thanks for the help!!
import flash.text.TextField;
import fl.controls.Button;
import flash.events.Event;
hotSpot.addEventListener(MouseEvent.CLICK, showMenu);
var continueBtn:Button;
var exitBtn:Button;
function showMenu(evt: Event):void
{
continueBtn = new Button();
continueBtn.x = 20;
continueBtn.y = 100;
continueBtn.width = 30;
continueBtn.height = 20;
continueBtn.border = true;
continueBtn.visible = true;
continueBtn.label = "Continue";
addChild(continueBtn);
exitBtn = new Button();
exitBtn.x = continueBtn.x;
exitBtn.y = continueBtn.y + continueBtn.height;
exitBtn.width = 30;
exitBtn.height = 20;
exitBtn.border = true;
exitBtn.visible = true;
exitBtn.label = "Exit";
addChild(exitBtn);
continueBtn.addEventListener(MouseEvent.CLICK, sendMsg);
exitBtn.addEventListener(MouseEvent.CLICK, endFlash);
inTxt.text = "showMenu";
}
The message "showMenu" is displayed but neither one of the buttons show.
Gary
function showMenu(evt: Event):void
The evt must be a "MouseEvent" instead of "Event" because the listener you added to the "hotSpot" sprite (probably, or other display object) is a MouseEvent not an Event.
hotSpot.addEventListener(MouseEvent.CLICK, showMenu);
This calls the showMenu function which listens and catch the MouseEvent and not the Event event.
You also imported only the Event, import the MouseEvent instead!
New Code:
import flash.text.TextField;
import fl.controls.Button;
import flash.events.MouseEvent; //This line changed!
hotSpot.addEventListener(MouseEvent.CLICK, showMenu);
var continueBtn:Button;
var exitBtn:Button;
//This line changed!
function showMenu(evt:MouseEvent):void{
continueBtn = new Button();
continueBtn.x = 20;
continueBtn.y = 100;
continueBtn.width = 30;
continueBtn.height = 20;
continueBtn.border = true;
continueBtn.visible = true;
continueBtn.label = "Continue";
addChild(continueBtn);
exitBtn = new Button();
exitBtn.x = continueBtn.x;
exitBtn.y = continueBtn.y + continueBtn.height;
exitBtn.width = 30;
exitBtn.height = 20;
exitBtn.border = true;
exitBtn.visible = true;
exitBtn.label = "Exit";
addChild(exitBtn);
continueBtn.addEventListener(MouseEvent.CLICK, sendMsg);
exitBtn.addEventListener(MouseEvent.CLICK, endFlash);
inTxt.text = "showMenu";
}

How to add a button in as

hi I am just starting to learn flex and action script. can someone tell me I doing wrong in this code.
public function createBoxes():void
{
//create a Panel
var colorsPanel:Panel = new Panel(); colorsPanel.layout = "absolute"; colorsPanel.width = 250; colorsPanel.height = 250;
//add the Panel to the Application
addElement(colorsPanel);
//create a red box
var redBox:Canvas = new Canvas(); redBox.x = 70; redBox.y = 70; redBox.width = 50; redBox.height = 50; redBox.setStyle("backgroundColor", 0xFF0000);
//create a green box
var greenBox:Canvas = new Canvas(); greenBox.x = 90; greenBox.y = 90; greenBox.width = 50; greenBox.height = 50; greenBox.setStyle("backgroundColor", 0x00FF00);
//create a blue box
var blueBox:Canvas = new Canvas(); blueBox.x = 100; blueBox.y = 60; blueBox.width = 50; blueBox.height = 50; blueBox.setStyle("backgroundColor", 0x0000FF);
//add the boxes to the Panel
var Button:spark.components.Button = new spark.components.Button(); Button.x = 120; Button.y = 60; Button.label ="removeG";
colorsPanel.addElement(redBox);
colorsPanel.addElement(greenBox);
colorsPanel.addElement(blueBox);
colorsPanel.addElement(Button);
}
thanks
I'm going to take a stab at it here...
Are you using a Spark panel, or a Halo panel?
The way you can tell is by looking at your import statements.
If you see the line:
import spark.components.Panel;
Then you're using a Spark Panel. In this case, you cannot set the layout property using a string. Instead you have to use an instance of a class that extends LayoutBase, such as BasicLayout. If, however, you see this line instead:
import mx.containers.Panel;
Then you're using a Halo Panel and I'm not sure what the problem is - you'll need to better describe the difference between what you expect to happen and what is actually happening. If you're getting some kind of error, post the text of the error.