ALK Armando Leopoldo Keller


Movendo o Blog
10 Abril, 2009, 7:42 pm
Arquivado em: AS 2.0

Bom, acho que ja era tempo de mudar o blog de lugar.

Novo endereço: http://armandokeller.com/blog

apartir de hoje eu só postarei no endereço novo.

Lembro que copiei boa parte dos posts antigos para o novo endereço.



Conexão AS3 com python via socket (simplificado)
17 Janeiro, 2009, 2:30 pm
Arquivado em: AIR, AS 3.0, Flash geral, Flex, Socket, conexao, python | Tags: , , , ,

Algumas vezes me perguntei como fazer algumas coisas mais complexas em AIR de uma maneira rapida e segura, como por exemplo pegar informaçoes do usuario, conectar com um banco de dados (sem ser o nativo do AIR) como oracle,mssql… executar linha de comando, e outras coisas que só seriam possiveis utilizando alguma outra linguagem mais poderosa. Levando em conta que isto realmente era necessario para aumentar o “poder” do AIR e que o AMF fazia algo parecido, só que para a internet, resolvi criar uma classe em AS e uma função em Python que facilita a comunicação entre os dois (deixe o servidor python rodando de fundo e chame as funçoes dele :D )

Primeiro a classe Python.as que pode ser baixada aqui :

package
{
    import com.adobe.serialization.json.JSON;
    import flash.net.Socket;
    /**
     * Classe para conexao com python utilizando socket
     * @author    Armando Leopoldo Keller - (http://alkeller.wordpress.com) - alkeller@live.de
     */
    public class Python extends Socket
    {
        // TODO: Implementar um metodo de retorno, verificando o tipo do retorno, e passando como parametro na funcao associada
        /**
         * Cria um novo Socket
         * @param host    Host onde esta o socket
         * @param port    Porta que esta o socket
         * @see flash.net.Socket
         * @usage    var p:Python = new Python("10.1.1.23",2727);
         */
        public function Python(host:String=null, port:uint=0)
        {
            super(host, port);
            host = null;
            port = 0;
        }
        /**
         * Chama uma funcao do python se o socket estiver conectado 
         * @param func    Nome da funcao a ser chamada no python
         * @param args    Argumentos a serem chamados no python
         * @usage p.call("teste",{um:1,dois:2,tres:3});
         * @usage p.call("teste");
         */
        public function call(func:String,args:Object=null):void
        {
            if(this.connected)
            {
                this.flush();
                var obj:Object = new Object();
                obj["funcao"] = func;
                for(var i:* in args)
                {
                    if(args[i] is String) args[i] = "'"+args[i]+"'"
                    obj[i]=args[i];
                }
                this.writeUTFBytes(JSON.encode(obj));
                obj = null;
            }
            else
                throw new Error("Voce deve estar conectado ao socket.")
            this.flush();
        }
    }
}

Depois é necessario a função em python que vai reconhecer o que está sendo chamado pelo flash, o arquivo pode ser baixado aqui :

import json;
def executar(objeto):
    __arr__ = [];
    __str__ = "";
    obj = json.loads(objeto);
    __str__ = str(obj["funcao"])+"(";
    obj.pop("funcao");
    if len(obj.keys()) >= 1:
        for k in obj:
            __arr__.append(str(k)+"="+str(obj[k]));
        for x in xrange(len(__arr__)-1):
            __str__ = __str__+__arr__[x]+",";
        __str__ = __str__ +__arr__[len(__arr__)-1]+")";
    else:
        __str__ = __str__+")";
    return __str__;

Agora precisamos de um “servidor socket” rodando de fundo com as funçoes a serem chamadas, que pode ser baixado aqui :

import socket
import threading
import json
from JMF import executar
class ClientThread ( threading.Thread ):
    def __init__ ( self, channel, details ):
        self.channel = channel
        self.details = details
        threading.Thread.__init__ ( self );
    def run ( self ):
        print 'Conexao recebida: ', self.details [ 0 ]
        self.channel.send ( "resposta vinda do python" )
        for x in xrange ( 10 ):
            string = self.channel.recv ( 1024 )
            self.interpretaComando(string)
        self.channel.close();
        print 'Conexao fechada: ', self.details [ 0 ]
    def interpretaComando(self,string):
        eval("self."+executar(str(string)));
    def testar(self,arg1,arg2):
        print "Chamou testar: "+str(arg1)+","+str(arg2);
        self.channel.send("Chamou testar: "+str(arg1)+","+str(arg2));
    def pegaVariaveis(self):
        print "chamou pegaVariaveis"
        self.channel.send("chamou pegaVariaveis");
    def pegarArray(self):
        print "Chamou pegar Array";
        arr = ['a','b','c',1,2,3];
        txt = json.dumps(arr);
        self.channel.send(txt);
    def pegarObj(self):
        print "Chamou pegar Objeto";
        teste = {}
        teste["item1"]   =   "Primeiro item";
        teste["item2"]   =   "Segundo item";
        teste["numero"]  =   2;
        self.channel.send(json.dumps(teste));
# Inicia o servidor
server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( socket.gethostbyname(socket.gethostname()), 2727 ) )
server.listen ( 5 )
print "Iniciando servidor..."
while True:
    channel, details = server.accept()
    ClientThread ( channel, details).start()
Pronto, agora só falta uma aplicação de exemplo chamando estas funçoes, que pode ser baixada aqui :
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication applicationComplete="iniciar()" xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
            import com.adobe.serialization.json.JSON;
            private var py:Python
            [Bindable]
            public var texto:String = ""
            public function iniciar():void
            {
                py = new Python();
                py.addEventListener(ProgressEvent.SOCKET_DATA,onRecebe);
                py.addEventListener(Event.CONNECT,onConecta);
                py.addEventListener(IOErrorEvent.IO_ERROR,onErroIO);
                py.connect("10.1.1.3",2727);
            }
            public function onRecebe(e:ProgressEvent):void
            {
                var str:String = py.readUTFBytes(py.bytesAvailable);
                texto = str;
                py.flush();
            }
            public function onConecta(e:Event):void
            {
                trace("Conectou")
            }
            private function chamarTeste():void
            {
                if(py.connected)
                    py.call("testar",{arg1:"Argumento 1",arg2:"Argumento 2"})
                else
                    texto = "O socket esta desconectado";
            }
            private function chamarPegaVariaveis():void
            {
                if(py.connected)
                    py.call("pegaVariaveis")
                else
                    texto = "O socket esta desconectado"
            }
            private function pegarArray():void
            {
                if(py.connected)
                    py.call("pegarArray");
                else
                    texto = "O socket esta desconectado";
            }
            private function pegarObj():void
            {
                if(py.connected)
                    py.call("pegarObj");
                else
                    texto = "O socket esta desconectado";
            }
            private function matarServer():void
            {
                py.close();
                texto = "Desconectado"
            }
            public function onErroIO(e:IOErrorEvent):void
            {
                trace("Erro ao conectar com o socket");
            }
        ]]>
    </mx:Script>
    <mx:VBox>
        <mx:HBox>
            <mx:Button label = "Testar"         click = "chamarTeste()"            />
            <mx:Button label = "PegaVar"         click = "chamarPegaVariaveis()"    />
            <mx:Button label = "pegarArray"     click = "pegarArray()"            />
            <mx:Button label = "pegarObj"         click = "pegarObj()"            />
            <mx:Button label = "Kill Server"    click = "matarServer()"            />
        </mx:HBox>
        <mx:Text text="{texto}" width="100%" height="115"/>
    </mx:VBox>
</mx:WindowedApplication>

Claro que esta aplicação ainda está bastante simples, mas o objetivo é demonstrar como pode ser facil conectar o AS3 com Python utilizando socket, para quem não conhece python, vale a pena dar uma estudada, é uma linguagem muito util, poderosa, e simples, que é utilizada em diversos lugares, alguns exemplos bons são nasa e google (precisa mais ? ), agora mistura isso com AS3  (tem algo MUITO funcional e bonito).

Explicação rapida

A sintaxe é muito parecida com a Tweener (classe de tween) que ja é bastante conhecida, então creio que não deve ter muita dificuldade para utilizar esta classe. Sendo que para chamar uma função do python é só chamar     instancia.call(“nome_da_funcao”,{nome_do_argumento:valor_do_argumento…….});

Se alguem tiver alguma duvida, ou sugestão para esta classe ou para futuras classes, deixe um comentario ou envie por email mesmo.

A formatação dos codigos ainda  não está boa, mas esta melhorando (plugin do Windows Live Writer)  se alguem conhecer algum plugin para formatar codigos que tenha suporte a AS, Python, PHP,e C  me avisa.



JSFL para converter png e jpg para swf (até 92% de compressão)
20 Dezembro, 2008, 11:22 am
Arquivado em: Flash geral, JSFL

Aproveitando as ferias da faculdade e essa parada de final de ano para trazer mais um JSFL desta vez realmente util.

O que ele faz:

- Abre 3 janelas, a primeira para escolher em que pasta estão as imagens a serem convertidas, a segunda para ver onde vão ser salvos os swf , e a terceira para ver onde vão ser salvos os flas (essa pode ser cancelada caso não precise dos flas)

- Para cada imagem da pasta selecionada na primeira janela, ele vai criar um fla novo, importar a imagem, redimensionar o palco, colocar allowsmooth, e exportar o swf, se optou por salvar so flas, ele ira salvar o fla na pasta selecionada, caso contrario ira fechar o fla e ir para a proxima imagem.

Resultados:

- Com alguns testes que eu fiz nas ultimas semanas a compressão dos arquivos chegou até 92% (isso faz uma boa diferença em qualquer site).

- Está facil de usar, qualquer um consegue usar, pois o jsfl faz tudo praticamente sozinho.

O JSFL:

Salve o codigo a seguir em como um arquivo jsfl:

/*
* JSFL para converter imagens para swf
* Importa a imagem em um fla novo, e exporta o swf com a imagem. (redução de até 92% no "peso do arquivo")
* @author Armando Leopoldo Keller (alkeller@live.de) http://alkeller.wordpress.com
*
* Quem utilizar esta classe, favor enviar um email para ALKELLER@LIVE.DE com o "peso" das imagens antes e depois de serem exportadas.
*
*/

var fotosURI = fl.browseForFolderURL("Armando Leopoldo Keller(alkeller@live.de)\n \nSelecione a pasta das imagens.\n ");
var swfsURI = fl.browseForFolderURL("Armando Leopoldo Keller(alkeller@live.de)\n \nSelecione a pasta dos swfs.\n ");
var flasURI = fl.browseForFolderURL("Armando Leopoldo Keller(alkeller@live.de)\n \nSelecione a pasta dos flas.\n ");

var fileMask1 = "*.png";
var fileMask2 = "*.jpg";

var list1 = FLfile.listFolder(fotosURI + "/" + fileMask1, "files");
var list2 = FLfile.listFolder(fotosURI + "/" + fileMask2, "files");

function converte(list)
{
for(var i in list)
{
var doc = fl.createDocument();
doc.importFile(fotosURI+"/"+list[i],true);
var it = doc.library.items[0];
it.quality = 80;
it.allowSmoothing = true;
doc.addItem({x:0,y:0},it);
var selecionado = doc.getTimeline().layers[0].frames[0].elements[0];
selecionado.x = 0;
selecionado.y = 0;
doc.width = parseInt(selecionado.width);
doc.height = parseInt(selecionado.height);
doc.frameRate = 1;
if(flasURI)
{
fl.saveDocument(doc,(flasURI+'/')+list[i].split(".png").join("").split(".jpg").join("")+'.fla',false);
}
doc.exportSWF(swfsURI+'/'+list[i].split(".png").join("").split(".jpg").join("")+'.swf',true);
doc.close(false);
}
}

if(fotosURI && swfsURI)
{
if(list1.length > 0)converte(list1); // png
if(list2.length > 0)converte(list2); // jpg
}
else
{
alert("Você deve selecionar todas as pastas.(a de .flas é opcional)")
}

Claro que ainda pode ser otimizado, assim que tiver mais tempo quero ver se otimizo ele.

Observaçoes importantes:

- Quando for converter pngs, exporte todos eles como interlaced (faça um batch no photoshop) assim ele não fica perguntando se quer importar como um bitmap flateado.

- Quem utilizar ele, favor mandar um email ou colocar aqui nos comentarios o tamanho dos arquivos convertidos antes e depois de converter (a soma de todos os arquivos) para motivos de estatistica e para ver se ainda tem como reduzir mais sem perder a qualidade da imagem.

Qualquer duvida é só colocar nos comentarios que eu respondo assim que tiver tempo.



BUG no flashplayer (votem para corrigirem)
30 Novembro, 2008, 10:23 pm
Arquivado em: Flash geral, flash player | Tags: , , ,

Bom, como devem ter percebido o blog está meio abandonado já faz algum tempo, mas isso devido a falta de tempo, trabalho + faculdade = no time :P , agora nas ferias da faculdade vou ter mais tempo para escrever aqui.

Hoje quero pedir a ajuda de toso os desenvolvedores que estão lendo o blog, para votarem para a adobe corrigir este bug ( http://bugs.adobe.com/jira/browse/FP-501 ) , este bug é muito incomodo para a entrada de textos em flash (formularios), quando o wmode esta transparente é impossivel digitar caracteres como “ãéíúê”… e todos os outros caracteres que precisam de duas teclas para serem inseridos como por exemplo teclados que possuem a tecla ç conseguem inserir a mesma, ja teclados como os de notebooks que precisa digitar ‘ + c para inserir o ç não é possivel usar ç nos campos :P aqui tem um exemplo do bug acontecendo ( http://www.5etdemi.com/blog/archives/2005/06/firefox-wmodetransparent-is-completely-screwy-and-breaks-textfields/ ).

Quem encontrar outro bug no flashplayer ( mas que tenha certeza que é no flashplayer e não no seu codigo, e nem algo que foi alterado por questoes de segurança) por favor, verifique se o bug ja foi reportado, se foi reportado, comente e vote para que ele seja corrigido (isso agiliza o processo), caso contrario reporte ele.

Desde ja, obrigado a todos os que votarem, e provavelmente agora em dezembro eu volte a postar com mais frequencia.

Ideia dos proximos posts: Como usar o debuger, inserir flash no flex, inserir flex no flash, performance no AS3 …. Se alguem tiver mais alguma sugestão, avisa por email, ou por comentario.



BUG com numeros no AS2 que foi ‘corrigido’ no AS3
20 Agosto, 2008, 11:31 pm
Arquivado em: AS 2.0, AS 3.0, Flash geral | Tags: , , , , ,

Não sei se alguem percebeu, mas no AS2 tinha um ‘erro’ se é que da para chamar assim, pois na documentação possui um exemplo.
Quando tem algum numero com 0 na frente ele convertia para octal. Agora no AS3 ele converte certo para decimal. É bom avisar, vai que alguem ta acostumado com o octal.
Exemplos e comparaçoes
Conversão da base:

// Execute isso:
trace(00000001)
trace(00000010)
trace(00000100)
trace(00001000)
trace(00010000)
trace(00100000)
trace(01000000)
trace("--------")
trace(Number("00000001"))
trace(Number("00000010"))
trace(Number("00000100"))
trace(Number("00001000"))
trace(Number("00010000"))
trace(Number("00100000"))
trace(Number("01000000"))
/*
Resultado em AS2:
1
8
64
512
4096
32768
262144
--------
1
8
64
512
4096
32768
262144

Em AS3:
1
10
100
1000
10000
100000
1000000
——–
1
10
100
1000
10000
100000
1000000
*/

Outro Exemplo, desta vez com erro:

// Executa
trace(08);
/*
Resposta em AS2: Erro de sintaxe
Resposta em AS3: 8
*/

Isso pode parecer não ser nada, mas em alguma aplicação que trabalha com numeros formatados com umas 10 casas, e tudo tem 0 antes do valor real, isso altera o valor de tudo :P

EDITADO :

Pelo que eu vi isso está documentado, mas não muito bem, ta dentro de um outro artigo no help do flash, apenas como um exemplo.

mas do numero em si com 0 antes ser octal tudo bem, mas o Number(“numero em string”) deveria retornar decimal :P ainda mais que normalmente a entrada de dados depende do usuario (uma coisa a mais para filtrar).



Classe para utilização de banco de dados em AIR atualizada (com eventos)
2 Agosto, 2008, 9:49 pm
Arquivado em: AIR, AS 3.0, Flash geral, Flex | Tags: , , , , , ,

Seguindo as sugestões do flavio no post antigo, eu atualizei a classe, agora ela tem eventos e aceita parametros (mais seguro).

OBS: copie e cole os links no seu navegador

link para arquivos da classe: http://paginas.terra.com.br/lazer/alksk8/DB.zip

Fiz tambem um exemplo da utilização da mesma, que agora não é mais global.

link para .as do exemplo : http://paginas.terra.com.br/lazer/alksk8/Main.as

link para o .fla do exemplo: http://paginas.terra.com.br/lazer/alksk8/Main.fla

Eu estou postando com menos frequencia devido a falta de tempo, mas quando sobra tempo estou aqui.

Agora estou envolvido com outro projeto o GOAS3 que tem por objetivo utilizar os serviços disponibilizados pela API do google, isto tambem esta consumindo uma boa parte do meu tempo.

Qualquer duvida , sugestão, ou critica sobre a classe favor fazer por comentario.



JSFL para ajustar posiçoes dos itens como campos de texto com pixelFonts(pixel Snapping)
11 Julho, 2008, 10:28 pm
Arquivado em: AS 2.0, AS 3.0, Flash geral, JSFL | Tags: , , , , , ,

Olá, primeiramente quero dizer que não tenho postado muita coisa no blog devido a falta de tempo, e tambem de conteudo(até se alguem tiver alguma sugestão manda por email ou coloca aqui como comentario que eu farei o possivel para falar sobre o assunto).

Hoje a tarde depois de arrumar as posiçoes dezenas de movieClips para que não distorcessem eu pensei “por que eu estou fazendo isso? o flash poderia fazer sozinho”, então criei este JSFL que faz exatamente isto (link)

OBS: se o link não funcionar copie ele e cole no navegador;

Como utilizar: é só executar.

ele pega todos os itens(movieClip,Button,Graphic,TextField..)  da timeline atual e ajusta  as posiçoes dos mesmos.

para aplicar isto dentro de um movieClip , abra-o e execute o comando dentro do movie;

pra quem não conseguiu abrir o link aqui vai o codigo:

// Pixel Snapping [alk].jsfl

/*
Script criado por Armando Leopoldo Keller(http://alkeller.wordpress.com)
para instalar: só colar este arquivo em C:\Users\nome_do_usuario\AppData\Local\Adobe\Flash CS3\en\Configuration\Commands
obs: este é o caminho no windows vista
*/
for( var i = 0; i < fl.getDocumentDOM().getTimeline().layers.length; i++)
{
var layerAtual = fl.getDocumentDOM().getTimeline().layers[i];
for(var j = 0 ; j < layerAtual.frames.length ; j++)
{
var frameAtual = layerAtual.frames[j];
for(var k = 0 ; k < frameAtual.elements.length ; k++)
{
var elementoAtual = frameAtual.elements[k];
elementoAtual.x = parseInt(elementoAtual.x);
elementoAtual.y = parseInt(elementoAtual.y);
}
}
}

Qualquer coisa é só comentar, ou mandar email que eu respondo.



Away3D ou Papervision ?
21 Abril, 2008, 11:38 am
Arquivado em: AIR, AS 3.0, Flash geral, Flex, Papervision 3D | Tags: , , , , , ,

Olá, eu estava procurando algumas outras engines 3d para Actionscript, foi então que eu encontrei o Away3D( http://away3d.com/ ) que aparentemente parece ser melhor do que o papervision para coisas mais completas.

Se alguem testar os dois coloque a sua opnião aqui.

eu escolho o  Away3D   :D



Classe para utilização de SQL em AIR (Flash, Flex)
5 Abril, 2008, 7:42 pm
Arquivado em: AIR, AS 3.0, Flash geral, Flex | Tags: , , , , , , ,

Neste tutorial mostrarei como utilizar uma classe que eu criei para facilitar o uso de SQL em AIR (tanto para flash quanto para flex)
A classe é esta:

/*
################################################
# #
# Classe : DB (com.alkeller.air.DB) #
# Autor : Armando Leopoldo Keller #
# Versão : 1.0 #
# Contato : alksk8@hotmail.com #
# Blog : http://alkeller.wordpress.com #
# Documentaçao em breve no blog #
# #
################################################
——- Deixe os creditos na classe ———-
*/
package com.alkeller.air
{
// Imports
import flash.data.SQLResult;
import flash.filesystem.File;
import flash.data.SQLStatement;
import flash.data.SQLConnection;
import flash.events.SQLEvent;
import flash.events.SQLErrorEvent;
import flash.errors.SQLError;

// Classe;
public class DB
{
// Variaveis utilizadas;
private static var conectado:Boolean = false;
private static var dbFile:File
private static var conn:SQLConnection
private static var _sqlStatement:SQLStatement;
private static var resultado:SQLResult;
private static var retornoString:String;
private static var retornoObjeto:Object;

// Funçao Inicia :utilizada para conectar com o banco de dados;
public static function Inicia(_nome:String):String
{
conn = new SQLConnection();
dbFile = File.applicationStorageDirectory.resolvePath(String(_nome+”.db”));
try
{
conn.open(dbFile);
conectado = true;
trace(“Conectado com “+_nome+”.db”);
retornoString = “Conectado com “+_nome+”.db”;
}
catch (error:SQLError) {
conectado = false;
retornoString = “Falha ao conectar: “+error.message+”\nDetalhes: “+error.details;
}
return retornoString;
}
// Funçao executeQuery: Utilizada para executar um comando SQL(verificar quais são aceitos pelo AIR);
// Retorno: SQLResult –> http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/data/SQLResult.html
// ou String de erro;
public static function executeQuery(_sql:String):Object
{
if(conectado == true)
{
_sqlStatement = new SQLStatement();
_sqlStatement.sqlConnection = conn;
_sqlStatement.text = _sql;
try
{
_sqlStatement.execute();
resultado = _sqlStatement.getResult();
retornoObjeto = resultado;
}
catch (error:SQLError)
{
retornoString = “Falha ao executar(“+_sql+”): “+error.message+”\nDetalhes: “+error.details;
}
return retornoObjeto?retornoObjeto:retornoString;
}
else
{
return “Não conectado!”;
}
}
}
}

Classe para download: http://paginas.terra.com.br/lazer/alksk8/DB.as

Como utilizar:
1 – Importe a classe:

// OBS: Aqui é bom verificar se a classe esta no local certo com/alkeller/air/
import com.alkeller.air.*;
// ou
import com.alkeller.air.DB;

2 – Inicie o banco:

DB.Inicia(“teste”); // sendo que teste é o nome do banco

3 – Se as tabelas não existirem, crie elas:

DB.executeQuery(“CREATE TABLE IF NOT EXISTS testando (id INTEGER PRIMARY KEY AUTOINCREMENT,nome TEXT,sobrenome TEXT)”);

4.1 – Execute as Querys que desejar, por exemplo inserir alguns dados:

DB.executeQuery(“INSERT INTO testando (id,nome,sobrenome) VALUES (null,’ARMANDO LEOPOLDO’,'KELLER’)”);

4.2 – Exemplo de como buscar dados:

var obj:Object = DB.executeQuery(“SELECT * FROM testando”).data;
for(var i:uint=0; i < obj.length; i++)
{
trace(“linha: “+i)
for(var j:Object in obj[i])
{
trace(j+”: “+obj[i][j])
}
}

Aproveitem a classe :D

Em breve colocarei aqui este tutorial em video.



NativeMenu em AIR (flash)
16 Março, 2008, 6:04 pm
Arquivado em: AIR, AS 3.0, Flash geral | Tags: , , , , , , ,

Olá, segue abaixo um exemplo comentado de como utilizar menus(como os da maioria dos softwares) em AIR, é um exemplo básico baseado em tutoriais da Adobe.

/*

Primeiro crie um arquivo novo(air)

crie um campo de texto com o tamanho que desejar

instancie o campo de texto como “texto” (sem as aspas)

cole o codigo a seguir no primeiro frame

*/

// importa as classes necessarias

import flash.display.NativeMenu;

import flash.display.NativeMenuItem;

import flash.display.NativeWindow;

import flash.desktop.NativeApplication;

//declara os 2 items do menu

var Menu01:NativeMenuItem;

var Menu02:NativeMenuItem;

if (NativeWindow.supportsMenu)// Se o sistema operacional for windows

{

          stage.nativeWindow.menu = new NativeMenu(); //cria o menu

          stage.nativeWindow.menu.addEventListener(Event.SELECT, selecionouUmItem);//adiciona um evento de seleção no menu

Menu01 = stage.nativeWindow.menu.addItem(new NativeMenuItem(“Primeiro item”));//adiciona o primeiro item no menu

Menu01.submenu = criaSubMenu(); // adiciona o submenu(que vai ser criado logo abaixo) ao primeiro item

Menu02 = stage.nativeWindow.menu.addItem(new NativeMenuItem(“Segundo item”));//adiciona o segundo item no menu

}

if (NativeApplication.supportsMenu)// se o sistema operacionall for mac

{

Menu01 = NativeApplication.nativeApplication.menu.addItem(new NativeMenuItem(“Primeiro item”));//adiciona o primeiro item no menu

          NativeApplication.nativeApplication.menu.addEventListener(Event.SELECT, selecionouUmItem);//adiciona um evento de seleção no menu

Menu01.submenu = criaSubMenu(); // adiciona o submenu(que vai ser criado logo abaixo) ao primeiro item

Menu02 = NativeApplication.nativeApplication.menu.addItem(new NativeMenuItem(“Segundo item”));//adiciona o segundo item no menu

}

function criaSubMenu():NativeMenu

{

var tmpMenu:NativeMenu = new NativeMenu(); // cria o submenu do primeiro item

var MenuNovo:NativeMenuItem = tmpMenu.addItem(new NativeMenuItem(“Novo”));//adiciona o item “Novo” ao submenu

var MenuSalva:NativeMenuItem = tmpMenu.addItem(new NativeMenuItem(“Salva”));//adiciona o item “Salva” ao submenu

var MenuSair:NativeMenuItem = tmpMenu.addItem(new NativeMenuItem(“Sair”));//adiciona o item “Sair” ao submenu

return tmpMenu;

}

function selecionouUmItem(e:Event)
{

texto.text = e.target.label // escreve o nome do item selecionado no campo de texto

}

Qualquer duvida é só postar que eu respondo.

Assim que sobrar algum tempo por aqui eu postarei um tutorial (bem detalhado) e com os exemplos, de como utilizar um banco de dados local com o AIR.