⬆️ ⬇️

First, but not easy steps in Flex

Not so long ago, I began my acquaintance with Flex Builder 3. Since I have been friends with programming for a long time and in every way, there were no problems with tasks like “Hello, world”, sorting an array and “how to make an image crawl on the button”. However, I met with tasks that, while outwardly simple, did not have simple solutions in the Flex environment.





For convenience, I highlighted four of the most interesting of them:

  1. Adding a variety of resources to the project;
  2. Multilingual application;
  3. Modal window;
  4. Flex and CSS.


Tasks are listed in decreasing order of difficulty. I will be glad if someone solved the same tasks easier (or differently than I do) and will describe these solutions in the comments.



1. Add multiple resources to a project



I very quickly found out that embedding files of any type into a Flex project is easy:

')

[Embed(source="index.xml", mimeType="application/octet-stream")]

private static var index_xml : Class;



[Embed(source="picture.png")]

private static var picture_png : Class;



Thus, at the time of execution of the application, we can access them simply by creating the necessary object, rather than loading the file from the network or from the local disk.



However, almost immediately I ran into an error:

1067: Implicitly casting an int to an inappropriate Class.



This error was given by the following code:



public class res {

[Embed(source="test.png")]

public static var test: Class;

public static var res_test: int;

}



As it turned out, for embedded resources, Flex generates intermediate AS classes. For the example above, the class was generated:



public class res_test extends mx.core.BitmapAsset {

public function res_test() {

super();

}

}



The useful compiler directive helped me figure it out: keep-generated-actionscript . If this directive is set to true , the compiler for all intermediate generated classes creates files in the src / generated / folder.



Having dealt with this problem, I thought about the following: how do I include a lot of embedded files? Not one or two, which can be entered by hand, but ten to twenty or more. Neither help, nor books, nor forums gave an answer. Honestly, I did not understand: either no one did this, or they did everything, but they are silent.



Since strings like [Embed (source = "folder \")] Flex stubbornly denied, I decided to go for the trick: archive the folder with resources. Thus, I get a file that I can include in the project, like any other. It was up to the class library for working with archives. Find such a library is not working. For example, AS3 Zip Library or FZip .



Now I could use any file from the archive when the application was executed. And in the archive I could put as many files as I like without any labor costs. It seems everything is as it should.



But no. Files from the archive are returned as ByteArray. If it is text files or binary data, then no problem. But if this image or, God forbid, swf, then begin dancing with a tambourine.



It just wasn't possible to convert ByteArray to BitmapData or BitmapAsset. There were not even converters for various data types: png, jpeg, swf, etc. Flex has PNGEncoder, JPEGEncoder and so on, but for some reason there is no PNGDecoder, JPEGDecoder.



After a little more help, I found the Loader class. This class has a loadBytes () method that takes a ByteArray parameter, automatically recognizes the content, and converts it to the desired Flex class.



Having resigned myself to the need to subscribe to the download completion event and somehow rip out my data from this component, I expected that they would “make me beautiful” now. It was not there.



Testing this option from under the Flex environment, I did not notice any problems. However, when I made a release and launched it, I got an error. Its essence was as follows: I do not have rights to access the file “My Application File.swf. << 1 >>. ByteArray ()” . In other words, I do not have permission to access my array. This is what shocked me.



Yes, I understand that if I did not set the use-network flag to false when compiling, then my application will not be able to use local files, if it does not belong to the trusted zone, or is not in the local-trusted sandbox, or does not fall under what else any rule of security flash player. But I don’t understand why my array, which I had just created and initialized myself, turned out to be some kind of local resource, which I still can’t access through the Loader!



Recovering, I decided to fight on. The next idea was to create some kind of add-on over Flex, which when compiled would convert strings like [Embed (source = “folder \”)] to class AS3, where all files from this folder would be explicitly listed with the embedded flag. The plugin was too lazy to write, and I did not find any macros in Flex. So I turned to a friend who writes in Java in the Eclipse environment. I reasoned that, since Flex is based on Eclipse, then perhaps solutions for Eclipse are also suitable for Flex.



After some thought, a friend suggested Apache Ant to me. For Java developers, it replaces make. At the same time, he can create unimaginable things with files and folders, run applications, edit text files and much more. Having picked up this utility a bit, I did not understand how to sharpen it under Flex, and time was already pressing. Therefore, I abandoned the idea of ​​using Apache Ant and I have only one way left (which I could think of) to achieve the desired.



And this way was to create a small application that would generate an AS3 file for a given folder. This idea appeared immediately, as soon as the task arose to include many files in the project, but I always tried not to notice it, hoping that there is a more harmonious solution.



In twenty minutes in C ++, I wrote a program that generates this AS3 file. The only problem that remains is not to forget to run this program when the resources in the folder change :). I do not cite the code of this program here, because it is primitive.



I still hope that someone will show me a more competent solution to the problem of including many resources in the project.



2. Multilingual application



Here I would like to describe the method I used to create a multilingual application. Flex has its own localization technology, with which you can create applications that support multiple languages. However, this technology was somewhat inconvenient for me, so I decided to go my own way.



The class has been created:



public class LanguageProvider {

private var fobj_languageData: Array = new Array();



public function Clear(): void {

fobj_languageData = new Array();

}



public function AddLanguageData(fileName : String): void {

var id : String = "";

var parent : XML = null;



for each (var item: XML in ResourcesManager.FileAsXML(fileName)..*.(hasOwnProperty("@value"))) {

id = item.name();

parent = item.parent();

while (parent != null) {

id = parent.name() + "." + id;

parent = parent.parent();

}

fobj_languageData[id] = item.@value;

}

}



public function GetStringFor(item : String): String {

var result: String = fobj_languageData[item];

if (result != null) return result; else return "<-!->";

}

}



A localization file was also created:

<menu value = "Menu">

<new value = "Create a new" />

<settings value = "Settings">

<sound value = "Sound" />

<music value = "Music" />

</ settings>

</ menu>



How is it better than the standard method:



What is worse than the standard method:



I do not pretend to the ultimate truth, but for me personally my approach is more convenient. Maybe someone else will come in handy.



3. Modal window



There is a need to create your modal "window". Like the "window" Alert. I write the word “window” in quotation marks because in reality it’s just panels, not windows per se. Of course, I got into the source code of the Alert class and got everything I needed from there.



<?xml version="1.0" encoding="utf-8"?>

<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="300">

<mx:Script>

<![CDATA[

import mx.managers.PopUpManager;

import mx.events.CloseEvent;

import mx.core.Application;



// private

private var fbol_init: Boolean = false;

private var fobj_closeHandler: Function = null;



// protected

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {

super.updateDisplayList(unscaledWidth, unscaledHeight);



if (!fbol_init) {

var x:Number;

var y:Number;



if (parent == systemManager) {

x = (screen.width - width) / 2;

y = (screen.height - height) / 2;

}

else if (parent != null) {

x = (parent.width - width) / 2;

y = (parent.height - height) / 2;

}

else {

x = (Application.application.width - width) / 2;

y = (Application.application.height - height) / 2;

}



// Set my position, because my parent won't do it for me.

move(Math.round(x), Math.round(y));

fbol_init = true;

}

}



// public

public virtual function Show(closeHandler:Function = null): void {

fobj_closeHandler = closeHandler;

if (closeHandler != null) this.addEventListener(CloseEvent.CLOSE, closeHandler);

PopUpManager.addPopUp(this, Sprite(Application.application), true);



}



public virtual function Close(): void {

PopUpManager.removePopUp(this);

fbol_shown = false;

dispatchEvent(new CloseEvent(CloseEvent.CLOSE));

if (fobj_closeHandler != null) removeEventListener(CloseEvent.CLOSE, fobj_closeHandler);

}



]]>

</mx:Script>

</mx:Panel>





It's very simple, but I hope someone will come in handy :).



4. Flex and CSS



It's no secret that Flex and CSS are friends. And they are very close friends. You can set the CSS for the entire application, and define in it what the buttons, panels, etc. will look like.



On the other hand, there is a component TextArea. This component has htmlText and styleSheet properties. Thus, HTML text can be placed in this component, and it will be displayed using the style specified in the styleSheet.



And now the question is: how can I for all TextArea in the application set the CSS with which the htmlText should be displayed inside them?



If we set the CSS for the entire application, and in it we prescribe what the TextArea will look like, then the text in this component will only look that way. If we describe some classes that are used in HTML text in TextArea, then these styles do not apply. Somewhat complicates all this is the fact that the TextArea styleSheet property is only available from AS3 and has no MXML analog.



Not finding a standard solution, I invented my own - I created a successor from TextArea:



<?xml version="1.0" encoding="utf-8"?>

<mx:TextArea xmlns:mx="http://www.adobe.com/2006/mxml"

width="100"

height="100"

creationComplete="OnCreationComplete()"

borderThickness="0"

editable="false"

horizontalScrollPolicy="off"

verticalScrollPolicy="off">



<mx:Script>

<![CDATA[

// static

private static var fobj_styleSheet : StyleSheet = null;



public static function SetStyleSheet(ss : StyleSheet):void {

fobj_styleSheet = ss;

}



// private

private function OnCreationComplete(): void {

if (fobj_styleSheet != null) this.styleSheet = fobj_styleSheet;

}

]]>

</mx:Script>

</mx:TextArea>



Apparently from the code, I defined a static field and a method at the successor. Now in applications I use not TextArea, but my successor. Somewhere in the application code, I once load the CSS object and pass it to the static function SetStyleSheet. It turns out that when creating all objects of this class, they now faithfully prescribe CSS for themselves.



I hope my experience will be useful to someone.



Thank you in advance for comments and additions :).

Source: https://habr.com/ru/post/43311/



All Articles