Solved

How do I create a rounded-corner textField component in AS3

Posted on 2011-03-03
17
2,046 Views
Last Modified: 2012-05-11
Hi,

I need to create labels with coloured round-cornered backgrounds.

I am creating a flash file that will be used as a base or template flash file by three designers (including myself) to create hundreds of informative SWF files.

These labels will vary in size (depending on the amount of text) but the font size and position of the text (the padding effectively) must always be consistent.

I found a good article here: http://stackoverflow.com/questions/1223606/as3-rounded-text-field

Unfortunately I am an OKish AS2 coder, who struggles with classes and am only recently migrating uncomfortably to AS3.

After looking online I worked out how to get the above code into a component but my knowledge is not sufficient to do much more with it.

What I want:
- AS3 component (hereby referred to as label component)  that I can drag from library or component panel into a scene
- label component to have a text entry box in the componenrt inspector
- label component to show in the scene
- text to appear in label component

Of the above, I have sort of got the first bit working:
I saved the package as TextBorder.as in a new folder, created an AS3 flash document called demo.fla.
In demo.fla I created a movieclip and then I clicked 'Component Definition' in library and associated the class with TextBorder.as
Also in library I clicked on properties and associated class with TextBorder.as

When I drag my moviclip into the scene and compile it I get a round corner box with a text field saying Hello World. Which I expected.

The instance of the component is invisible on the stage and only appears when you compile/ at runtime.

Additionally I can't alter the hello world text and I can't define anything in the component inspector.

---

My gap (many gaps) in knowledge is how do I take this package and create it into a component that I can see in my development environment (the stage). I have seen a bit about live preview but it asks for a swf and I can't provide one as the label is produced dynamically.

I tried to add a stylesheet element so I could control the text but it is not picking it up, again i am a real newbie at all of this and AS3 so probably getting it terribly wrong.

---

If component is not my best approach, anybody able to suggest a solid work around with moviclips with 9 point scaling? I can't see it working as elegantly as a component, especially as I would have to separate the text layer from the background to prevent the text from scaling etc.

---

Any help or examples please would be amazing thank you.

Kind regards,
Ady
/*code taken from http://stackoverflow.com/questions/1223606/as3-rounded-text-field

modified by myself to include a stylesheet (which doesn't work) and to add padding - which sort of does.
*/

package
{

import flash.display.Graphics;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
//Ady added---
import flash.text.Stylesheet;
//--- Ady end

public class TextBorder extends Sprite
{
    private static const CORNER_RADIUS:int = 5;
    // display objects
    private var background:Sprite;
    private var field:TextField;

    // properties
    private var _text:String;
    //Ady add---
    private var newStyleSheet:StyleSheet = new StyleSheet();
    //--- Ady end

    public function TextBorder()
    {
        background = new Sprite;
        field = new TextField;
        field.autoSize = TextFieldAutoSize.LEFT;

        //Ady added---
        var styleObj:Object = new Object();
        styleObj.fontWeight="bold";
        styleObj.color="#666666";
        newStyle.setStyle(".defStyle",styleObj)

        field.styleSheet = newStyle;
        field.htmlText="";
        //--- Ady end

        addChild(background);
        addChild(field);

        // TESTING:
        text = "Hello World";
    }

    public function set text(newText:String):void
    {
        _text = newText;
        display();
    }

    public function get text():String
    {
        return _text;
    }

    private function display():void
    {
        field.text = _text;

        //Ady add--
        var expX:Number = field.width+20;
        var expY:Number = field.height+20;
        //--- Ady end

        var g:Graphics = background.graphics;
        g.clear();
        //Ady add
        g.lineStyle(0.1,0x000000,0.5,true,"normal");
        //--- Ady end
        g.lineStyle(0, 0x0);
        g.beginFill(0xFFFFFF);
        //--- Ady end
        g.drawRoundRect(-10, -10, expX, expY, CORNER_RADIUS);
        //--- Ady end

        /* originally was this:
        g.drawRoundRect(0, 0, field.width, field.height, CORNER_RADIUS);
        */
    }
}

}

Open in new window

0
Comment
Question by:arasburn
  • 10
  • 7
17 Comments
 
LVL 17

Expert Comment

by:deepanjandas
Comment Utility
Create a CustomTextField which should extend Sprite.

Now have a textFiled within and set all setters and getters in the class to set the properties of the textfield.

Have a base sprite where you draw the border using drawRoundedRect.

Hope this makes sense.

Warm Regards
Deepanjan Das
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Hi Deepanjandas,

I'm really sorry but I don't understand.

I am really new to classes, I used them a little in the past in AS2 but even then I think I was using them incorrectly or at least not how they were designed to be used. I really am trying to up my game and use them properly. I have never made a component before either so this is doubly confusing to me.

Would you mind leading me through your answer a little more please?

Do I make a new .as file called customTextField for example? How do I link it in please?

I'm so sorry I'm thick about all of this. I mainly have only ever done procedural type coding before. Objects and classes confuse the heck out of me.
0
 
LVL 17

Expert Comment

by:deepanjandas
Comment Utility
Okie, I will try to create a sample file for you shortly.

Warm Regards
Deepanjan Das
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Deepanjandas, that would be amazing of you thank you so much!
0
 
LVL 17

Accepted Solution

by:
deepanjandas earned 500 total points
Comment Utility
My pleasure...
The base component class:
package com.dd.controls.core
{
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	
	public class Component extends Sprite
	{
		// ------------------------------------------
		// PROPERTIES
	    // isSuspended starts as true as the component is off stage
	    protected var _isSuspended:Boolean = true;

		protected var _width:Number = 0;
		protected var _height:Number = 0;
		
		public static const DRAW:String = "compDrawComplete";

		/**
		 * Constructor
		 */
		public function Component():void
		{
			super();
			
			if (stage) { 
				resume(); 
			}else {
				init(); 
			}
		}
		
		
		///////////////////////////////////
		// PROTECTED METHODS
		///////////////////////////////////
		protected function init():void
		{
		  // concrete classes that override this function should call super.init()
		  // n.b. These events require Flash Player 9.0.28.0
		  addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true);
		  addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage, false, 0, true);
		  
		  // initialise component here.
		  // no need to call draw() as it will be called when component is added to the stage.
		}
		
		/**
		 * Overriden in subclasses to create child display objects.
		 */
		protected function createChildren():void
		{
			// defining component elements
		}
		
		protected function invalidate():void
		{
			if(!hasEventListener(Event.ENTER_FRAME))
				addEventListener(Event.ENTER_FRAME, onInvalidate, false, 0, true);
		}
		
		protected function draw():void
		{
			// concrete classes should override this function
			// redraw component state
			dispatchEvent(new Event(Component.DRAW));
		}
		
		protected function suspend():void
		{
		  // concrete classes that override this function should call super.suspend()
		  // suspend all processes
		  removeEventListener(Event.ENTER_FRAME, onInvalidate);
		  removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
		  this._isSuspended = true;
		}
		
		public function resume():void
		{
		  // concrete classes that override this function should call super.resume()
		  // resume all processes
		  this._isSuspended = false;
		  createChildren();
		  invalidate();
		}
		
		public function get isSuspended():Boolean
		{
			return _isSuspended;
		}
		
		/**
		 * Moves the component to the specified position.
		 * @param xpos the x position to move the component
		 * @param ypos the y position to move the component
		 */
		public function move(xpos:Number, ypos:Number):void
		{
			x = Math.round(xpos);
			y = Math.round(ypos);
		}
		
		/**
		 * Sets the size of the component.
		 * @param w The width of the component.
		 * @param h The height of the component.
		 */
		public function setSize(w:Number, h:Number):void
		{
			_width = w;
			_height = h;
			invalidate();
			dispatchEvent(new Event(Event.RESIZE));
		}
		
		///////////////////////////////////
		// getter/setters
		///////////////////////////////////
		
		/**
		 * Sets/gets the width of the component.
		 */
		override public function set width(w:Number):void
		{
			_width = w;
			invalidate();
			dispatchEvent(new Event(Event.RESIZE));
		}
		override public function get width():Number
		{
			return _width;
		}
		
		/**
		 * Sets/gets the height of the component.
		 */
		override public function set height(h:Number):void
		{
			_height = h;
			invalidate();
			dispatchEvent(new Event(Event.RESIZE));
		}
		override public function get height():Number
		{
			return _height;
		}
		
		/**
		 * Overrides the setter for x to always place the component on a whole pixel.
		 */
		override public function set x(value:Number):void
		{
			super.x = Math.round(value);
		}
		
		/**
		 * Overrides the setter for y to always place the component on a whole pixel.
		 */
		override public function set y(value:Number):void
		{
			super.y = Math.round(value);
		}
		
		
		///////////////////////////////////
		// EVENTS
		///////////////////////////////////
		private function onInvalidate(e:Event):void
		{
			removeEventListener(Event.ENTER_FRAME, onInvalidate);
			draw();
		}

		private function onAddedToStage(e:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			resume();
		}

		private function onRemovedFromStage(e:Event):void
		{
			suspend();
		}
		
	}
}

Open in new window


Now the custom textfield component extending the base class:
package com.dd.controls
{	
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	
	import flashx.textLayout.formats.TextAlign;
	
	public class CustomTextField extends Component
	{
		protected var base:Sprite;
		protected var textField:TextField;
		
		protected var _textFormat:TextFormat = new TextFormat();
		protected var _text:String = "";
		protected var _type:String = "input";
		protected var _displayAsPassword:Boolean = false;
		protected var _enabled:Boolean = true;
		protected var _border:Boolean = false;
		protected var _padding:int = 5;
		protected var _maxChars:int = 0;
		protected var _restrict:String;
		protected var _cornerRadius:int = 0;
		
		public function CustomTextField()
		{
			name = "CustomTextField";
			
			_width = 40;
			_height = 24;
			
			super();
		}
		
		override protected function init():void
		{
			_textFormat.font = "Arial";
			_textFormat.size = 14;
			_textFormat.bold = false;
			_textFormat.leftMargin = 2;
			
			super.init();
		}
		
		override protected function createChildren():void
		{
			base = new Sprite();
			addChild( base );
			
			textField = new TextField();
			if( _restrict ){
				textField.restrict = _restrict;
			}
			textField.tabEnabled = true;
			textField.mouseEnabled = true;
			textField.type = _type;
			textField.borderColor = 0xFF0000;
			textField.border = _border;
			textField.displayAsPassword = _displayAsPassword;
			textField.multiline = false;
			textField.wordWrap = false;
			textField.embedFonts = true;
			textField.defaultTextFormat = _textFormat;
			
			if( _maxChars > 0 ) {
				textField.maxChars = _maxChars;
			}
			
			textField.width = _width - ( _padding * 4 );
			textField.height = _height - ( _padding * 4 );
			textField.x = _padding * 2;
			textField.y = _padding * 2;
			
			addChild( textField );
		}
		
		override protected function draw():void
		{
			
			super.draw();
			
			if( base == null )
				return;
			
			var baseGraphic:Graphics = base.graphics;
			baseGraphic.clear();
			baseGraphic.lineStyle( 1, 0x000000, 0.5 );
			baseGraphic.beginFill( 0xCCCCCC, 0.0 );
			baseGraphic.drawRoundedRect( 0, 0, _width, _height, _cornerRadius, _cornerRadius );
			baseGraphic.endFill();
			
			textField.type = _type;
			textField.displayAsPassword = _displayAsPassword;
			textField.setTextFormat( _textFormat );
			textField.text = _text;
			
			//textField.height = _height - ( _padding * 2 );
			textField.autoSize = "left";
			
			textField.width = _width - ( _padding * 2 );
			textField.autoSize = "none";
			
			textField.x = _padding;
			textField.y = ( _height - textField.height ) / 2;
		}
		
		
		public function set text( value:String ):void
		{
			_text = ( value == null ) ? "" : value;
			
			if( textField != null )
				textField.text = _text;
			
			
			invalidate();
		}
		
		public function get text():String
		{
			_text = textField.text;
			return _text;
		}
		
		public function set cornerRadius( value:int ):void
		{
			_cornerRadius = value;
			
			invalidate();
		}
		
		public function set type( value:String ):void
		{
			_type = value;
			
			if( textField != null )
				textField.type = _type;
		}
		
		public function set displayAsPassword( value:Boolean ):void
		{
			_displayAsPassword = value;
			
			invalidate();
		}
		
		public function set defaultTextFormat( value:TextFormat ):void
		{
			_textFormat = value;
			_textFormat.font = "Arial";
			
			invalidate();
		}
		
		public function set restrict( value:String ):void
		{
			_restrict = value;
		}
		
		public function get enabled():Boolean
		{
			return _enabled;
		}
		
		public function set enabled( value:Boolean ):void
		{
			_enabled = value;
			if( _enabled ) {
				alpha = 1.0;
				textField.selectable = true;
				type = "input";
			} else {
				alpha = 0.7;
				textField.selectable = false;
				type = "dynamic";
			}
		}
		
		public function set border( value:Boolean ):void
		{
			_border = value;
		}
		
		public function set maxChars( value:int ):void
		{
			_maxChars = value;
		}
		
		public function get maxChars():int
		{
			return _maxChars;
		}
		
		public function get text():String
		{
			return text;
		}
		
		public function set text( value:String ):void
		{
			text = value;
			
		}
	}
}

Open in new window


This is just a basic start. So you need to develop on top of this.

Warm Regards
Deepanjan Das
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Hi Deepanjan,

I can only echo what I said earlier, thank you so much for taking the time to do this.

I'm going to type in your code and see what happens. Please may I call on you again if I get stuck, I'm still a little unclear about this.

Cheers,
Ady
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Hi Deepanjan,

I have created a new folder (called label). Inside this folder I have created a folder structure of com\dd\controls\core.

I have created 2 .as files one called Component.as and one called CustomTextField. Both these .as files are in the core folder.

In the top level folder (label) I have created an AS3 flash file unorriginally called demo.fla.

I have written in the first frame of demo.fla:
import com.dd.*;

I'm embarrassed to admit at this point I'm now totally stuck.

I have read your code and the minutiae of each bit pretty much makes sense to me, but lloking at it as the two separate chunks of code is baffling me.

I don't know if I am meant to create a dynamic text field and turn it into a component as I had done in my own earlier attempts or if I need to make a movieClip or whatever.

Please would you mind guiding me through this bit? I am so desparate to understand it but it feels too big a project to cut my teeth on. In hindsight I should start on something much smaller, but I do need to achieve the result I set out to do and I believe components are my best approach to do this.

I clearly need to learn more about AS3 and classes etc.

If you don't have time to help then I totally understand, you have already done loads and definitely will get full points.

Thank you again,
Ady
0
 
LVL 1

Author Closing Comment

by:arasburn
Comment Utility
Deepanjan has been amazing and has given me some amazing code, unfortunately I don't fully know how to use it. I am 100% confident it will work. I just need to work out how.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 17

Expert Comment

by:deepanjandas
Comment Utility
Okie, here you go:
The package structure will be like this:

- projectDir
        |__ com
        |        |__ dd
        |                |__ controls
        |                           |__ CustomTextField.as
        |                           |__ core
        |                                    |__ Component.as
        |__ demo.fla

Now in demo.fla place this code:
//imports
import com.dd.*;

var myTextField:CustomTextField = new CustomTextField();
myTextField.cornerRadius = 16;
myTextField.text = "Hello World!"
myTextField.setSize( 200, 30 );
addChild( myTextField );

Open in new window


Remember, you might need to tweak or update the CustomTextField class to as per your requirements.

Warm Regards
Deepanjan Das
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Hi Deepanjan,

Firstly thank you so much for your last post. I had set the folder structure up as indicated, although I had originally placed the cutomtextfield.as field in the core folder.

I have everything set up as you described above, and I placed the code in that you listed.

I get the following errors:
1046: Type was not found or was not a compile-time constant: CustomTextField.
1180: Call to a possibly undefined method CustomTextField.

I know this is a huge imposition, but please can you advise me what I am doing wrong. I am very aware that you are effectively doing this all for me, my coding skill does not cover this area and as such I feel very out of my depth.

I have just enrolled in an Open University to study programming, so in time I am confident that I would be able to do all of this sort of thing on my own, but right now - I am struggling massively.

I just can't see how this will become a component. I'm happy to raise this as a related question or post a new question to assign you more points.

Kind regards and thank you again for taking the time and effort to help me
0
 
LVL 17

Expert Comment

by:deepanjandas
Comment Utility
@arasburn, it is my pleasure in providing solutions, so points does not always matter.
I believe that I also learn while providing solutions.

Anyways, coming back to the problem.

May be add this as import:

import com.dd.controls.CustomTextField;

Let me know.

Warm Regards
Deepanjan Das
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Hi Deepanjan,

Again thank you for your continued support. I tried the above line, no joy.

At this stage I thought it might be wise for me to upload my file in case you wouldn't mind having a look at it please.

Zip file contains the demo.fla and the folder structure as outlined in your previous comment and the subsequent AS files.

Thank you again,
Ady label.zip
0
 
LVL 17

Expert Comment

by:deepanjandas
Comment Utility
Here you go:demo.zip

Warm Regards
Deepanjan Das
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Hi Deepanjan,

Thank you for taking the time to look at my files again. I downloaded your demo.zip and tried to compile it. I experienced the following error:
CustomTextField.as line 10  1172: Definition flashx.textLayout.formats:TextAlign could not be found.
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Hi Deepanjan,

I wrote you a massive reply and it got truncated. Sorry the above comment appeared so short.

More to follow; I wrote this 3 times now and it has not uploaded it... will do it in chunks.

Cheers,
Ady
0
 
LVL 1

Author Comment

by:arasburn
Comment Utility
Hi Deepanjan,

As mentioned above I experienced a problem with line 10 of the CustomTextField.as file, the flashx import, and commented it out - after doing so, the file compiled fine.

Ideally is there a way to include the flashx line please? From looking at your code I can see it is important as it helps define the look of the label.

Once again Deepanjan, I just want to say how much I appreciate all you have done. It is really cheeky of me to ask this, but please can you help some more? In my original post I was trying to create a component, and whilst I understand that is what you have produced for me, I was hoping / aiming to have it in a more designer friendly state. There are three of us on the project, and I laughably have the most programming experience, my colleagues have zero. I was hoping to have a component that could be pulled out of the component library and used with the component inspector, ideally with a livePreview so they/we could properly layout these labels within the scene. If you could make that final leap and show me how you take all the code you have done so far and turn it into such a component I would really appreciate it; as the code stands, I'm confident my colleagues will unfortunately not be able to use it.

As a small aside, I noticed in your bio that you have created some commercial components for flashcomponents.net, I strongly suggest you consider turning the work you have kindly done for me into such a component, I am confident that people would want to buy it. Before I came onto experts exchange with the naive belief I could make my own component I had scoured the net looking for a component I could buy and couldn't find one! Anyway, is just a thought :)

Kind regards Deepanjan, and again, thank you so much!
Ady
0
 
LVL 17

Expert Comment

by:deepanjandas
Comment Utility
Thanks Ady for your suggestion :) I will keep this in mind for sure.

Just remove that import, not sure how that came along.
Rest will work.


Warm Regards
Deepanjan Das
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

I hope you'll find this tutorial useful and interesting. So let's try to extend Tcl with a new package.  For anyone more deeply interested please check out the book "Practical Programming in Tcl and Tk". It's really one of the best written books abo…
I made this because I wanted to get e-mail with a attached csv file so I'd would be able to import user input into a MS Excel template, but I also wanted to register/save all inputs from each day in a file on the server. 1st - It creates a temp C…
The goal of the tutorial is to teach the user what frame rate is, how to control it and what effect it has on the video.
This Micro Tutorial will teach to how to utilize bit rate in Adobe Flash Media Live Encoder.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now