I am making something in Actionscript 3, where people can modify a piece of text, within a TextArea.
Now, it's easy to get the typed character, but using event.getChar.
But, I would also like to know where the character was typed: the (text)cursor position.
I've read about that it's easy to do with a TextField, however, I want to use a TextArea for a few reasons:
I've read about it being possible with a TextField, but I'm not sure how I would make that into an input field...
Also, the TextArea is recommended for multiline text.
If I could hack a TextField to behave like a TextArea, I'm fine with that.
So, my question:
How can I get the position of the cursor in a TextArea?
or
How can I make a TextField behave like a TextArea?
EDIT: I managed to make an input TextField, but the caretIndex returns xyz coordinates, pretty useless for text editing/comparing... Any suggestions on that?
you can see which letter was clicked in a textfield by doing the following:
var tf:TextField;
var clicked_on_index:int = tf.getCharIndexAtPoint(tf.mouseX, tf.mouseY);//find index of char clicked on in string
var clicked_on_char:String = tf.text.substr( clicked_on_index, 1 );//find char clicked on from textfield
or if you just want to know the position of the last character entered:
var tf:TextField;
tf.addEventListener(Event.CHANGE,function(event:Event):void{
var newCharacterPosition:int=tf.caretIndex;
var totalCharacters:int=tf.text.length;
});
Related
I didn't know how to phrase the title, so sorry about that. If you have a better title suggestion, let me know and I'll change it.
I've got a chunk of text that is displayed as HTML in a TextField. An example of this text is this:
1
<font size="30" color="#FF0000">When your only tool is a hammer, all problems start looking like nails.</font>
</br>
2
<i>99 percent of lawyers give the rest a bad name.</i>
<b>Artificial intelligence is no match for natural stupidity.</b>
<u>The last thing I want to do is insult you. But it IS on the list.</u>
</br>
3<showimage=Images/image1.jpg>
I don't have a solution, but I do admire the problem.
The only substitute for good manners is fast reflexes.
Support bacteria - they're the only culture some people have.
</br>
4
Letting the cat out of the bag is a whole lot easier than putting it back in.
Well, here I am! What are your other two wishes?
Most of the tags are basic, meant to display what I can do formatting wise. However, since Adobe Air has a sandbox that prevents inline images (via the <img src='foo.png'> tag), I've had to come up with another way to display images.
Basically, I intend on having an image displayed somewhere on the screen, and as the user scrolls the image will change based on where in the text they have scrolled to. The image can be a background image, a slideshow on the right, anything really.
In the snippet above, look for my custom tag <showimage=Images/image1.jpg>. I want to get the local y position of that tag once the TextField is rendered as HTML and word wrapped. The trouble is, when I query the y position of the tag (using getCharBoundaries), I can only either search for the tag when I render the text as a .text instead of a .htmlText. If I search for the tag in the TextField after rendering it as .htmlText, it doesn't get found because the tags are hidden and replaced with formatting.
The trouble with the y value I get before rendering the HTML is that the y value will be different due to font sizes, tags being hidden and word wrap changing the line and y value that the tag is located at.
How do I get the correct y value of an HTML tag once the HTML has been rendered?
I've considered using a different style tag, maybe something like &&&&&showImage=Images/image1.jpg&&&&, but that seems like a cop-out and I'd still run into problems if multiple of those tags were in a block of text and the tags were removed, followed by word wrap that shifts lines in a pretty unpredictable way.
myTextField.textHeight tells you the height of the text in pixels. So you can split the string on whatever you're looking for, put the text before your target in the textField and get the textHeight, then put the rest of the text in.
Here's some example code - tMain is the name of the textField:
var iTextHeight: int = 0;
var sText: String = '<font size="30" color="#FF0000">When your only tool is a hammer, all problems start looking like nails.</font></br><i>99 percent of lawyers give the rest a bad name.</i><b>Artificial intelligence is no match for natural stupidity.</b><u>The last thing I want to do is insult you. But it IS on the list.</u></br><showimage=Images/image1.jpg> I don\'t have a solution, but I do admire the problem. The only substitute for good manners is fast reflexes. Support bacteria - they\'re the only culture some people have. </br>Letting the cat out of the bag is a whole lot easier than putting it back in. Well, here I am! What are your other two wishes?';
var aStringParts: Array = sText.split("<showimage=Images/image1.jpg>");
for (var i = 0; i < aStringParts.length; i++) {
if (i == 0) {
tMain.htmlText = aStringParts[i];
trace("height of text: " + tMain.textHeight);
} else {
tMain.appendText(aStringParts[i]);
}
}
sText gets split on the tag you're looking for (removes the text you're looking for and breaks remaining text into an array). The text leading up to the tag is put in the textField and the textHeight is traced. Then the rest of the text is put in the textField. This gives you the y pixel number you need to arrange things.
Let me know of any questions you have.
Instead of going through the trouble of parsing your image tag, have you tried playing with HTMLLoader and using the loadString method? This should load everything in its proper place including the image using the img tag.
private var htmlLoader:HTMLLoader;
private function loadHtml(content:String):void
{
htmlLoader = new HTMLLoader(); //Constructor
htmlLoader.addEventListener(Event.COMPLETE, handleHtmlLoadComplete); //Handle complete
htmlLoader.loadString(content); //Load html from string
}
private function handleHtmlLoadComplete(e:Event):void
{
htmlLoader.removeEventListener(Event.COMPLETE, handleHtmlLoadComplete); //Always remove event listeners!
htmlLoader.width = htmlLoader.contentWidth; //Set width and height container
htmlLoader.height = htmlLoader.contentHeight;
addChild(htmlLoader); //Add to stage
}
Another approach is to search your html string for <showImage ..> tags and replace these with shortcodes e.g [showImage ..] , before inserting the htmlString in a textField. Then this is NOT xml but text and you can retrieve the y value (that is if i understand correctly your issue).
Then the rest of your code can take it from there.
(ps using HtmlLoader seems nice alternative though)
I have a MovieClip called "number" in the library. I need to add multiple instances of that MovieClip to stage. Instances should be called number1, number2,number3...and each one needs to have different text inside it.
Is it possible to do this without code, just using flash interface tools? If not, could someone help me with coding that?
Thanks!
For an Class linked MyNumber containing a text field named output:
const N:int = 3; // 3 instances
const TEXTS:Array = ['text 1', 'text 2', 'text 3']; // 3 texts
var n:MyNumber;
for (var i:int = 0; i < N; i++) {
n = new MyNumber();
n.y = 50 * i;
n.output.text = TEXTS[i];
this.addChild(n);
}
You have to use code - at least a little bit.
In addition to #helloflash's answer, here is a simpler solution (with some caveats described below).
On your movieClip, make your text box dynamic, and give it an instance name of txt (or whatever you'd like). Then, put the following line of code on the first frame of your movieClips's timeline:
txt.text = this.name; //works if your text is a simple word with no spaces/puntuaction/symbols and doesn't match any actionscript keywords
This will set the text to whatever the instance name of each movieClip is. Will work great if you text is something simple like "Hello" or "Player1".
Now, if you're text is a number (or starts with one), or your text matches a keyword or already defined variable (like this/continue/function/break/stop/play etc), you'll need make it a bit more complicated, something like this:
txt.text = this.name.replace("$MC_","");
Then give your instance name in this format: $MC_stop, the code will strip out the $MC_ part and show the rest. so the text field would be "stop".
Now, if you want to include spaces, or most symbols (dollar sign, underscore and dash I think are the only supported ones), you'll have to add a replace for each one and create a place holder for that character.
So if your text was "This is my text", you should give it an instance name of `this_is_my_text" and this should be the code:
txt.text = this.name.replace("_"," "); //replace all underscores with space
Add as many replace statements for as many characters you need.
So, if you text was "1. This is my text!!!" - The instance name could be: $MC_1$dot_This_is_my_text$ex$ex$ex and the code:
txt.text = this.name.replace("$MC_","").replace("_"," ").replace("$dot",".").replace("$ex","!"); //you can keep chaining on as many replace statements as you need.
Of course, at this point you might as well just use full on code like #helloflash's answer. But if you text isn't that complicated, this may be a good solution for you.
I want to receive separate click events from separate lines in a text field, and every time a certain line is clicked by the user, I would like to highlight it and have an event happen.
I would ideally like this to happen with dynamic text, and not have to break the text apart by hand. Using the htmlText property is an option, but I am unsure as to how to bind clickEvents to separate elements.
Where do I begin?
There is no ready to use solution for this. But you can make it yourself using a few things:
set CLICK listener for the whole text field
listen for click and check the caretIndex property
use getLineIndexOfChar to check what's the line of the current caret position
use getLineOffset and getLineLength to get the position of the first and last character of that line
use setSelection to highlight this line
There might be some faster and easier way, but this is what works for sure :)
EDIT: decided to post the solution code, as I was wondering how exactly it works.. and it would be a shame to just leave it unpublished and make you do it instead :)
field.addEventListener(MouseEvent.CLICK, onTfClicked);
function onTfClicked(e:MouseEvent):void {
trace (field.caretIndex);
var line:uint = field.getLineIndexOfChar(field.caretIndex);
var start:uint = field.getLineOffset(line);
var end:uint = start + field.getLineLength(line);
field.setSelection(start, end);
}
Current my code is as such
setcustomlocation.addEventListener(MouseEvent.CLICK,customlocation2);
function customlocation2(e:MouseEvent):void
{
locationinput.text = FlashingWon.Won1.name.text;
}
I'm trying to make it such that it would copy the input text field values into a dynamic text. However, it throws up the error that
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at main/customlocation2()[main::frame1:9]
Which can I only assume that it is not able to communicate with the dynamic text field in the movieclip within another movieclip.
First, you can be 100% sure that it CAN communicate with the dynamic TextField in the MovieClip.
From you description I understand that you wish to copy from input into dynamic. But from your code I see that you take from the dynamic into the input, please check that out:
// This will copy in such a way: input <= wonText
locationinput.text = FlashingWon.Won1.name.text;
// This will copy from input
FlashingWon.Won1.name.text = locationinput.text;
Anyhow, the error that you get has nothing to do with this, it's rather like you already noticed, that one of your TextField is not 'found'. For this I recommend you a best practice: To create instances of the objects you want to use and populate them from the stage through the getChildByName method. This way you will promptly now (specially if you do this on construction or init) if you had any misspelling or miss structure on the childs you want to get.
like so:
var inputText: TextField;
var dynoText: TextField;
In your Constructor or else where at a soon level, give to your vars the proper value:
inputText = getChildByName('locationinput') as TextField;
dynoText = FlashingWon.Won1.getChildByName('name') as TextField;
This way you will soon enough know if one of this 2 textFields were not found under the object you give, and you have only one place to miss spell it. Also you will get code completion on your TextFields.
Finally the copy text part:
dynoText.text = inputText.text;
Hope it helps.
Alright, sorry for the delay, I was out on holidays.
I have opened your example and can see where the problems are:
1) You are trying to reach the FlashingWon when initiating the dynoText on the FIRST frame like so var dynoText = FlashingWon.Won1.getChildByName('name_txt'); BUT the FlashingWon element is ONLY available on the FIFTH frame. Meaning that you cannot refer to it quite yet, unless you add it on the first frame and make in invisible till the fifth frame. (You can make it visible in the goto1 function if you wish after the goToAndStop(5) line)
2) You called the TextField on the Won1 element 'name' which is a restricted sting in AS3, so change it to name_txt or label if you wish and it will work.
Let me know how it worked.
I want to know how(and what scripts) to take words from a text input box and cause it to display and image Ex: if the text box said "smiley face" in it, then the image "smiley_face.jpg" would display on a certain movieclip and can be dragged around the stage and when a new image is loaded, it doesn't replace the previous image on the movie clip.
You need to listen for the textInput event and you need to constantly search for "smile" using something like the search() function(u can use strings or regular expressions).
It returns -1 if the string you're searching for wasn't found, otherwise it returns the first index where the searched string was found.
Here's a really basic example:
var ti:TextField = new TextField();
ti.type = TextFieldType.INPUT;
ti.border = true;
addChild(ti);
ti.addEventListener(TextEvent.TEXT_INPUT, onInput);
function onInput(event:TextEvent):void {
if(ti.text.search('smile')!=-1) trace('display smiley image');
}
You did mention smileys, so depending on your level of comfort with actionscript 3, it might be also worth having a look at Thibault Imbert's SmileyRenderer. Careful it uses the new FTE so you need to use Flash Player 10, etc.
yeah. In ActionScript you need to add a listener event to the text field. then you can do something like this. My action script is not so good so I will just stick with logic.
if listener.text == "smile"
smile.jpg
else if listener.text == "frown"
frown.jpg
else
default.jpg
end
You should check out lynda.com for their basic AS screencasts