Mostrando postagens com marcador lab. Mostrar todas as postagens
Mostrando postagens com marcador lab. Mostrar todas as postagens

segunda-feira, 19 de setembro de 2011

#AndroidApp: Chat via IP + Porta

Se você acompanha meu blog, já deve ter lido que estou cursando Ciência da Computação aqui em Ribeirão Preto/SP, e também que estou tendo aulas de Java que estão me ajudando muito no aprendizado de Android. E enfim, à alguns dias, fiz minha primeira app!

sexta-feira, 8 de julho de 2011

Usando o forEach com Vector

Olá, está cansado de usar FOR ou WHILE para percorrer seus vetores? Essa funcionalidade também suportada pelo Array facilita executar um bloco de comandos para cada ítem, assim como deixa seu código e lógica muito mais desacoplados.

terça-feira, 14 de junho de 2011

Usando Array e Vector

Olá pessoal, a muito tempo venho observando com mais atenção os tipos de variáveis que uso em minhas aplicações e, ao longo do tempo fui percebendo que alguns tipos usados, junto com algumas boas práticas, melhoraram de forma considerável a velocidade de minhas aplicações.

quarta-feira, 13 de abril de 2011

Conectando Aplicação AIR à banco MySQL via AsSQL

Há alguns dias, um co-worker me deu essa dica. Era sobre um novo projeto open-source de um driver que conectava, à primeira vista, aplicações Actionscript 3.0 à bancos MySQL diretamente. Mas depois de uma olhada rápida, percebemos que era voltado somente a aplicações AIR.

terça-feira, 12 de abril de 2011

LightMVC no GitHub

Hoje, aproveitando a “folga” da faculdade resolvi por algumas coisas em dia. Atualizar as fotos do Picasa, buscar umas novidades na internet (para futuros posts) e versionar alguns códigos… Não fazia idéia da quantidade de projetos e fontes que eu tinha aqui sem backup versionar.

segunda-feira, 11 de abril de 2011

Projeto “Asa de Águia”

Mais um projeto de conclusão de bimestre da faculdade, nomeado pelo Mateus (mesmo autor do primeiro nome do Projeto “Meia Noite”). Dessa vez, tivemos que fazer um programa que efetuava soma e multiplicação de polinômios. Além de eu e o Mateus, tivemos a ilustre participação do Jake Sully! Sim, o Avatar… Bom, o nome dele é Vitor Reis, mas quase ninguém sabe disso.

segunda-feira, 28 de março de 2011

LightMVC v.1

Hoje estou lançando oficialmente a primeira versão do LightMVC, o mais novo framework Actionscript 3.0 baseado na arquitetura MVC. Trata-se basicamente de um conjunto de comandos que fazem seu projeto ser mais escalável, desacoplado e fácil de manter.

sexta-feira, 10 de dezembro de 2010

ISS Orbit

Estava procurando na internet algum site que me mostrasse a posição da ISS em tempo real, e achei! Chama-se Heavens Above e tem vários detalhes sobre a ISS e outras coisas sobre o espaço e os planetas de nossos sistema solar.

Mas como podem ver no site, a imagem é estática, não se atualiza automaticamente. Então resolvi fazer uma pequena aplicação em Flex que faz isso pra mim!


Veja o código fonte ou clique com o botão direito na aplicação.

sexta-feira, 15 de outubro de 2010

Ponteiros em C

Olá, faz algum tempo que eu não posto nada relacionado a programação, estou muito ocupado ultimamente, trabalhando e estudando, fora os projetos pessoais que invadem a madrugada e finais de semana. Mas hoje, felizmente, tive um tempo para solucionar uma dúvida que pintou aqui na sala.

Os temidos PONTEIROS em C, por ter uma certa experiência em programação, foi fácil assimilar o conceito de endereço de memórias e afins, mas ainda tenho muito o que aprender sobre eles. Então, salve enganos, abaixo vou explicar tudo o que sei sobre esses facilitadores e solucionar algumas dúvidas.

Vamos lá...

 

Introdução

Primeiro, vamos definir o que é ponteiro:

"Em programação, um ponteiro ou apontador é um tipo de dado de uma linguagem de programação cujo valor se refere diretamente a um outro valor alocado em outra área da memória, através de seu endereço. Um ponteiro é uma simples implementação do tipo referência da ciência da computação."
(Wikipedia: http://pt.wikipedia.org/wiki/Ponteiro_(programa%C3%A7%C3%A3o))

Entendido? É simples, imagine da seguinte forma. Você declara uma variável A e atribui a ela o valor de 5.

int a = 5;

Imaginando que você é um super nerd espinhento que decorou os endereços de memória do seu computador, considere que o valor da variável A foi alocado no endereço:

0x10 = a = 5

Agora vamos declarar uma variável que guarda o ondereço de memórias de outras variáveis (isso é um ponteiro):

int *p;

Explicando... Em C, basicamente, quando você insere um asterísco (*) antes do nome da variável ela torna-se um ponteiro, que conterá o endereço de memória de uma variável do mesmo tipo que ela (no exemplo, o ponteiro P necessáriamente terá que apontar para um endereço de memória de uma variável do tipo INTEIRO).

Entendido isso, podemos agora guardar o endereço de memória de A em P, atribuindo A prescedido de um E comercial (&):

p = &a;

Prescedendo um variável qualquer (mesmo ponteiro) com um &, isso faz com que a variável retorne naquele momento seu próprio endereço de memória. Então, se dermos um PRINTF em &a:

// %p é o marcador para mostrar endereços de memória
printf("%p", &a); // exibe: 0x10

 

Trabalhando com Ponteiros

Agora podemos passar para o passo de pegar o valor da variável pelo seu endereço de memória, de uma forma ainda mais simples. Se dermos um PRINTF em P veremos:

printf("%p", p); // exibe: 0x10 (o endereço de memória de A)

E se usarmos o prescedente asterísco (*) em P, veremos:

printf("%i", *p); // exibe: 5 (o valor do endereço de memória, que no caso é o valor da variável A)

Compreendendo tudo isso, podemos definir algumas coisas baseadas em nosso exemplo:

a  = 5
&a = 0x10
p  = &a = 0x10
&p = ao endereço de memória de P, por exemplo, 0x11
*p = a = 5

O que é preciso definir muito bem é, que o ponteiro não se refere a quantidade de memória alocada pela variável (independente do tipo) e sim ao local quem está alocada na memória. Por exemplo, podemos ter a seguinte informação em sua memória:

0x10 = 10 Mb
0x11 = 1 Kb
0x12 = 5 Gb
0x13 = 7 Bytes
0x14 = 100 Tb

 

Vetor é um Ponteiro

Para continuarmos a entender e usar ponteiros, temos que ter em mente que um vetor é um ponteiro (matriz é um pouco diferente). Como assim?!

Um vetor (array para os íntimos), nada mais é que um ponteiro para o endereço de memória da primeira posição do vetor. Por exemplo:

int v[5] = {1, 2, 3, 4, 5};

E assumindo que o programa aloca os seguintes endereços de memória:

0x10 = 1
0x11 = 2
0x12 = 3
0x13 = 4
0x14 = 5

Se dermos um PRINTF em V:

printf("%p", v); // exibe: 0x10
printf("%p", &v[0]); // exibe: 0x10

Então, podemos complementar nossa tabela acima da seguinte forma:

0x10 = v[0] = 1
0x11 = v[1] = 2
0x12 = v[2] = 3
0x13 = v[3] = 4
0x14 = v[4] = 5

 

O Uso do Ponteiro

Em C, se incrementarmos (++) um ponteiro, ele passará a valer o próximo endereço de memória. Por exemplo:

printf("%p", p); // 0x10
p++;
printf("%p", p); // 0x11

Baseado nisso, poder percorrer um vetor incremetando o ponteiro:

int v[5] = {1, 2, 3, 4, 5};

for(i=0; i<5; i++)
{
    printf("V aponta para %p \n", v++);
}

Exibindo:

V aponta para 0x10
V aponta para 0x11
V aponta para 0x12
V aponta para 0x13
V aponta para 0x14

E se quisermos pegar o valor:

int v[5] = {1, 2, 3, 4, 5};

for(i=0; i<5; i++)
{
    printf("V aponta para o valor %i \n", *v++);
}

Exibindo:

V aponta para o valor 1
V aponta para o valor 2
V aponta para o valor 3
V aponta para o valor 4
V aponta para o valor 5

 

Exemplo Prático

Juntando tudo que você provavelmente aprendeu nesse post, tente entender o código abaixo. Está simples e didático:

/*
 * LearningPointers.c
 *
 * @Linux Ubuntu 10.4
 * @IDE Eclipse CDT
 * @Compiler Linux GCC
 *
 *  Created on: Oct 1, 2010
 *      Author: idemax - www.idemax.net
 */

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int x;

    int i=2, *p_int=&i;

    char str[5]="test", *p_str=str; // ou *p=&str

    printf("i\t<-\t%i\n*p_int\t<-\t%i\np_int\t<-\t%p", i, *p_int, p_int);

    printf("\np_str:\t");

    for(x=0; x<5; x++)
    {
        printf("%c", *p_str++); // percorrendo por ponteiro
    }

    return EXIT_SUCCESS;
}

 

Conclusão

Espero ter esclarecido suas dúvidas com ponteiro em C. Qualquer dúvida me mande um e-mail no:
idemax@gmail.com

Até a próxima...

sábado, 19 de junho de 2010

ControlToy v.1

Depois de algumas madrugadas a dentro e "perdendo" algumas aulas de ditado na faculdade, consegui concluir meu primeiro projeto em linguagem C usando a IDE Dev-C++, para a faculdade. Um programa para gerenciamento de loja com controle de estoque, caixa, entrada de produtos e listagem de com paginação!

Tela Principal

Código Fonte

ControlToy v.1.c
Onde é chamado os métodos correspondentes a opção selecionada pelo usuário.
/*
 * ControlToy v.1 - 2010
 * Desenvolvido por Marcelo L. Filho ( Idemax )
 * idemax@idemax.net - www.idemax.net
 * Todos os direitos intelectuais reservados ao uso educacional.
 */

#include "includes.c"

void main()
{
    char option;
    
    // Descomente a linha abaixo para o programa cadastrar 100 produtos automaticamente.    
    // testProducts();
    
    while(option != '6')
    {
        system("cls");
        
        printf("\n\t------------------");
        printf("\n\t| ControlToy v.1 |");
        printf("\n\t------------------");
        
        printf("\n\n\tMENU PRINCIPAL\n");
        printf("\n\t1) Cadastrar Produtos");
        printf("\n\t2) Frente de Caixa");
        printf("\n\t3) Consultar Estoque");
        printf("\n\t4) Entrada de Produtos");
        printf("\n\t5) Listagem de Produtos");
        printf("\n\t6) Sair");
        printf("\n\n\tSelecione a opcao desejada: ");
        fGetCH(&option);
        
        switch(option)
        {
            case '1': // Cadastrar Produtos
                createNewProduct();
                break;
            case '2': // Frente de Caixa
                cashier();
                break;
            case '3': // Consultar Estoque
                checkStock();
                break;
            case '4': // Entrada de Produtos
                entryProduct();
                break;
            case '5': // Listagem de Produtos
                listProducts();
                break;
            case '6': // Sair
                if( !confirm(CONFIRMACAO_SAIR, 1) )
                    option = 0;
                break;
            default:
                alert(OPCAO_INVALIDA, 1);
                break;
        }
    }
}

includes.c
Aqui é concentrado todos os includes necessários para o funcionamento do programa.
/*
 * ControlToy v.1 - 2010
 * Desenvolvido por Marcelo L. Filho ( Idemax )
 * idemax@idemax.net - www.idemax.net
 * Todos os direitos intelectuais reservados ao uso educacional.
 */

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <math.h>

#include "Constants.c"
#include "Prototypes.c"
#include "Structs.c"
#include "db.c"
#include "Utils.c"
#include "Functions.c"

Constants.c
Constantes usadas no programa avisar e informar o usuário.
/*
 * ControlToy v.1 - 2010
 * Desenvolvido por Marcelo L. Filho ( Idemax )
 * idemax@idemax.net - www.idemax.net
 * Todos os direitos intelectuais reservados ao uso educacional.
 */

// menu
#define OPCAO_INVALIDA   "Opcao invalida!"

// db
#define FIRST_ID   100
#define DB_SIZE    500

// novo produto
#define PRODUTO_SUCESSO     "Produto cadastrado com sucesso!"
#define QTD_PAGINACAO       5

// caixa
#define QUANTIA_INDISPONIVEL    "Quantidade nao disponivel em estoque!"
#define INSERIR_NOVO            "Deseja inserir novo produto na lista de compra? ( s:SIM, n:NAO )"
#define FINALIZAR_LISTA         "Deseja finalizar a lista de compra? ( s:SIM, n:NAO )"
#define NOVO_PRODUTO_CAIXA_ERRO "Produto ja existe da lista de compra!"
#define NAO_HA_PRODUTOS_CAIXA   "Nao existem produtos cadastrados na lista de compra!"
#define CONFIRMAR_LISTA_COMPRA  "Efetuar saida dos produtos e baixa em estoque? ( s:SIM, n:NAO )"
#define NOVA_LISTA              "Deseja iniciar uma nova lista de compra? ( s:SIM, n:NAO )"
#define VENDA_FINALIZADA        "Saida de produtos efetuada com sucesso!"

// consulta
#define ID_NAO_ENCONTRADO   "Produto nao encontrado, tente novamente!"
#define CONTINUAR_BUSCA     "Deseja consultar outro produto? ( s:SIM, n:NAO )"

// entrada
#define ENTRAR_OUTRO    "Novos dados gravados com sucesso!\n\n\tDeseja da entrada em outro produto? ( s:SIM, n:NAO )"
#define CONFIRMAR_INFO  "Deseja alterar os valores de compra e venda do produto? ( s:SIM, n:NAO )"

// lista
#define NUMERO_PRE_CADASTRO 100
#define SAIR_LISTAGEM       "Pressione qualquer tecla para voltar ao menu inicial..."
#define NAO_HA_PRODUTOS     "Nao existe produto cadastrado!"

// sair
#define CONFIRMACAO_SAIR "Tem certeza que deseja sair? ( s:SIM, n:NAO )"

Prototypes.c
Mantém as assinaturas dos métodos que são necessários antes da implementação.
/*
 * ControlToy v.1 - 2010
 * Desenvolvido por Marcelo L. Filho ( Idemax )
 * idemax@idemax.net - www.idemax.net
 * Todos os direitos intelectuais reservados ao uso educacional.
 */

void alert(char text[], char cleanScreen);
float *sumPurchases(); // [0]: quantidade total, [1]: valor total
void completeShoppingList();

Structs.c
Estruras necessárias para tipar conjuntos de dados.
/*
 * ControlToy v.1 - 2010
 * Desenvolvido por Marcelo L. Filho ( Idemax )
 * idemax@idemax.net - www.idemax.net
 * Todos os direitos intelectuais reservados ao uso educacional.
 */

typedef struct products
{
    int id;
    char description[100];
    float sale, purchase;
    int stored;
}product;

db.c
Variáveis e métodos usados para gerenciar as entradas e saídas de dados do vetor que guarda os produtos.
/*
 * ControlToy v.1 - 2010
 * Desenvolvido por Marcelo L. Filho ( Idemax )
 * idemax@idemax.net - www.idemax.net
 * Todos os direitos intelectuais reservados ao uso educacional.
 */

int id = FIRST_ID, index = 0, cashierIndex = 0, cashierProducts[DB_SIZE][2];
product products[DB_SIZE];

int getNewId()
{
    return ++id;
}

void insertNewProduct(product newProduct)
{
    newProduct.id = getNewId();
    
    products[index] = newProduct;
    
    index++;
}

void insertNewProductVariables(char description[], float sale, float purchase, int stored)
{
    product newProduct;
    
    strncpy(newProduct.description, description, 100);
    newProduct.sale = sale;
    newProduct.purchase = purchase;
    newProduct.stored = stored;
    
    insertNewProduct( newProduct );
}

int verifyProductID( int pID )
{
    int i, rtn = 0, found = 0;
    product prod;
    
    for(i = 0; i < index; i++)
    {
        if(pID == products[i].id)
        {
            rtn = pID;
            found = 1;
            break;
        }
    }
    
    if( !found )
    {
        alert(ID_NAO_ENCONTRADO, 1);
        return -1;
    }
    
    return rtn;
}

int getProductByID( int pID )
{
    int i, rtn = 0, found = 0;
    product prod;
    
    for(i = 0; i < index; i++)
    {
        if(pID == products[i].id)
        {
            rtn = i;
            found = 1;
            break;
        }
    }
    
    if( !found )
    {
        alert(ID_NAO_ENCONTRADO, 1);
        return -1;
    }
    
    return rtn;
}

float getProductSellingPrice(int pID)
{
    float rtn = 0.0;
    int i;

    for(i = 0; i < index; i++)
    {
        if(pID == products[i].id)
        {
            rtn = products[i].sale;
            break;
        }
    }
    
    return rtn;
}

void startNewCashier()
{
    int i;
    
    for(i = 0; i < DB_SIZE; i++)
    {
        cashierProducts[i][0] = -1;
        cashierProducts[i][1] = -1;
    }
    
    cashierIndex = 0;
}

void inserNewCashierProduct(int pID, int qtd)
{
    cashierProducts[cashierIndex][0] = pID;
    cashierProducts[cashierIndex][1] = qtd;
    
    cashierIndex++;
}

int hasProductInCashier(int pID)
{
    int i;
    
    for(i = 0; i < cashierIndex; i++)
        if(cashierProducts[i][1] == pID)
            return 1;
    
    return 0;
}

Utils.c
Métodos e variáveis usadas globalmente pelo programa, para auxiliar no feedback do usuário e na execução de operações.
/*
 * ControlToy v.1 - 2010
 * Desenvolvido por Marcelo L. Filho ( Idemax )
 * idemax@idemax.net - www.idemax.net
 * Todos os direitos intelectuais reservados ao uso educacional.
 */

// Mostra uma mensagem na tela
void alert(char text[], char cleanScreen)
{
    if(cleanScreen)
        system("cls");
        
    printf("\n\n\n\t*** AVISO ***\n\n\t%s\n\n\n\n\t", text);
    system("pause");
}

void pause(char text[])
{
    printf("%s", text);
    fflush(stdin);
    getch();
}

void fGetCH(char * value)
{
    fflush(stdin);
    *value = getch();
}

void fGetS(char * value)
{
    fflush(stdin);
    gets(value);
}

int confirm(char text[], char cleanScreen)
{
    int rtn = 0;
    char choice;
    
    if(cleanScreen)
        system("cls");
    
    printf("\n\n\n\t*** ATENCAO ***\n\n\t%s\n\t", text);
    fGetCH(&choice);
    
    if(choice == 'S' || choice == 's' || choice == 13)
        rtn = 1;
    
    return rtn;
}

int stopPagination(int cPage, int tPage)
{
    int rtn = 1;
    char key;
    
    printf("\n\tPagina %i de %i.\n\tQualquer tecla: proxima pagina \\ ESQ: menu principal", cPage, tPage);    
    fGetCH(&key);
    
    if(key == 27)
        rtn = 0;
        
    return rtn;
}

void showProductInfo(int pID)
{
    printf("\t[%i] %s\n\t\tVenda R$ %.2f - Compra R$ %.2f // Estoque: %d unidades\n\n", products[pID].id, products[pID].description, products[pID].sale, products[pID].purchase, products[pID].stored);
}

void showCashierProductInfo(int pID)
{
    int correctID = getProductByID(cashierProducts[pID][0]);
    
    printf("\t[%i] %s\n\t\tQuantidade: %i unidades - Total: R$ %.2f\n\n", products[correctID].id, products[correctID].description, cashierProducts[pID][1], cashierProducts[pID][1] * products[correctID].sale);
}

int closeShoppingList()
{
    if(cashierIndex == 0)
    {
        alert(NAO_HA_PRODUTOS_CAIXA, 1);
        return 0;
    }
    
    int listIndex = 0, i, cPage = 1, tPage, rest, rtn = 1;
    
    tPage = cashierIndex / QTD_PAGINACAO;
    rest = cashierIndex % QTD_PAGINACAO;
    
    if(rest < 5)
        tPage++;
    else
        tPage--;
    
    for(i = 0; i < cashierIndex; i++)
    {
        if(listIndex == 0)
        {
            system("cls");
            
            printf("\n\t--------------------");
            printf("\n\t| FINALIZAR COMPRA |");
            printf("\n\t--------------------\n\n");
        }
        
        if(listIndex < QTD_PAGINACAO)
        {
            showCashierProductInfo(i);
            listIndex++;
        }
        
        if(listIndex >= QTD_PAGINACAO)
        {
            if( !stopPagination(cPage, tPage) )
                break;

            cPage++;
            listIndex = 0;
        }
        
        if(listIndex != 0 && i == cashierIndex - 1)
        {
            float *sum = sumPurchases();
            
            printf("\n\tPagina %i de %i.\n\n\t-------------------------------------------------------\n\tFIM DA LISTA DE COMPRA\n\n\tTotal de produtos: %.0f - Total da compra: R$ %.2f\n", cPage, tPage, sum[0], sum[1]);
            
            if(confirm(CONFIRMAR_LISTA_COMPRA, 0))
                completeShoppingList();
            else
                rtn = 0;
        }
    }
    
    return rtn;
}

float *sumPurchases() // [0]: quantidade total, [1]: valor total
{
    float *rtn, qtd = 0.0, pSum = 0, saleValue, result[2];
    int i;
    
    for(i = 0; i < cashierIndex; i++)
    {
        qtd += cashierProducts[i][1];
        
        saleValue = getProductSellingPrice(cashierProducts[i][0]);
        pSum += saleValue * cashierProducts[i][1];
    }
    
    result[0] = qtd;
    result[1] = pSum;
    
    rtn = &result;
    
    return rtn;
}

void completeShoppingList()
{
    int i, productID;
    
    for(i = 0; i < cashierIndex; i++)
    {
        productID = getProductByID(cashierProducts[i][0]);
        products[productID].stored -= cashierProducts[i][1];
    }
    
    alert(VENDA_FINALIZADA, 1);
}

Functions.c
Métodos e variáveis do menu principal.
/*
 * ControlToy v.1 - 2010
 * Desenvolvido por Marcelo L. Filho ( Idemax )
 * idemax@idemax.net - www.idemax.net
 * Todos os direitos intelectuais reservados ao uso educacional.
 */

// popula o DB de produtos para testes
void testProducts()
{
    int i, n, t = NUMERO_PRE_CADASTRO;
    product testProduct;
    
    for(i = 0; i < t; i++)
    {
        n = i + 1;
        insertNewProductVariables("Produto", n*4, n*2, n*6);
    }
}

// 1- Cadastrar Produtos
void createNewProduct()
{
    system("cls");
    
    product newProduct;
    
    printf("\n\t--------------------------");
    printf("\n\t| CADASTRAR NOVO PRODUTO |");
    printf("\n\t--------------------------\n");
    printf("\n\n\tDigite a descricao do produto:\n\t");
    
    fGetS( newProduct.description );
    
    printf("\n\n\tDigite o valor de compra do produto:\n\t");
    scanf("%f", &newProduct.purchase);
    
    printf("\n\n\tDigite o valor de venda do produto:\n\t");
    scanf("%f", &newProduct.sale);
    
    printf("\n\n\tDigite a quantia que o produto tem em estoque:\n\t");
    scanf("%d", &newProduct.stored);
    
    insertNewProduct( newProduct );
    
    printf("\n\n\tNovo produto \"%s\" cadastrado com o ID: %i\n\n\t", newProduct.description, id);
    system("pause");
    
    alert(PRODUTO_SUCESSO, 1);
}

// 2- Frente de Caixa
void cashier() // cashier = caixa de supermercado ( http://www.liveenglishprogram.com/caixa.html )
{
    startNewCashier();
    
    int continueRegistration = 1, listSize = cashierIndex, pID, qtd, qtdError;
    
    while( continueRegistration )
    {
        system("cls");
        
        printf("\n\t-------------------");
        printf("\n\t| FRENTE DE CAIXA |");
        printf("\n\t-------------------\n\n");
        
        printf("\tProdutos da lista: %i", listSize);
        
        printf("\n\n\tDigite o ID do produto a ser inserido:\n\t\t( 0: menu principal, 1: finalizar lista )\n\t");
        scanf("%i", &pID);
        
        if( pID == 0 )
            return;
            
        if( pID != 1 ) // novo produto da lista
        {
            pID = verifyProductID(pID);
            
            if(pID > -1)
            {
                if( hasProductInCashier(pID) )
                {
                    alert(NOVO_PRODUTO_CAIXA_ERRO, 1);
                    continue;
                }
                
                qtdError = 1;
                while( qtdError )
                {
                    printf("\n\n");
                    showProductInfo(getProductByID(pID));
                    
                    printf("\tDigite a quantidade comprada: ");
                    scanf("%i", &qtd);
                    
                    if( qtd > products[getProductByID(pID)].stored )
                        alert(QUANTIA_INDISPONIVEL, 0);
                    else
                        qtdError = 0;
                }
                
                inserNewCashierProduct(pID, qtd);
                
                listSize = cashierIndex;
                
                if(confirm(INSERIR_NOVO, 1))
                {
                    continue;
                }
                else if(confirm(FINALIZAR_LISTA, 0))
                {
                    if(!closeShoppingList() && confirm(NOVA_LISTA, 1))
                        cashier();
                    
                    continueRegistration = 0;
                }
                else
                {
                    continueRegistration = 0;
                }
            }
        }
        else // finaliza a lista
        {
            if(listSize != 0 && !closeShoppingList() && confirm(NOVA_LISTA, 1))
                cashier();
            
            continueRegistration = 0;
        }
    }
}

// 3- Consultar Estoque
void checkStock()
{
    system("cls");
    
    printf("\n\t---------------------");
    printf("\n\t| CONSULTAR ESTOQUE |");
    printf("\n\t---------------------\n\n");
    
    int pID;
    
    printf("\tDigite o ID do produto a ser consultado ( 0: menu principal ):\n\t");
    scanf("%i", &pID);
    
    if( pID == 0 )
        return;
        
    pID = getProductByID(pID);
        
    if(pID > -1)
    {
        printf("\n\n");
        showProductInfo(pID);
        
        if(!confirm(CONTINUAR_BUSCA, 0))
            return;
    }
    
    checkStock();
}

// 4- Entrada de Produtos
void entryProduct()
{
    system("cls");
    
    printf("\n\t-----------------------");
    printf("\n\t| ENTRADA DE PRODUTOS |");
    printf("\n\t-----------------------\n\n");
    
    int pID;
    
    printf("\tDigite o ID do produto a ser dada entrada ( 0: menu principal ):\n\t");
    scanf("%i", &pID);
    
    if( pID == 0 )
        return;
        
    pID = getProductByID(pID);
        
    if(pID > -1)
    {
        printf("\n\n");
        showProductInfo(pID);
        
        float sale, purchase;
        int stored;
        
        printf("\tDigite a quantidade de produtos que esta sendo adquirida:\n\t");
        scanf("%i", &stored);
        
        products[pID].stored  += stored; //  No PDF pedia a quantidade adquirida nao a nova quantidade, por isso é adicionado a quantidade atual, nao atualizado.
        
        /*
        Contribuição abaixo de Xandão ( http://www.twitter.com/xandao_luchetti )
        */
        if(!confirm(CONFIRMAR_INFO, 0))
            return;
        
        printf("\n\n\tDigite o novo preco de compra:\n\t");
        scanf("%f", &purchase);
        
        printf("\n\n\tDigite o novo preco de venda:\n\t");
        scanf("%f", &sale);
        
        products[pID].purchase = purchase;
        products[pID].sale     = sale;
        
        if(!confirm(ENTRAR_OUTRO, 0))
            return;
    }
    
    entryProduct();
}

// 5- Listagem de Produtos
void listProducts()
{
    if(index == 0)
    {
        alert(NAO_HA_PRODUTOS, 1);
        return;
    }
    
    int listIndex = 0, i, cPage = 1, tPage, rest;
    
    tPage = index / QTD_PAGINACAO;
    rest = index % QTD_PAGINACAO;
    
    if(rest < 5)
        tPage++;
    else
        tPage--;
    
    for(i = 0; i < index; i++)
    {
        if(listIndex == 0)
        {
            system("cls");
            
            printf("\n\t------------------------");
            printf("\n\t| LISTAGEM DE PRODUTOS |");
            printf("\n\t------------------------\n\n");
        }
        
        if(listIndex < QTD_PAGINACAO)
        {
            showProductInfo(i);
            listIndex++;
        }
        
        if(listIndex >= QTD_PAGINACAO)
        {
            if( !stopPagination(cPage, tPage) )
                break;

            cPage++;
            listIndex = 0;
        }
        
        if(listIndex != 0 && i == index - 1)
        {
            printf("\n\tPagina %i de %i.\n\t", cPage, tPage);
            pause(SAIR_LISTAGEM);
        }
    }
}

Baixe os códigos fontes: ControlToy v.1.rar (16.39 KB)

domingo, 22 de novembro de 2009

Enviando e Recuperando Dados por HTTPService usando PHP

Hoje vou mostrar exatamente o que o título diz, vamos enviar alguns dados para uma página PHP via HTTPService e recuperá-los no evento ResultEvent.RESULT.

Infelizmente não conseguir fazer o PHP realmente enviar porque o lixo do meu servidor de hospedagem não habilita o método mail(), tendo que fazer envio por SMTP. Mas não achei uma classe que funcionasse significativamente bem. Então estou deixando sua imaginação fluir...

Bom, vamos ao que interessa. No exemplo, eu fiz um formulário simples em que o usuário insere o nome, e-mail, assunto por combobox e a mensagem, e travei os campos usando os Validators do próprio Flex. Também fiz um bom uso do Declarations, para deixar as coisas mais explícitas.



Segue abaixo o código do FlexContactForm.mxml.

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
width="400"
height="400"
applicationComplete="applicationCompleteHandler()"
viewSourceURL="srcview/index.html">
<fx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import mx.rpc.events.ResultEvent;
import mx.validators.Validator;

private var _validadores:Array;

private function applicationCompleteHandler():void
{
_validadores = [ campoNomeValidator, campoEmailValidator, comboAssuntoValidator, campoMensagemValidator ];

campoNome.setFocus();
}

private function btnEnviar_clickHandler():void
{
if( Validator.validateAll( _validadores ).length )
return;

PopUpManager.addPopUp( progressEnviando, this, true );
PopUpManager.centerPopUp( progressEnviando );

httpServiceSendMail.send();
}

private function btnLimpar_clickHandler():void
{
campoNome.text = campoEmail.text = campoMensagem.text = '';
comboAssunto.selectedIndex = -1;

campoNome.setFocus();
}

private function httpServiceSendMail_resultHandler( $event:ResultEvent ):void
{
PopUpManager.removePopUp( progressEnviando );

PopUpManager.addPopUp( titleRetornoPhp, this, true );

textRetorno.htmlText = $event.result as String;

PopUpManager.centerPopUp( titleRetornoPhp );
}

private function titleRetornoPhp_closeHandler():void
{
PopUpManager.removePopUp( titleRetornoPhp );
}
]]>
</fx:Script>
<fx:Declarations>
<mx:TitleWindow id="titleRetornoPhp"
title="Retorno do PHP"
showCloseButton="true"
close="titleRetornoPhp_closeHandler()"
minWidth="200">
<mx:Text id="textRetorno" />
</mx:TitleWindow>
<mx:ProgressBar id="progressEnviando"
indeterminate="true"
label="enviando mensagem..." />
<s:HTTPService id="httpServiceSendMail"
method="POST"
resultFormat="text"
result="httpServiceSendMail_resultHandler(event)"
url="php/enviaEmail.php">
<s:request>
<nome>
{campoNome.text}
</nome>
<email>
{campoEmail.text}
</email>
<assunto>
{comboAssunto.selectedItem.@label}
</assunto>
<mensagem>
{campoMensagem.text}
</mensagem>
</s:request>
</s:HTTPService>
<fx:XMLList id="xmlAssuntos">
<assunto label="Informação" />
<assunto label="Reclamação" />
<assunto label="Crítica" />
<assunto label="Dúvida" />
<assunto label="Outro" />
</fx:XMLList>
<mx:StringValidator id="campoNomeValidator"
source="{campoNome}"
property="text"
tooShortError="Digite seu nome!"
tooLongError="Digite somente seu primeiro nome!"
minLength="4"
maxLength="20" />
<mx:EmailValidator id="campoEmailValidator"
source="{campoEmail}"
property="text" />
<mx:NumberValidator id="comboAssuntoValidator"
source="{comboAssunto}"
lowerThanMinError="Selecione um assunto!"
property="selectedIndex"
minValue="0"
thousandsSeparator="."
decimalSeparator=","
trigger="{comboAssunto}"
triggerEvent="{Event.CHANGE}" />
<mx:StringValidator id="campoMensagemValidator"
source="{campoMensagem}"
property="text"
tooShortError="Digite uma mensagem relevante!"
tooLongError="Vá direto ao assunto!"
minLength="10"
maxLength="255" />
</fx:Declarations>
<s:Rect width="100%"
height="100%">
<s:fill>
<s:RadialGradient>
<s:GradientEntry color="#ffffff" />
<s:GradientEntry color="#cccccc" />
</s:RadialGradient>
</s:fill>
</s:Rect>
<s:Panel title="Formulário de Contato"
horizontalCenter="0"
verticalCenter="0">
<mx:Form horizontalCenter="0"
verticalCenter="0">
<mx:FormHeading label="Preencha o formulário abaixo." />
<mx:FormItem label="Nome:"
required="true"
width="100%">
<s:TextInput id="campoNome"
width="100%" />
</mx:FormItem>
<mx:FormItem label="E-Mail:"
required="true"
width="100%">
<s:TextInput id="campoEmail"
width="100%" />
</mx:FormItem>
<mx:FormItem label="Assunto:"
required="true"
width="100%">
<mx:ComboBox id="comboAssunto"
prompt="Selecione um assunto..."
selectedIndex="-1"
width="100%"
dataProvider="{xmlAssuntos}"
labelField="@label" />
</mx:FormItem>
<mx:FormItem label="Mensagem:"
required="true">
<s:TextArea id="campoMensagem" />
</mx:FormItem>
<mx:FormItem direction="horizontal"
width="100%">
<s:Button id="btnEnviar"
label="enviar"
click="btnEnviar_clickHandler()" />
<mx:Spacer width="100%" />
<s:Button id="btnLimpar"
label="limpar"
click="btnLimpar_clickHandler()" />
</mx:FormItem>
</mx:Form>
</s:Panel>
</s:Application>

O PHP está bem simples, o foco é mostrar como vem e vão os valores.

<?
echo '<b>Nome: </b>'.$_POST['nome'].'<br />'.
'<b>E-Mail: </b><a href="mailto:'.$_POST['email'].'">'.$_POST['email'].'</a><br />'.
'<b>Assunto: </b>'.$_POST['assunto'].'<br />'.
'<b>Mensagem: </b>'.$_POST['mensagem'];
?>

É simplesmente um echo nos Posts, veja que a chave é a mesma do nó no request que é passado no HTTPService.

Como eu setei resultFormat="text" no HTTPService, é só pergar no evento a propriedade result como String e escrever onde quiser.

O ver / baixar o projeto / código-fonte, clique com o botão direito na aplicação ou clique aqui.

sábado, 31 de outubro de 2009

Usando Path no Flex 4

Olá, hoje vou mostrar como usar um novo componente primitivo do Flex SDK 4, o Path:

"The Path class is a filled graphic element that draws a series of path segments. In vector graphics, a path is a series of points connected by straight or curved line segments. Together the lines form an image. In Flex, you use the Path class to define a complex vector shape constructed from a set of line segments."

Não vou arriscar uma tradução, mas basicamente fala que o Path é um elemento gráfico de preenchimento que desenha uma série de formas. Em vetores gráficos, o Path é uma série de pontos conectados por linhas retas e curvas. Juntas formando uma imagem. No Flex, você pode usar a classe Path para definir a construção de um vetor complexo a partir de um conjunto de linhas.

Bom, pelo menos viram que o curso de inglês está rendendo alguma coisa!

Continuado, fiz um exemplo bem simples usando o máximo que o framework possível, para mostrar também algumas outras facilidades que o novo SDK tráz:



No exemplo, eu fiz um Path com o data contendo váriaveis Bindable, e o preenchimento, borda e filtro, todos por MXML.
A animação, eu usei o framework TweenMax, vale a pena estudá-lo. É parecido com a Tweener do Zeh Fernando, mas com várias funcionalidades que fazem diferença.
Não usei nenhuma fórmula para o Path parecer elástico, o foco é como ficou fácil desenhar e animar vetores complexos.

Path.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
width="400"
height="400"
applicationComplete="applicationCompleteHandler()"
viewSourceURL="srcview/index.html">
<fx:Script>
<![CDATA[
import com.greensock.TimelineMax;
import com.greensock.TweenMax;
import com.greensock.easing.Bounce;
import com.greensock.easing.Elastic;

[Bindable]
private var _timelineMax:TimelineMax;

[Bindable]
public var pathY:Number = 10;

[Bindable]
public var pathWidth:Number = 200;

[Bindable]
public var pathHeight:Number = pathWidth + pathY;

private function applicationCompleteHandler():void
{
_timelineMax = new TimelineMax();

_timelineMax.addChild( new TweenMax( this, 12, { pathY:height - myPath.height, ease:Elastic.easeOut } ) );
_timelineMax.addChild( new TweenMax( this, 2, { pathHeight:height, ease:Bounce.easeOut } ) );

_timelineMax.pause();
}

private function playClickHandler():void
{
_timelineMax.play();
}

protected function stopClickHandler():void
{
_timelineMax.currentTime = 0;
_timelineMax.stop();
}

protected function labelClickHandler():void
{
navigateToURL( new URLRequest( 'http://www.idemax.net/' ), '_blank' );
}
]]>
</fx:Script>
<s:Rect width="100%"
height="100%">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="#ffffff" />
<s:GradientEntry color="#cccccc" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<mx:Image horizontalCenter="0"
verticalCenter="0"
source="@Embed('/assets/images/idemax.jpg')">
<mx:filters>
<mx:BlurFilter quality="3" />
</mx:filters>
</mx:Image>
<s:VGroup top="10"
left="10">
<s:Button label="play"
click="playClickHandler()" />
<s:Button label="stop"
click="stopClickHandler()" />
</s:VGroup>
<s:Path id="myPath"
data="m 0 {pathY}
q {pathWidth/2} {-((pathHeight-pathY)-pathWidth)} {pathWidth} 0
Q {pathWidth+((pathHeight-pathY)-pathWidth)} {(pathHeight-(pathWidth/2))-((pathHeight-pathY)-pathWidth)} {pathWidth} {pathHeight}
h {-pathWidth}
Q {-((pathHeight-pathY)-pathWidth)} {(pathHeight-(pathWidth/2))-((pathHeight-pathY)-pathWidth)} 0 {pathY}
z"
horizontalCenter="0">
<s:stroke>
<s:SolidColorStroke color="#333333"
weight="1" />
</s:stroke>
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="#a8d848" />
<s:GradientEntry color="#63802a"
alpha=".5" />
</s:LinearGradient>
</s:fill>
<s:filters>
<s:DropShadowFilter angle="90"
distance="20"
quality="3"
blurX="20"
blurY="20" />
</s:filters>
</s:Path>
<s:Label right="10"
bottom="10"
text="www.idemax.net"
fontWeight="bold"
alpha=".25"
click="labelClickHandler()"
buttonMode="true" />
</s:Application>

O ver ou baixar o projeto / código-fonte, clique com o botão direito na aplicação e depois em "View Source", ou clique aqui.

Qualquer dúvida, enviem para idemax@gmail.com.

segunda-feira, 21 de setembro de 2009

TwitterFeed

Olá pessoal, estou testando um novo aplicativo para o Twitter, é o TwitterFeed.



E sobre novos posts e tutoriais... Estou analisando alguns bons assuntos. Em breve terão novidades...
Se tiverem idéias, enviem para idemax@gmail.com.

segunda-feira, 3 de agosto de 2009

Seguindo o Mouse com Trigonometria

Olá, esse poste de hoje foi baseado na dúvida do leitor Jefferson A. Pereira. Espero que gostem...

Se não leu meu post sobre Trigonometria em Actionscript, leia-o antes clicando aqui.

Vou ensinar hoje como usar a trigonometria em actionscript para fazer o olhos seguirem o ponteiro do mouse. Assim...


No método construtor, vamos adicionar o listener MouseEvent.MOUSE_MOVE no STAGE:

public function Main() 
{
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
}

No método listener, vamos limpar os riscos antigos dos triângulos que usamos para testar e executar a função que rotaciona o olho. Também forço o updateAfterEvent para que fique mais suave.

private function onMouseMoveHandler($event:MouseEvent):void 
{
graphics.clear();

rotateEye(eye1);
rotateEye(eye2);

$event.updateAfterEvent();
}

No método rotateEye é onde faço os cálculos para que o olho seja rotacionado de forma que "siga" o mouse do usuário. Primeiro eu encontro os catetos adjacente e oposto para que possa encontrar a hipotenusa:

var catAdj:Number = mouseX - $eye.x;
var catOp:Number = mouseY - $eye.y;
var hipot:Number = Math.sqrt((catAdj * catAdj) + (catOp * catOp));

Com isso posso calcular o ângulo de abertura do triângulo em radianos:

var radians:Number = Math.asin(catOp / hipot);

E transformar em graus:

var degree:Number = radians * (180 / Math.PI);

Ok, até essa parte tudo bem. Mas como o actionscript trabalha com graus de forma diferente, temos que verificar se o mouse está a direita ou esquerda do nosso olho. Fazemos isso comparando se o cateto adjacente está positivo ou negativo:

if (catAdj >= 0)
{
$eye.rotation = degree;
}
else
{
$eye.rotation = 180 - degree;
}

Se for negativo, subtraimos o valor de 180º. Por exemplo: 180º - (-90º) = 180º + 90º = 270º. Ou seja, está apontando na direção norte.

E depois adicionamos as linhas de teste e o log:

log.text = 'catAdj: ' + catAdj;
log.appendText('\ncatOp: ' + catOp);
log.appendText('\nhipot: ' + hipot);
log.appendText('\nradians: ' + radians);
log.appendText('\ndegree: ' + degree);

graphics.lineStyle(1, 0xff0000);
graphics.moveTo($eye.x, $eye.y);
graphics.lineTo(mouseX, mouseY);
graphics.lineStyle(1, 0xcccccc);
graphics.lineTo(mouseX, $eye.y);
graphics.lineTo($eye.x, $eye.y);

O método rotateEye ficou assim:

private function rotateEye($eye:MovieClip):void
{
var catAdj:Number = mouseX - $eye.x;
var catOp:Number = mouseY - $eye.y;
var hipot:Number = Math.sqrt((catAdj * catAdj) + (catOp * catOp));

var radians:Number = Math.asin(catOp / hipot);
var degree:Number = radians * (180 / Math.PI);

if (catAdj >= 0)
{
$eye.rotation = degree;
}
else
{
$eye.rotation = 180 - degree;
}

log.text = 'catAdj: ' + catAdj;
log.appendText('\ncatOp: ' + catOp);
log.appendText('\nhipot: ' + hipot);
log.appendText('\nradians: ' + radians);
log.appendText('\ndegree: ' + degree);

graphics.lineStyle(1, 0xff0000);
graphics.moveTo($eye.x, $eye.y);
graphics.lineTo(mouseX, mouseY);
graphics.lineStyle(1, 0xcccccc);
graphics.lineTo(mouseX, $eye.y);
graphics.lineTo($eye.x, $eye.y);
}

Pronto!!!

Abaixo a classe Main inteira:

package  
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.text.TextField;

/**
* ...
* @author www.idemax.net
*/
public class Main extends MovieClip
{
public var eye1:MovieClip;
public var eye2:MovieClip;
public var log:TextField;

public function Main()
{
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
}

private function onMouseMoveHandler($event:MouseEvent):void
{
graphics.clear();

rotateEye(eye1);
rotateEye(eye2);

$event.updateAfterEvent();
}

private function rotateEye($eye:MovieClip):void
{
var catAdj:Number = mouseX - $eye.x;
var catOp:Number = mouseY - $eye.y;
var hipot:Number = Math.sqrt((catAdj * catAdj) + (catOp * catOp));

var radians:Number = Math.asin(catOp / hipot);
var degree:Number = radians * (180 / Math.PI);

if (catAdj >= 0)
{
$eye.rotation = degree;
}
else
{
$eye.rotation = 180 - degree;
}

log.text = 'catAdj: ' + catAdj;
log.appendText('\ncatOp: ' + catOp);
log.appendText('\nhipot: ' + hipot);
log.appendText('\nradians: ' + radians);
log.appendText('\ndegree: ' + degree);

graphics.lineStyle(1, 0xff0000);
graphics.moveTo($eye.x, $eye.y);
graphics.lineTo(mouseX, mouseY);
graphics.lineStyle(1, 0xcccccc);
graphics.lineTo(mouseX, $eye.y);
graphics.lineTo($eye.x, $eye.y);
}

}

}

Clique abaixo para fazer o download dos arquivos:

sábado, 18 de julho de 2009

Você conhece QR-Code?

Você é capaz de entender o que está escrito na imagem acima?!

quarta-feira, 15 de julho de 2009

Rotação 3D no Flash Player 10

Olá, quem me segue no Twitter, está lendo ultimamente que estou fazendo um Coverflow usando a rotação 3D nativa do Flash Player 10. Então resolvi fazer um post antes de dormir para mostrar como é fácil usar essa nova classe.

Abaixo é o teste simples que fiz no Flash:


Obs.: Caso não funcione, instale o Flash Player 10 clicando aqui.

E a classe Main:

package  
{
import fl.controls.Slider;
import fl.events.SliderEvent;
import flash.display.MovieClip;

/**
* ...
* @author www.idemax.net
*/
public class Main extends MovieClip
{
public var avatar:MovieClip;
public var xAxis:Slider;
public var yAxis:Slider;
public var zAxis:Slider;

public function Main()
{
xAxis.addEventListener(SliderEvent.CHANGE, onSliderChange);
yAxis.addEventListener(SliderEvent.CHANGE, onSliderChange);
zAxis.addEventListener(SliderEvent.CHANGE, onSliderChange);
}

private function onSliderChange(event:SliderEvent):void
{
var slider:Slider = event.target as Slider;

switch(slider)
{
case xAxis:
avatar.rotationX = slider.value;
break;
case yAxis:
avatar.rotationY = slider.value;
break;
case zAxis:
avatar.rotationZ = slider.value;
break;
}
}

}

}

Clique abaixo para fazer o download dos arquivos:

quarta-feira, 1 de julho de 2009

Criando e Disparando Eventos Customizados - 2ª Parte

Olá, continuando a sequência de posts sobre criar e disparar eventos customizados, hoje vou ensinar como colocar também propriedades customizadas. Por exemplo, você tem três elementos na tela e três botões que giram esses elementos.

Para fazer isso de uma forma que seu código não fique acoplado e você possa futuramente mudar o efeito (no caso, girar) sem estragar outras partes do código, você precisar pensar genericamente. Para isso, teoricamente seu código deve ser assim:


  1. Cada botão no MouseEvent.CLICK dispara um evento dizendo que é para girar um certo elemento.

  2. O método listener do evento que o botão disparou verifica em qual elemento deve ser feito o bloco de comandos (no caso, girar)


É ai que entra o evento customizado com propriedades customizadas. No MouseEvent ou em qualquer evento nativo do actionscript não há propriedades disponíveis para que você passe qualquer tipo de informação extra, no caso de nosso exemplo, um MovieClip.

Se você não leu o meu primeiro post sobre eventos customizados, leia-o antes clicando aqui.

Há duas maneiras de fazer isso, na verdade, um é complemento do outro. O que vou mostrar hoje é a primeira fase, para que você entenda passo à passo como funciona o processo de customizar eventos com propriedades customizadas.

Inicialmente vamos criar nossa classe de evento customizado normalmente, como criamos no post passado:

package  
{
import flash.events.Event;

/**
* ...
* @author www.idemax.net
*/
public class MeuEvento extends Event
{
public static const GIRAR_ELEMENTO:String = 'girarElemento';

public function MeuEvento(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}

}

}

O que muda é o seguinte, como num classe qualquer, você irá criar variáveis públicas, além das constantes usadas para disparar o seu evento:

public var instancia:String;
public var elemento:MovieClip;

Vou usar dois tipos para deixar o exemplo mais completo. No meu evento customizado eu vou poder passar a instância do MovieClip (uma String) ou o próprio MovieClip.

Então a classe do nosso evento customizado com propriedades customizadas fica assim:

package  
{
import flash.display.MovieClip;
import flash.events.Event;

/**
* ...
* @author www.idemax.net
*/
public class MeuEvento extends Event
{
public static const GIRAR_ELEMENTO:String = 'girarElemento';

public var instancia:String;
public var elemento:MovieClip;

public function MeuEvento(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}

}

}

Pronto, agora vamos usá-lo! Vou cria minha classe Main que escutará o evento MouseEvent.CLICK nos botões e o meu evento customizado:

public function Main() 
{
addEventListener(MeuEvento.GIRAR_ELEMENTO, onGirarElementoHandler);

btnAzul.addEventListener(MouseEvent.CLICK, onBtnClick);
btnVerde.addEventListener(MouseEvent.CLICK, onBtnClick);
btnVermelho.addEventListener(MouseEvent.CLICK, onBtnClick);
}

No listener onBtnClick, vou guardar qual botão está disparando esse evento pelo event.target:

var buttonClicked:Button = event.target as Button;

E vamos instanciar nosso evento customizado:

var evt:MeuEvento = new MeuEvento(MeuEvento.GIRAR_ELEMENTO);

Mas porque instânciar? A sua classe de eventos comporta-se como uma classe normal, por isso declaramos como public as propriedades customizadas.

Agora verificamos por um switch qual botão disparou o evento MouseEvent.CLICK para que seja guardado na propriedade de nosso evento customizado qual elemento ele deve girar:

switch(buttonClicked)
{
case btnAzul:
evt.elemento = azul;
break;
case btnVerde:
evt.instancia = 'verde';
break;
case btnVermelho:
evt.elemento = vermelho;
break;
}

Veja que eu acessei normalmente as propriedades "elemento" e "instancia" da classe MeuEvento. Na "elemento" eu passei o MovieClip direto, mas na "instancia" eu passei uma String com a instância do meu MovieClip.

Agora disparamos nosso evento:

dispatchEvent(evt);

O listener onBtnClick inteiro ficou assim:

private function onBtnClick(event:MouseEvent):void 
{
var buttonClicked:Button = event.target as Button;

var evt:MeuEvento = new MeuEvento(MeuEvento.GIRAR_ELEMENTO);

switch(buttonClicked)
{
case btnAzul:
evt.elemento = azul;
break;
case btnVerde:
evt.instancia = 'verde';
break;
case btnVermelho:
evt.elemento = vermelho;
break;
}

dispatchEvent(evt);
}

Como o botão já disparou o evento com o elemento que ele quer que sejá girado, vamos tratar esse evento no listener onGirarElementoHandler que adicionamos na contrutora da classe.

Primeiro vamos tratar alguns possíveis erros que podem acontecer, caso seja passado nenhum elementos nas propriedades "elemento" e "instancia" ou seja passado em ambas.

if (event.elemento == null && event.instancia == null) return; // Se não for declarado algum elemento para ser girado
if (event.elemento != null && event.instancia != null) return; // Se os dois argumentos forem declarados, deve-se escolher um

Se estiver somente um das propriedades difernte de NULL, vamos verificar qual delas foi atribuída e guadar em uma variável:

var girarElemento:MovieClip;

if (event.elemento != null)
{
girarElemento = event.elemento as MovieClip;
}
else if (event.instancia != null)
{
girarElemento = this[event.instancia as String] as MovieClip;
}

Pronto! Agora fazemos o que devemos fazer com o elemento selecionado!

girarElemento.rotation = Math.random() * 360;

O listener onGirarElementoHandler inteiro ficou assim:

private function onGirarElementoHandler(event:MeuEvento):void 
{
if (event.elemento == null && event.instancia == null) return; // Se não for declarado algum elemento para ser girado
if (event.elemento != null && event.instancia != null) return; // Se os dois argumentos forem declarados, deve-se escolher um

var girarElemento:MovieClip;

if (event.elemento != null)
{
girarElemento = event.elemento as MovieClip;
}
else if (event.instancia != null)
{
girarElemento = this[event.instancia as String] as MovieClip;
}

girarElemento.rotation = Math.random() * 360;
}

Agora você pode deixar sua aplicação mais rica e muito menos acoplada a um determido tipo de execução, e para mudar ou atualizar algum efeito ou processo, basta você mudar apenas um método!

A classe Main inteira ficou assim:

package  
{
import fl.controls.Button;
import flash.display.MovieClip;
import flash.events.MouseEvent;

/**
* ...
* @author www.idemax.net
*/
public class Main extends MovieClip
{
public var vermelho:MovieClip;
public var verde:MovieClip;
public var azul:MovieClip;
public var btnVermelho:Button;
public var btnVerde:Button;
public var btnAzul:Button;

public function Main()
{
addEventListener(MeuEvento.GIRAR_ELEMENTO, onGirarElementoHandler);

btnAzul.addEventListener(MouseEvent.CLICK, onBtnClick);
btnVerde.addEventListener(MouseEvent.CLICK, onBtnClick);
btnVermelho.addEventListener(MouseEvent.CLICK, onBtnClick);
}

private function onBtnClick(event:MouseEvent):void
{
var buttonClicked:Button = event.target as Button;

var evt:MeuEvento = new MeuEvento(MeuEvento.GIRAR_ELEMENTO);

switch(buttonClicked)
{
case btnAzul:
evt.elemento = azul;
break;
case btnVerde:
evt.instancia = 'verde';
break;
case btnVermelho:
evt.elemento = vermelho;
break;
}

dispatchEvent(evt);
}

private function onGirarElementoHandler(event:MeuEvento):void
{
if (event.elemento == null && event.instancia == null) return; // Se não for declarado algum elemento para ser girado
if (event.elemento != null && event.instancia != null) return; // Se os dois argumentos forem declarados, deve-se escolher um

var girarElemento:MovieClip;

if (event.elemento != null)
{
girarElemento = event.elemento as MovieClip;
}
else if (event.instancia != null)
{
girarElemento = this[event.instancia as String] as MovieClip;
}

girarElemento.rotation = Math.random() * 360;
}

}

}

Clique aqui para ver um exemplo ou abaixo para fazer o download dos arquivos:

segunda-feira, 22 de junho de 2009

Criando e Disparando Eventos Customizados - 1ª Parte

Olá, esse post de hoje é o primeiro de uma série de três onde vou mostrar como se cria um evento customizado até a melhor maneira de usá-lo com argumentos customizados.

Nesse exemplo eu vou fazer um botão que gira a forma selecionada em dois RadioButtons, primeiramente vamos criar nossa classe de evento com o nome de MeuEvento que é subclasse da Event:

public class MeuEvento extends Event

E vamos crias as duas constantes que usaremos para disparar esses eventos:

public static const GIRAR_FORMA_AZUL:String     = 'girarFormaAzul';
public static const GIRAR_FORMA_VERMELHA:String = 'girarFormaVermelha';

A classe do evento customizado fica assim:

package  
{
import flash.events.Event;

/**
* ...
* @author www.idemax.net
*/
public class MeuEvento extends Event
{
public static const GIRAR_FORMA_AZUL:String = 'girarFormaAzul';
public static const GIRAR_FORMA_VERMELHA:String = 'girarFormaVermelha';

public function MeuEvento(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}

}

}

Bom, agora vamos montar o exemplo, a classe principal será a Main que é subclasse de MovieClip:

public class Main extends MovieClip

No método construtor da classe eu vou adicionar o EventListener MouseEvent.CLICK no botão:

botao.addEventListener(MouseEvent.CLICK, onClickBotao);

E também os EventListener MeuEvento.GIRAR_FORMA_AZUL e MeuEvento.GIRAR_FORMA_VERMELHA direto no STAGE:

addEventListener(MeuEvento.GIRAR_FORMA_AZUL, girarFormaAzul);
addEventListener(MeuEvento.GIRAR_FORMA_VERMELHA, girarFormaVermelha);

O método listener do MouseEvent.CLICK do botão verifica o valor do RadioButtonGroup para disparar o evento de qual forma o usuário quer girar:

private function onClickBotao(event:MouseEvent):void 
{
switch(radioButtonGroup.selection.value)
{
case 'forma1':
dispatchEvent(new MeuEvento(MeuEvento.GIRAR_FORMA_AZUL));
break;
case 'forma2':
dispatchEvent(new MeuEvento(MeuEvento.GIRAR_FORMA_VERMELHA));
break;
}
}

E nos métodos listeners que adicionamos no STAGE fazemos a rotação da forma que o usuário disparou o evento:

private function girarFormaAzul(event:MeuEvento):void 
{
forma1.rotation += 45;
}

private function girarFormaVermelha(event:MeuEvento):void
{
forma2.rotation -= 45;
}

Pronto! Você deve estar se perguntando o porque de usar eventos customizados nesse exemplo ou em qualquer outra explicação. Os comando de rotacionar a forma poderiam sim estar no bloco de comando de cada CASE do SWITCH ou na necessidade de usar um método genérico, executar o método ao invés de disparar o evento.

Mas o uso do evento customizado te da oportunidade de ouví-lo de onde estiver, por exemplo, ao carregar um SWF externo ele faz uma animação de 3 segundos e depois para. Como você faria isso de uma forma que não seja necessário ter um método que seja executado quando essa animação acabar?

Resposta: Você dispara um evento quando a animação acabar para que internamente você execute o que quiser e também deixa diponível para quem estiver de fora, no caso, quem carregou esse SWF. Saber quando essa animação acabou. Isso deixa seu código mais desacoplado...

Classe Main completa:

package  
{
import fl.controls.Button;
import fl.controls.CheckBox;
import fl.controls.RadioButton;
import fl.controls.RadioButtonGroup;
import flash.display.MovieClip;
import flash.events.MouseEvent;

/**
* ...
* @author www.idemax.net
*/
public class Main extends MovieClip
{
public var botao:Button;
public var radioButtonGroup:RadioButtonGroup = new RadioButtonGroup('radioButtonGroup');
public var radioButtonAzul:RadioButton;
public var radioButtonVermelho:RadioButton;
public var forma1:MovieClip;
public var forma2:MovieClip;

public function Main()
{
addEventListener(MeuEvento.GIRAR_FORMA_AZUL, girarFormaAzul);
addEventListener(MeuEvento.GIRAR_FORMA_VERMELHA, girarFormaVermelha);

botao.addEventListener(MouseEvent.CLICK, onClickBotao);
}

private function onClickBotao(event:MouseEvent):void
{
switch(radioButtonGroup.selection.value)
{
case 'forma1':
dispatchEvent(new MeuEvento(MeuEvento.GIRAR_FORMA_AZUL));
break;
case 'forma2':
dispatchEvent(new MeuEvento(MeuEvento.GIRAR_FORMA_VERMELHA));
break;
}
}

private function girarFormaAzul(event:MeuEvento):void
{
forma1.rotation += 45;
}

private function girarFormaVermelha(event:MeuEvento):void
{
forma2.rotation -= 45;
}

}

}

Clique aqui para ver um exemplo ou abaixo para fazer o download dos arquivos:

domingo, 17 de maio de 2009

Loader do Stage e de aquivos externos (Preloader)

Olá, ví alguns posts na internet sobre esse assunto mas sempre estavam faltando algo. Nesse post vou tentar mostrar os dois principais carregadores em actionscript 3.0, o carregamento do STAGE e de um arquivo externo, no caso, uma imagem JPEG.

Esse post também é dedicado ao meu amigo que está com dificuldades nesse assunto.

Segue abaixo o código da classe Main:

package  
{
import fl.controls.ProgressBarMode;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
import flash.net.URLRequest;

/**
* ...
* @author www.idemax.net
*/
public class Main extends MovieClip
{
private var externalLoader:Loader;

public function Main()
{
stop();

stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;

loaderInfo.addEventListener(Event.INIT, onStageLoaderInit);
loaderInfo.addEventListener(ProgressEvent.PROGRESS, onStageLoaderProgress);
loaderInfo.addEventListener(Event.COMPLETE, onStageLoaderComplete);
}

/**
* Iniciou o carregamento do STAGE
* @param event
*/
private function onStageLoaderInit(event:Event):void
{
event.target.removeEventListener(Event.INIT, onStageLoaderInit);

stageLoader.label.text = '0%';
}

/**
* Enquando está carregando o STAGE
* @param event
*/
private function onStageLoaderProgress(event:ProgressEvent):void
{
var pct:Number = Math.round((event.bytesLoaded / event.bytesTotal) * 100);

stageLoader.label.text = pct + '%';
}

/**
* O STAGE acabou de carregar
* @param event
*/
private function onStageLoaderComplete(event:Event):void
{
event.target.removeEventListener(Event.COMPLETE, onStageLoaderComplete);

addFrameScript(1, onFrame2);

gotoAndStop(2);
}

/**
* Linha do tempo no FRAME 2
*/
private function onFrame2():void
{
botao.label = 'carregar imagem externa';
botao.addEventListener(MouseEvent.CLICK, onButtonClick);

externalLoader = new Loader();
externalLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onExternalLoaderProgress);
externalLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onExternalLoaderComplete);
}

/**
* Quando o botão de 'carregar imagem externa' é clicaco
* É iniciado o Loader
* @param event
*/
private function onButtonClick(event:MouseEvent):void
{
botao.enabled = false;

barra.mode = ProgressBarMode.MANUAL;

externalLoader.load(new URLRequest('imagem_externa.jpg'));
}

/**
* Enquando carrega a imagem externa
* @param event
*/
private function onExternalLoaderProgress(event:ProgressEvent):void
{
barra.setProgress(event.bytesLoaded, event.bytesTotal);
}

/**
* A imagem externa está carregada
* @param event
*/
private function onExternalLoaderComplete(event:Event):void
{
event.target.removeEventListener(Event.COMPLETE, onExternalLoaderComplete);

externalLoader.width = 550;
externalLoader.height = 400;

addChild(externalLoader);
}

}

}

Clique aqui para ver um exemplo on-line ou no link abaixo para fazer o download dos arquivos:

Paint em Actionscript 3.0

Olá, fiz um protótipo bem simples de "Paint" em Actionscript 3.0. Nele você pode escolher a cor, o tamanho do pincél e limpar a tela.


Classe principal:


package
{
import fl.controls.Button;
import fl.controls.ColorPicker;
import fl.controls.Slider;
import fl.events.ColorPickerEvent;
import fl.events.SliderEvent;
import flash.display.MovieClip;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.ui.Mouse;

/**
* ...
* @author www.idemax.net
*/
public class Main extends MovieClip
{
private var margin:Number = 10;
private var rounding:Number = 20;
private var border:Number = 5;
private var defaultWord:String = 'desenhe na área branca acima';
private var brushMinimum:Number = 1;
private var brushCurrent:Number = 10;
private var brushMaximum:Number = 100;
private var drawEnable:Boolean = false;
private var startDrawingEnable:Boolean = false;

private var container:MovieClip;
private var panel:MovieClip;
private var panelTitle:TextField;
private var infoLabel:TextField;
private var drawStage:MovieClip;
private var tools:MovieClip;
private var toolsTitle:TextField;
private var labelColorPicker:TextField;
private var colorPicker:ColorPicker;
private var currentColor:uint;
private var slider:Slider;
private var labelSlider:TextField;
private var currentBrushSize:Number;
private var brushCicle:MovieClip;
private var drawMask:MovieClip;
private var drawContainer:MovieClip;
private var lineDraw:MovieClip;
private var button:Button;
private var linesDraw:Array;
private var drawMouseInspector:MovieClip;

/**
* Construtora da Classe
* Adiciona os listeners necessários e aplica as configurações básicas
* Os eventos "MainEvents" são personalizados
*/
public function Main()
{
loaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);

stage.align = 'TL';
//stage.scaleMode = StageScaleMode.NO_SCALE;

stage.addEventListener(Event.RESIZE, onResizeStage);

addEventListener(MouseEvent.ROLL_OUT, onRollOutApplication);

addEventListener(MainEvents.CREATE_PANEL, onCreatePanelHandler);
addEventListener(MainEvents.CREATE_TOOLS, onCreateToolsHandler);

addEventListener(MainEvents.UPDATE_INFO_LABEL, onUpdateInfoLabelHandler);
addEventListener(MainEvents.UPDATE_BRUSH, onUpdateBrushHandler);

addEventListener(MainEvents.UPDATE_COMPLETE_BRUSH, onUpdateCompleBrushHandler);
addEventListener(MainEvents.UPDATE_COMPLETE_INFO_LABEL, onUpdateCompleInfoLabelHandler);

addEventListener(MainEvents.DRAW_START, onDrawStartHandler);
addEventListener(MainEvents.DRAWING, onDrawingHandler);
addEventListener(MainEvents.DRAW_COMPLETE, onDrawCompleteHandler);
}

/**
* Inicia a criação da aplicação quando a mesma foi totalmente carregada
* @param e
*/
private function onCompleteHandler(e:Event):void
{
dispatchEvent(new MainEvents(MainEvents.CREATE_PANEL));
}

/**
* Re-cria a aplicação quando as dimensões do STAGE são alteradas
* OBS.: Se houver desenho, ele será perdido
* @param e
*/
private function onResizeStage(e:Event):void
{
dispatchEvent(new MainEvents(MainEvents.CREATE_PANEL));
}

/**
* ANTI-BUG: Se o usuário rolar para fora da aplicação ele para de desenhar se estiver do modo DESENHO
* @param e
*/
private function onRollOutApplication(e:MouseEvent):void
{
dispatchEvent(new MainEvents(MainEvents.DRAW_COMPLETE));
}

/**
* Cria e configura os listeners dos elementos visuais, exceto os componentes das ferramentas
* @param e
*/
private function onCreatePanelHandler(e:MainEvents):void
{
if (container != null)
{
removeChild(container);
container = null;
}

container = new MovieClip();
addChild(container);

panel = new MovieClip();
panel.graphics.beginFill(0xcccccc);
panel.graphics.drawRoundRect(0, 0, stage.stageWidth - (margin * 2), stage.stageHeight - (margin * 2), rounding, rounding);
panel.graphics.endFill();
panel.x = panel.y = margin;
container.addChild(panel);

panelTitle = new TextField();
panelTitle.autoSize = 'left';
panelTitle.htmlText = 'Desenhando com o actionscript 3.0';
panelTitle.x = panelTitle.y = margin;
panel.addChild(panelTitle);

infoLabel = new TextField();
infoLabel.autoSize = 'left';
infoLabel.text = defaultWord;
infoLabel.x = margin;
infoLabel.y = panel.height - infoLabel.textHeight - margin;
panel.addChild(infoLabel);

drawStage = new MovieClip();
drawStage.graphics.lineStyle(border, 0x000000, .25);
drawStage.graphics.beginFill(0xffffff);
drawStage.graphics.drawRoundRect(0, 0, stage.stageWidth / 100 * 75, infoLabel.y - (panelTitle.y + panelTitle.textHeight + (margin * 2)), rounding, rounding);
drawStage.graphics.endFill();
drawStage.x = margin;
drawStage.y = panelTitle.y + panelTitle.textHeight + margin;
panel.addChild(drawStage);

drawContainer = new MovieClip();
panel.addChild(drawContainer);

drawMask = new MovieClip();
drawMask.graphics.beginFill(0x000000);
drawMask.graphics.drawRoundRect(0, 0, stage.stageWidth / 100 * 75, infoLabel.y - (panelTitle.y + panelTitle.textHeight + (margin * 2)), rounding, rounding);
drawMask.graphics.endFill();
drawMask.x = margin;
drawMask.y = panelTitle.y + panelTitle.textHeight + margin;
panel.addChild(drawMask);

drawContainer.mask = drawMask;

drawMouseInspector = new MovieClip();
drawMouseInspector.addEventListener(MouseEvent.ROLL_OVER, onRollOverMouseInspector);
drawMouseInspector.addEventListener(MouseEvent.ROLL_OUT, onRollOutMouseInspector);
drawMouseInspector.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownMouseInspector);
drawMouseInspector.addEventListener(MouseEvent.MOUSE_UP, onMouseUpMouseInspector);
drawMouseInspector.graphics.beginFill(0xff0000, 0);
drawMouseInspector.graphics.drawRoundRect(0, 0, stage.stageWidth / 100 * 75, infoLabel.y - (panelTitle.y + panelTitle.textHeight + (margin * 2)), rounding, rounding);
drawMouseInspector.graphics.endFill();
drawMouseInspector.x = margin;
drawMouseInspector.y = panelTitle.y + panelTitle.textHeight + margin;
panel.addChild(drawMouseInspector);

tools = new MovieClip();
tools.graphics.lineStyle(border, 0x000000, .25);
tools.graphics.beginFill(0xffffff);
tools.x = drawStage.x + drawStage.width + margin;
tools.y = drawStage.y;

toolsTitle = new TextField();
toolsTitle.autoSize = 'left';
toolsTitle.htmlText = 'Ferramentas';
toolsTitle.x = toolsTitle.y = margin;
tools.addChild(toolsTitle);

container.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownContainer);
container.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveContainer);
container.addEventListener(MouseEvent.MOUSE_UP, onMouseUpContainer);

dispatchEvent(new MainEvents(MainEvents.CREATE_TOOLS));
}

/**
* Crias e configuras os listeners dos componentes das ferramentas
* @param e
*/
private function onCreateToolsHandler(e:MainEvents):void
{
linesDraw = new Array();

labelColorPicker = new TextField();
labelColorPicker.autoSize = 'left';
labelColorPicker.text = 'Selecione a cor:';
labelColorPicker.x = margin;
labelColorPicker.y = toolsTitle.y + toolsTitle.textHeight + (margin * 3);
tools.addChild(labelColorPicker);

colorPicker = new ColorPicker();
colorPicker.addEventListener(ColorPickerEvent.CHANGE, onColorPickerChange);
colorPicker.x = labelColorPicker.x + labelColorPicker.textWidth + margin;
colorPicker.y = labelColorPicker.y;
tools.addChild(colorPicker);

currentColor = colorPicker.selectedColor;

labelSlider = new TextField();
labelSlider.autoSize = 'left';
labelSlider.text = 'Tamanho do pincel:';
labelSlider.x = margin;
labelSlider.y = colorPicker.y + colorPicker.height + (margin * 3);
tools.addChild(labelSlider);

slider = new Slider();
slider.addEventListener(SliderEvent.CHANGE, onSliderChange);
slider.minimum = brushMinimum;
slider.maximum = brushMaximum;
slider.x = margin * 2;
slider.y = labelSlider.y + labelSlider.textHeight + margin;
slider.value = brushCurrent;
tools.addChild(slider);

currentBrushSize = slider.value;

button = new Button();
button.addEventListener(MouseEvent.CLICK, onClickButtonCleanScreean);
button.label = 'limpar tela';
button.x = margin;
button.y = slider.y + slider.height + (margin * 3);
tools.addChild(button);

tools.graphics.drawRoundRect(0, 0, stage.stageWidth - drawStage.width - (margin * 5), button.y + button.height + margin, rounding, rounding);
tools.graphics.endFill();
panel.addChild(tools);
}

/**
* O usuário rolou para dentro da área de desenho
* @param e
*/
private function onRollOverMouseInspector(e:MouseEvent):void
{
var mc:MovieClip = e.target as MovieClip;
mc.addEventListener(Event.ENTER_FRAME, onEnterFrameDrawStage);
}

/**
* O usuário rolou para fora da área de desenho
* @param e
*/
private function onRollOutMouseInspector(e:MouseEvent):void
{
var mc:MovieClip = e.target as MovieClip;
mc.removeEventListener(Event.ENTER_FRAME, onEnterFrameDrawStage);

dispatchEvent(new MainEvents(MainEvents.UPDATE_COMPLETE_BRUSH));
dispatchEvent(new MainEvents(MainEvents.UPDATE_COMPLETE_INFO_LABEL));
}

/**
* O usuário começa a desenhar na área de desenho
* @param e
*/
private function onMouseDownMouseInspector(e:MouseEvent):void
{
startDrawingEnable = true;
}

/**
* O usuário parou de desenhar
* @param e
*/
private function onMouseUpMouseInspector(e:MouseEvent):void
{
startDrawingEnable = false;
}

/**
* O usuário soltou o botão esquerdo do mouse dentro da aplicação
* @param e
*/
private function onMouseUpContainer(e:MouseEvent):void
{
dispatchEvent(new MainEvents(MainEvents.DRAW_COMPLETE));
}

/**
* O usuário está movimentando o mouse dentro da aplicação
* @param e
*/
private function onMouseMoveContainer(e:MouseEvent):void
{
dispatchEvent(new MainEvents(MainEvents.DRAWING));
}

/**
* O usuário tenta desenhar dentro da aplicação
* A aplicação verifica se o usuário está tentando
* dentro da área de desenho
* @param e
*/
private function onMouseDownContainer(e:MouseEvent):void
{
if (!startDrawingEnable) return;
dispatchEvent(new MainEvents(MainEvents.DRAW_START));
}

/**
* Dispara enquanto o usuário está com o mouse dentro da área de desenho
* @param e
*/
private function onEnterFrameDrawStage(e:Event):void
{
dispatchEvent(new MainEvents(MainEvents.UPDATE_INFO_LABEL));
dispatchEvent(new MainEvents(MainEvents.UPDATE_BRUSH));
}

/**
* Posiciona o ponteiro de desenho na mesma posição do mouse do usuário
* enquanto o mesmo se encontra na área de desenho
* @param e
*/
private function onUpdateBrushHandler(e:MainEvents):void
{
if (infoLabel == null) return;
if (brushCicle != null) drawContainer.removeChild(brushCicle);

Mouse.hide();

brushCicle = new MovieClip();
brushCicle.graphics.lineStyle(border, 0x000000, .5);
brushCicle.graphics.beginFill(currentColor);
brushCicle.graphics.drawCircle(drawContainer.mouseX, drawContainer.mouseY, currentBrushSize);
brushCicle.graphics.endFill();
drawContainer.addChild(brushCicle);
}

/**
* Atualiza o LOG de posição cartesiana do ponteiro do mouse na área de desenho
* enquanto o mesmo se encontra na área de desenho
* @param e
*/
private function onUpdateInfoLabelHandler(e:MainEvents):void
{
if (infoLabel == null) return;
infoLabel.text = 'x: ' + drawStage.mouseX + ' - y: ' + drawStage.mouseY;
}

/**
* Seta a mensagem padrão quando o usuário não está com o
* ponteiro do mouse sobre a área de desenho
* @param e
*/
private function onUpdateCompleInfoLabelHandler(e:MainEvents):void
{
infoLabel.text = defaultWord;
}

/**
* Quando o ponteiro do mouse sai da área de desenho, o ponteiro de desenho some
* e da lugar novamente ao ponteiro do mouse
* @param e
*/
private function onUpdateCompleBrushHandler(e:MainEvents):void
{
if (brushCicle != null)
{
drawContainer.removeChild(brushCicle);
brushCicle = null;
}

Mouse.show();
}

/**
* Fecha a linha desenhada pelo usuário e deixa a variável preparada para uma nova
* @param e
*/
private function onDrawCompleteHandler(e:MainEvents):void
{
drawEnable = false;

if (lineDraw == null) return;

lineDraw.graphics.endFill();
lineDraw = null;
}

/**
* Desenha as linhas referente ao ponteiro do mouse
* @param e
*/
private function onDrawingHandler(e:MainEvents):void
{
if (!drawEnable) return;

lineDraw.graphics.lineTo(drawContainer.mouseX, drawContainer.mouseY);
}

/**
* Cria um ponto caso o usuário somente queira pontilhar
* e inicia a nova linha
* @param e
*/
private function onDrawStartHandler(e:MainEvents):void
{
var dot:MovieClip = new MovieClip();
dot.graphics.beginFill(currentColor);
dot.graphics.drawCircle(drawContainer.mouseX, drawContainer.mouseY, currentBrushSize);
linesDraw.push(drawContainer.addChild(dot));

lineDraw = new MovieClip();
lineDraw.graphics.moveTo(drawContainer.mouseX, drawContainer.mouseY);
lineDraw.graphics.lineStyle(currentBrushSize * 2, currentColor);
linesDraw.push(drawContainer.addChild(lineDraw));

drawEnable = true;
}

/**
* Guarda a cor escolhida
* @param e
*/
private function onColorPickerChange(e:ColorPickerEvent):void
{
var cp:ColorPicker = e.target as ColorPicker;
currentColor = cp.selectedColor;
}

/**
* Guarda o tamanho do pincel escolhido
* @param e
*/
private function onSliderChange(e:SliderEvent):void
{
var sld:Slider = e.target as Slider;
currentBrushSize = sld.value;
}

/**
* Limpa os desenho feitos
* @param e
*/
private function onClickButtonCleanScreean(e:MouseEvent):void
{
for (var i:int = 0; i < linesDraw.length; i++)
{
var mc:MovieClip = linesDraw[i] as MovieClip;
drawContainer.removeChild(mc);
}

linesDraw = new Array();
}

}

}

Classe de eventos:


package
{
import flash.events.Event;

/**
* ...
* @author www.idemax.net
*/
public class MainEvents extends Event
{

public static const CREATE_PANEL:String = 'createPanel';
public static const CREATE_TOOLS:String = 'createTools';

public static const UPDATE_INFO_LABEL:String = 'updateInfoLabel';
public static const UPDATE_BRUSH:String = 'updateBrush';

public static const UPDATE_COMPLETE_INFO_LABEL:String = 'updateCompleteInfoLabel';
public static const UPDATE_COMPLETE_BRUSH:String = 'updateCompleteBrush';

public static const DRAW_START:String = 'drawStart';
public static const DRAWING:String = 'drawing';
public static const DRAW_COMPLETE:String = 'drawComplete';

public function MainEvents(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}

}

}

Clique aqui para ver um exemplo on-line ou no link abaixo para fazer o download dos arquivos: