I've a TextArea component in my MovieClip. When I double click on it, I want to switch to TextField component, allowing me to change its content. When I click outside, I want to restart its original class (TextArea).
How can I do it?
I'm doing this, but didn't work:
element.addEventListener(MouseEvent.DOUBLE_CLICK, changeName);
private function changeName(e:MouseEvent):void{
e.target.type = TextFieldType.INPUT;
}
Where element is a TextArea (clasic and dynamic text). Thanks!
EDIT:
This is how my MovieClip looks. "Name" is the TextArea that I want to allow user changes. I'm setting it like this:
[Spanish interface]
Nombre de instancia = Instance name (empty)
Texto clásico (classic text)
Texto dinámico (dynamic text)
The MovieClip is controlling my by own base class (called 'ConfLayer'). Inside it I have this:
public function doStuff(e:MouseEvent):void{
// element = TextArea 'Name'
element.addEventListener(MouseEvent.DOUBLE_CLICK, changeName);
}
private function changeName(e:MouseEvent):void {
var tarea:TextArea = e.target as TextArea;
var tf:TextField = tarea.TextField; // this line throwing error
tf.type = TextFieldType.INPUT;
}
Because AS3 gives me errors, I tried this:
private function changeName(e:MouseEvent):void {
e.target.TextField.type = TextFieldType.INPUT;
}
When I double-click on TextArea element, the previous string removes and I can't write nothing.
You make field editable only after second click. My idea is that it's to late. the field is editable, but you'll need to click again. So, try to make ediable for a while (e.g. 300 mileseconds) after the first click. If there's no click you set the type back to DYNAMIC. After second click you'll start editing text field.
Following on my comment above, a TextArea has a textfield property.
So you should be able to do something like this:
private function changeName(e:MouseEvent):void{
var tarea:TextArea = e.target as TextArea;
var tf:TextField = tarea.textField; //make sure that textfield is camelCase!!!
tf.type = TextFieldType.INPUT;
}
I solved my own problem using background and border properties from TextField. Instead of create TextField directly on my MovieClip, I create it dynamically.
// Field 'Name' of the layer
var tarea:TextField = new TextField();
tarea.text = 'Layer';
tarea.x = -80;
tarea.y = -23;
tarea.type = TextFieldType.DYNAMIC;
tarea.height = 20;
// Format the TextField
var format_tarea:TextFormat = new TextFormat();
format_tarea.font = "Arial";
format_tarea.size = 14;
format_tarea.bold = true;
tarea.setTextFormat(format_tarea,0,tarea.length);
Then, I add it some listeners to allow changes when I click on it:
// Add event to allow name changes
tarea.addEventListener(MouseEvent.CLICK,changeName);
When I press ENTER key, I accept the changes
// Add event to accept changes on press ENTER key
tarea.addEventListener(KeyboardEvent.KEY_DOWN,acceptKeyboardName);
When TextField lost his focus, accept the changes too:
tarea.addEventListener(FocusEvent.FOCUS_OUT,acceptFocusName);
Last, I added to my own MovieClip
// Add to MC
mc.addChild(tarea);
Handlers associated to below events are these:
private function changeName(e:MouseEvent):void
{
e.target.setSelection(0,e.target.text.length);
e.target.border = true;
e.target.background = true;
e.target.type = TextFieldType.INPUT;
}
private function acceptKeyboardName(e:KeyboardEvent):void
{
if (e.charCode == 13) // When pres ENTER, remove border, background and restore dynamic type
{
e.target.type = TextFieldType.DYNAMIC;
e.target.border = false;
e.target.background = false;
}
}
private function acceptFocusName(e:FocusEvent):void
{
// When lost focus, remove border, background and restore dynamic type
e.target.type = TextFieldType.DYNAMIC;
e.target.border = false;
e.target.background = false;
}
Related
I make a textfield named 'nama' and button 'ayo'. I want to make the button disable when the textfield is empty. But when I try this code my button not disable and still working. I want the button disable before the textfield filling.
stop();
menumulaikuis();
var namasiswa:String;
var nama:TextField = new TextField();
namasiswa = nama.text;
nama.addEventListener(Event.CHANGE,handler);
function handler(event:Event){
if (nama.text) {
ayo.enabled = true;
ayo.visible = true;
} else {
ayo.enabled = false;
ayo.visible = false;
}
}
You have some little problems in your code :
You should add your text filed to the stage using addChild() :
var nama:TextField = new TextField();
addChild(nama);
If your text field is for user's input, so its type should be input :
nama.type = 'input';
To verify if a text field's text is empty, you can simply do :
if(nama.text == ''){ /* ... */ }
So your text field's change handler can be like this :
function changeHandler(event:Event): void
{
if (nama.text != '') {
ayo.enabled = true;
ayo.visible = true;
} else {
ayo.enabled = false;
ayo.visible = false;
}
}
Hope that can help.
If the Text Field isn't for user input, you cannot use the Event.CHANGE listener.
I suggest changing Event.CHANGE to Event.ENTER_FRAME; that should fix your problem.
I'm relatively new to Flash, and I was just wondering if there was any way to keep the focus off certain elements (specifically, a button, but also input text areas and such alike).
It's nothing to drastic, but it annoys me having the tab key focus on a button rather than other things. I'd rather just be able to disable the focus on that object permanently if that possible.
Thank you so much!
To disable that your component (object) get the focus when the Tab key is pressed, you can use the tabEnabled property and set it to false, like this :
// button control
var button:Button = new Button(); // fl.controls.Button
button.tabEnabled= false;
addChild(button);
// input text field
var text_field:TextField = new TextField();
text_field.type = 'input';
text_field.tabEnabled = false;
addChild(text_field);
Also, for a UIComponent like fl.controls.ColorPicker, fl.controls.ComboBox, ..., you can use the focusEnabled property like this :
// color picker control
var color_picker:ColorPicker = new ColorPicker(); // fl.controls.ColorPicker
color_picker.focusEnabled = false;
addChild(color_picker);
// slider control
var slider:Slider = new Slider(); // fl.controls.Slider
slider.focusEnabled = false;
addChild(slider);
Hope that can help.
So first off i'd like to state that i am not very good at AS3, i'm completely self taught so i am sure that there are many things i've done badly, inefficiently or plain wrong and i'm happy for any comments on these if there is things i can improve.
Okay so, this seems like a really simple problem but i don't know the exact code for it and i can't find an example anywhere
what i want to do is to change the image which i am using for my character to a separate image on a button click, then after a certain amount of time for him to go back to the original.
My image is set as a movie clip and i am calling it like so :
public var Smallclock_hero = new Smallclock;
it is worth noting that smallclock has it's own separate class.
is there a way that i can change this image on a mouse click event ?
A simple way would be:
Add a new image on the second frame of the Smallclock movieclip. Have this new image span several frames of the timeline for the duration you want it to appear for.
Place a stop(); action on the first frame of the Smallclock movieclip.
btn.addEventListener(MouseEvent.CLICK, btnChangeCharacterFrame);
function btnChangeCharacterFrame(e:MouseEvent)
{
Smallclock_hero.gotoAndPlay(2);
// Or use a frame label
// Smallclock_hero.gotoAndPlay("jump");
}
This can be achieved relatively simply using the visible property and setTimeout. When you click on your MovieClip you'll want to make the old image invisible and the new image visible:
oldImage.visible = false;
newImage.visible = true;
Then you'll want to use setTimeout to change the visible properties back to:
oldImage.visible = true;
newImage.visible = false;
setTimeout can run a function after a specified number of milliseconds. Here is an example of this technique on wonderfl : http://wonderfl.net/c/acxl
private var imageA:ImageA = new ImageA();
private var imageB:ImageB = new ImageB();
private var revertId:int;
public function Main() {
imageB.visible = false;
addChild(imageA);
addChild(imageB);
addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(e:MouseEvent):void{
clearTimeout(revertId);
revertId = setTimeout(revert, 1000);
imageB.visible = true;
imageA.visible = false;
}
private function revert():void{
imageB.visible = false;
imageA.visible = true;
}
I'm not sure how long this has existed, it seems to have just come up for the first time.
If you create a TextArea component (author or runtime) and give it focus, you'll get 3 focus events.
create a new as3 fla, drag the TextArea component into your library and paste this on frame 1.
import flash.events.FocusEvent;
import fl.controls.TextArea;
var field = new TextArea();
addChild(field);
var field2 = new TextArea();
field2.x = 150;
addChild(field2);
field.addEventListener(FocusEvent.FOCUS_IN, onFocusIn);
function onFocusIn(event:FocusEvent):void{
trace(event.target);
}
Now click on the left field. Do you see 3 trace statements?
Any idea how to fix this?
You receive multiple FocusEvents, because TextArea contains a TextInput that it controls. When you Focus on the TextArea, the focus is actually given to the TextInput and you receive a focus event for the TextArea, and another for the TextInput.
The best way to limit the number of received event is to check if the target of the event is the same that the target you actually listen.
function onFocusIn(event:FocusEvent):void{
if (event.target == event.currentTarget) {
trace(event.target); // only the focus events generated by the TextArea.
}
}
EDIT So, I got back to the code with the issue about clicks, and the actual fix is really tricky. In fact, the source of the error was a combination of various same issues.
First : the fact that TextArea and the inner TextField both send Event at the beginning.
Second : After the beginning, when the TextField receive focus from a click, it is blocked by the parent.
And Third : When the focus come from out of the swf, in your case, the focus event is send two times (dunno why).
In order to fix it correctly, I had to listen to the unknown TextField within the TextArea (instead of the TextArea itself), and keep track of the focus leaving the Stage in order to inhibit the first of the two events generated. Which gives this :
import flash.events.FocusEvent;
import fl.controls.TextArea;
var stageFocus:Boolean = true;
var field = new TextArea();
addChild(field);
var field2 = new TextArea();
field2.x = 150;
addChild(field2);
field.addEventListener(FocusEvent.FOCUS_IN, onFocusIn);
function onFocusIn(event:FocusEvent):void{
if (event.target == event.currentTarget) {
if (event.target is TextField) {
if (stageFocus) {
// Finally ! one event at a Time and no miss.
trace(DisplayObject(event.target).parent);
} else {
stageFocus = true;
}
}
} else {
event.target.addEventListener(FocusEvent.FOCUS_IN, onFocusIn);
field.removeEventListener(FocusEvent.FOCUS_IN, onFocusIn);
}
}
// check if the focus leave the stage (the user clic out of the swf)
stage.addEventListener(FocusEvent.FOCUS_OUT, onStageFocusOut);
function onStageFocusOut(event:FocusEvent) {
if (event.relatedObject == null) {
stageFocus = false;
}
}
I'm trying to make something like bookmarks, I have 1 note on the stage and when the user clicks it, it starts to drag and the users drops it where they want. the problem is I want these notes to be dragged multiple times.. here is my code:
import flash.events.MouseEvent;
//notess is the instance name of the movie clip on the stage
notess.inputText.visible = false;
//delet is a delete button inside the movie clip,
notess.delet.visible = false;
//the class of the object i want to drag
var note:notes = new notes ;
notess.addEventListener(MouseEvent.CLICK , newNote);
function newNote(e:MouseEvent):void
{
for (var i:Number = 1; i<10; i++)
{
addChild(note);
//inpuText is a text field in notess movie clip
note.inputText.visible = false;
note.x = mouseX;
note.y = mouseY;
note.addEventListener( MouseEvent.MOUSE_DOWN , drag);
note.addEventListener( MouseEvent.MOUSE_UP , drop);
note.delet.addEventListener( MouseEvent.CLICK , delet);
}
}
function drag(e:MouseEvent):void
{
note.startDrag();
}
function drop(e:MouseEvent):void
{
e.currentTarget.stopDrag();
note.inputText.visible = true;
note.delet.visible = true;
}
function delet(e:MouseEvent):void
{
removeChild(note);
}
any help will be appreciated.
You need to create a new instance of your note class when you drop, copy the location and other variables from the note you were dragging, add your new note to the stage, and return the dragging note to its original position.
Something like:
function drop($e:MouseEvent):void
{
$e.currentTarget.stopDrag();
dropNote($e.currentTarget as Note);
}
var newNote:Note;
function dropNote($note:Note):void
{
newNote = new Note();
// Copy vars:
newNote.x = $note.x;
newNote.y = $note.y;
// etc.
// restore original note.
// You will need to store its original position before you begin dragging:
$note.x = $note.originalX;
$note.y = $note.orgiinalY;
// etc.
// Finally, add your new note to the stage:
addChild(newNote);
}
... this is pseudo-code really, since I don't know if you need to add the new note to a list, or link it to its original note. If you Google ActionScript Drag Drop Duplicate, you will find quite a few more examples.
I think you are not target the drag object in drag function and problem in object instantiation
for (var i:Number = 1; i<numberOfNodes; i++) {
note = new note();
addChild(note);
...
....
}
function drag(e:MouseEvent):void{
(e.target).startDrag();
}
If you are dragging around multiple types of objects (eg. Notes and Images), you could do something like this, rather than hard coding the type of object to be instantiated.
function drop(e:MouseEvent):void{
// Get a reference to the class of the dragged object
var className:String = flash.utils.getQualifiedClassName(e.currentTarget);
var TheClass:Class = flash.utils.getDefinitionByName(className) as Class;
var scope:DisplayObjectContainer = this; // The Drop Target
// Convert the position of the dragged clip to local coordinates
var position:Point = scope.globalToLocal( DisplayObject(e.currentTarget).localToGlobal() );
// Create a new instance of the dragged object
var instance:DisplayObject = new TheClass();
instance.x = position.x;
instance.y = position.y;
scope.addChild(instance);
}