Is there anyway I can effectively call the equiv. of setText on a Flex Graphics object ?
Specifically I'm using a custom cell renderer to display data in a datagrid. The renderer uses the Graphics object to set the background colour of only a portion of the cell (say the left half) based upon the underlying data. I would like to be able to have text over only that portion of the cell which has the background colour (eg centred within the left half).
I know all the widths (of both the cell itself and the graphics object) but I don't know how I can set text (centred) over the graphics object.
Anyone got any ideas pls?
Tks vm
Here's a solution that avoids adding UI components:
private function WriteText(text:String, rect:Rectangle):void
{
var uit:UITextField = new UITextField();
uit.text = text;
uit.width = rect.width;
var textBitmapData:BitmapData = ImageSnapshot.captureBitmapData(uit);
var matrix:Matrix = new Matrix();
var x:int = rect.x;
var y:int = rect.y;
matrix.tx = x;
matrix.ty = y;
graphics.beginBitmapFill(textBitmapData,matrix,false);
graphics.drawRect(x,y,uit.measuredWidth,uit.measuredHeight);
graphics.endFill();
}
The idea is to use the UITextField to create a bitmap, that can be used with the graphics object to fill a rectangle.
This is based on a blog post by Olga Korokhina at Adobe Developer Connection.
The short answer is that you can't draw text programmatically with a Graphics object. What you'll need to do is create one of the Text-like classes (e.g. Label, Text, etc.) and position that appropriately within your cell renderer.
Assuming that you're doing your custom painting in updateDisplayList, you'd want to do something like the following:
override protected function updateDisplayList( unscaledWidth:Number, unscaledHeight:Number ):void
{
super.updateDisplayList( unscaledWidth, unscaledHeight );
// perform all your custom painting
var label:Label = new Label();
label.text = "Some text";
label.width = widthOfCustomPainting;
// can also set x- and y-coordinates of label too
label.setStyle( "textAlign", "center" );
this.addChild( label );
}
This will need some tweaking based on how your item renderer is set up, but it should pretty much be what you need.
Note that my code above does not use best practices for custom item renderers. It would be worthwhile to take a look at this excellent blog post which describes how to properly create item renderers.
Polygonal labs comes up with a solution that convert the font to vector curves so that you can draw the text as graphics. See it here. The code has not been published, but you can see some similar projects in the comments.
But you will need to do it in AS instead of MXML or you write you own class for that.
using textformat for uit's defaulttextformat is the solution of my problem...
Related
I hope someone will be able to help here, so first of all though let's take a look at exactly what my problem is ...
I would have liked to insert a movieclip from an external swf into my textarea but I think it isn't as easy as I thought... because the Textarea,TextFlow components are unfortunately almost unusable to me in this respect ..
I have read the API of Textarea and TextFlow , and I searched a lot on Google and some forums, but I have not found the solution to my problem.
I have found similar topics to this one like as :
Using symbol from library in htmlText <img> tag in ActionScript 3
http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00000322.html
I have tried several ways to refer to the symbol but to no avail...
Here is my code :
[Bindable]
/**
* The text which will be displayed
**/
public var pblMessages:String = "";
<s:TextArea id="pblArea" left="10" right="242" top="241" bottom="55" editable="false"
textFlow="{TextConverter.importToFlow(pblMessages,TextConverter.TEXT_FIELD_HTML_FORMAT)}"
valueCommit="pblAreaCommitHandler(event)">
</s:TextArea>
Method for adding new line :
private function submitText(keyPress:Boolean=false) :void {
if (pblInput.text=="") {
pblInput.setFocus();
return;
}
var format:ElementFormat = new ElementFormat();
var fontDescription:FontDescription = new FontDescription("Arial");
format.fontSize = 11;
format.fontDescription = fontDescription;
var s:String = pblInput.text;
var re: RegExp = new RegExp("\r|\n","gi");
s = s.replace(re,"");
var inlineGraphicElement:InlineGraphicElement = new InlineGraphicElement();
inlineGraphicElement.source = Smileys.smi_kiss;
var p:ParagraphElement = new ParagraphElement();
p.addChild(inlineGraphicElement);
//pblArea.textFlow.addChild(p);
pblMessages += "<font color='#000000'>" + s + "</font><img src='assets/testmovie.swf#smi_kiss' width='20' height='20'/><br/>";
pblInput.text="";
}
If the smiley is displayed on the first frame in the swf, then it displayed (without symbol) too in the TextArea of course.. but I don't want to make 100 different swf file.. I'm quite sure that the smileys can be displayed by using symbols.
Thank you in advance for your help.
Try to create complete TextFlow without using TextConverter.importToFlow. After adding inlineGraphicElement to p, you should add a SpanElement to p, and then add text to SpanElement.text, and then assign a textFlow to pblArea.textFlow.
I have a component which inherrits Group. I made a property called dataSource:ArrayList. I wish to draw a Line for each of the entries.
When the 'function set dataSource' -method is invoked I do the following (simplified):
var newLine:Line = new Line();
newLine.stroke = new SolidColorStroke();
newLine.xFrom = 0;
newLine.yFrom = 0;
newLine.xTo = 0;
newLine.yTo = height;
this.addElement(newLine);
The line doesn't stretch itself to the very bottom of the parent. I'm guessing I'm messing up life cycle, but I'm not finding flex life cycle particular easy to understand, so I'm not sure how to go about this.
If you don't want to interact with the line as an object on the display list, I'd simply draw it in updateDisplayList() using the Graphics api, and call invalidateDisplayList() from set dataSource()
The "right" way is slightly more verbose ;-)
private var dataSourceValid = true;
public function set dataSource(value:FooData):void {
_dataSource = foo;
dataSourceValid = false;
invalidateProperties();
}
override protected function commitProperties():void {
if (!dataSourceValid)
commitDataSource();
// Do it later in case we've invalidated something
// belonging to Flex while validating our stuff
super.commitProperties();
}
protected function commitDataSource():void {
// Do whatever we need to with our datasource,
// including adding or removing child elements.
// ...
// If we also need to re-draw something, then
// invalidateDisplayList();
dataSourceValid = true;
}
(All code typed in TextMate, so it's probably full of spelling errors and doesn't compile, but you get the idea)
I agree with you, it probably has to do with the component not being properly measured yet when you create your lines. You could try overriding updateDisplayList and setting the height of the lines you created to be the height parameter supplied to the updateDisplayList method. Don't create the lines in updateDisplayList since it can get called multiple times during the component life cycle. Regarding the life cycle in general, here's a link to a chart I've found helpful in the past: http://danorlando.com/?p=122 Hope that helps.
It isn't entirely clear what you're looking to do, but by putting a dataSource property on Group it appears as if you're trying to re-invent DataGroup. Perhaps you should consider just using the latter instead, along with a custom ItemRenderer within which you could draw a line?
I'm having a problem similar to FLEX: dialog not display immediately . Code follows:
private function saveBitmap(event:ContextMenuEvent):void
{
loadingScreen.visible = true;
loadingScreen.appLoadingText.text = "Preparing bitmap...";
addChild(loadingScreen);
validateNow();
var bmpd:BitmapData = new BitmapData(canv.width, canv.height);
bmpd.draw(canv);
var fr:FileReference = new FileReference();
fr.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, removeLoadingScreen);
fr.addEventListener(Event.CANCEL, removeLoadingScreen);
var png:PNGEncoder = new PNGEncoder();
var iba:ByteArray = png.encode(bmpd);
fr.save(iba, "export.png");
}
Basically, bmpd.draw and/or png.encode are dog slow, so I'd like to have a nice "please hold while we prepare your png" dialog to appear. I can't use callLater() because of the FileReference.
And just for good measure, the loading screen appears at the same time the save dialog appears from the call to fr.save().
Any ideas?
Cheers!
You're adding the child in this function. Are you doing any other work to the loadingScreen, such as sizing it? Or positioning it? Most commonly this is done in updateDisplayList(). What container are you using?
Are you sure the Z-order of your two children is correct? You can swap children with the swapChildren method
I'm a beginner in Flex so there must be more elegant way of doing this.
//move effect
private var m:Move = new Move();
//this function creates labels with some text and starts move effect on them
public function moveText(i:int):void {
var myLabel:Label = new Label();
myLabel.text = "some text";
m.target = myLabel;
...
m.play();
}
Method moveText is called in a loop so I guess that labels don't get "garbage collected".
What I want to do is to remove Labels created in moveText method after play animation ends.
Another way of doing this is maybe creating some kind of "pool" of labels which I would use to move arround text. I don't know how would I return labels in to "pool".
The question is how to do something after effect animation ends?
You can listen to the EffectEnd event.
Check out here
Look at the effectEnd event in the Effect class. You can put a handler in there that does your garbage collection.
I've reviewed all the documentation and Google results surrounding this and I think I have everything setup correctly. My problem is that the symbol is not appearing in my app. I have a MovieClip symbol that I've embedded to my Flex Component. I need to create a new Image control for each item from my dataProvider and assign this embedded symbol as the Image's source. I thought it was simple but apparently not. Here's a stub of the code:
[Embed(source="../assets/assetLib.swf", symbol="StarMC")]
private var StarClass:Class;
protected function rebuildChildren():void {
iterator.seek( CursorBookmark.FIRST );
while ( !iterator.afterLast ) {
child = new Image();
var asset:MovieClipAsset = new StarClass() as MovieClipAsset;
(child as Image).source = asset;
}
}
I know the child is being created because I can draw a shape and and that appears. Am I doing something wrong? Thank you!
You should be able to simply set child.source to StarClass:
child = new Image();
child.source = StarClass;
See the MovieClipAsset Language Reference for more details:
you rarely need to create MovieClipAsset instances yourself
because image-related properties and
styles can be set to an
image-producing class, and components
will create instances as necessary.
For example, to set the application
background to this animation, you can
simply write the following:
<mx:Application backgroundImage="{backgroundAnimationClass}"/>