Em continuação a série de tutoriais sobre AS3…
Hoje vou falar pouco sobre novidades, mas vou apenas apresentar um exemplo pratico de como criar um painel personalizado usando apenas action script 3 e todos os conceitos que aprendemos até agora…
5.4. Classes, Exemplo Painel personalizado
Vamos a um exemplo prático, usando o flex o meu objectivo é fazer o seguinte:
Criar um painel personalizado que permita:
– ser arrastado (drag & drop) na nossa aplicação
– ter botões de maximizar, minimizar e restaurar
– Adicionar efeitos de maximizar, minimizar e restaurar.
Vamos aplicar todos os conhecimentos adquiridos anteriormente bem como a utilização de algumas classes nativas de efeitos disponiveis no flex como efeitos que mais à frente falaremos. Este exemplo apenas funcionará no Flex, visto que o AS3 do flash ainda não suporta alguns pontos e classes de efeitos que foram adicionadas no Flex.
Vejam o seguinte código que foi devidamente comentado para perceberem facilmente toda a sua estrutura.
{
//imports necessários ao nosso painel / class
//Eventos
import flash.events.Event;
import flash.events.MouseEvent;
import mx.containers.Panel;
import mx.controls.Image;
import mx.core.Application;
import mx.effects.Move;
import mx.effects.Parallel;
import mx.effects.Resize;
//extendemos o nosso painel
public class customPanel extends Panel
{
//incluimos as nossas imagens de maximizar, minimizar e restaurar
//para a resposta do carregamento / troca das imagens seja imediata
[Embed(source="maxBut.png")]
public var max:Class;
[Embed(source="minBut.png")]
public var min:Class;
[Embed(source="restBut.png")]
public var rest:Class;
//variaveis
//estados do painel
private var maximizado:Boolean = false;
private var minimizado:Boolean = false;
//imagens dos botões
private var minBut:Image;
private var maxBut:Image;
//usado para guardar os tamanhos e posições originais do nosso panel
private var originalSizeW:int;
private var originalSizeH:int;
private var originalPosX:int;
private var originalPosY:int;
//construtor da nossa class
public function customPanel()
{
//definimos alguns estilos do nosso panel para ficar mais agradável
this.setStyle("headerHeight",19);
this.setStyle("borderThicknessBottom", 0);
this.setStyle("borderThicknessLeft", 0);
this.setStyle("borderThicknessTop", 0);
this.setStyle("borderThicknessRight", 0);
this.title="Painel 1";
}
//re-escrevemos a função createChildren que o componente painel usa
//para definir o novo layout que ele terá, ou seja vamos adicionar
//os botões
override protected function createChildren():void {
super.createChildren();
//guardamos as posições e tamanhos originais
originalSizeW=this.unscaledHeight;
originalSizeH=this.unscaledHeight;
originalPosX=this.x;
originalPosY=this.y;
/**
Apenas vamos criar os botões se eles não existirem, temos
que fazer isto porque esta função é chamada sempre que é
adicionado um elemento novo ao painel, no caso de
adicionarem uma caixa de texto esta função é chamada de novo
e se não indicasse-mos o "if" ele iria criar novos botões
sempre que fosse chamada.
**/
//verificamos se o botão de minimizar existe
if(!minBut){
//criamos a nova imagem
minBut=new Image;
//atribuimos a class (imagem) min ao nosso botão e definimos
//alguns parametros
minBut.source=min;
minBut.visible=true;
minBut.toolTip="Minimiza";
/**
a imagem mostra o icon por defeito (seta), usamos os 3
metodos em baixo para que o botão se comporte como um icon e
apresente o cursor "hand" / mão.
**/
minBut.mouseChildren=false;
minBut.useHandCursor=true;
minBut.buttonMode=true;
//Evento para detectar quando foi clicada.
minBut.addEventListener(MouseEvent.CLICK, minOnClick, false, 0, true);
/**
adicionamos como filho. Aqui adicionamos no metodo rawChildrem que faz
um "overlay" à nossa imagem e vai apresenta-la em cima do painel, se
usarmos apenas this.addChild() o nosso botão iria aparecer dentro da
area util do painel e não no topo. Poderiamos usar também
this.titleBar.addChild() onde a titlebar é o topo do nosso painel.**/
this.rawChildren.addChild(minBut);
}
//o mesmo procedimento para a imagem de maximizar, notem que
//não defini posições, elas serão definidas mais abaixo.
if(!maxBut) {
maxBut=new Image;
maxBut.visible=true;
maxBut.source=max;
maxBut.toolTip="Maximiza";
maxBut.mouseChildren=false;
maxBut.useHandCursor=true;
maxBut.buttonMode=true;
maxBut.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
this.rawChildren.addChild(maxBut);
}
//adicionamos um listner para saber quando o titleBar foi
//clicado para iniciar o drag e drop
this .titleBar.addEventListener(MouseEvent.MOUSE_DOWN, beginDrag,false,0,true);
this .titleBar.addEventListener(MouseEvent.MOUSE_UP, endDrag,false,0,true);
// actualiza a displayList.
invalidateDisplayList();
}
/**
Aqui vamos subscrever o metdo chamado pelo invalidateDisplayList()
que vai ser chamado sempre que existam modificações a fazer no
nosso layout, em cima como lhe adcionei duas imagens forcei a
chamada da função em baixo para poder definir as posições dos meus
botões.**/
protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
//definimos os tamanhos da nossa imagem
//ela por defeito está com 16px por 16px mas vamos nos certificar
//que elas ficam com esses tamanhos
minBut.setActualSize(16,16);
maxBut.setActualSize(16,16);
/**
Vamos definir a posição x e y dos nossos botões
o unscaledWidth indica-nos o tamanho "on-execution" do
nosso painel, ou seja o tamanho actual, poderiamos usar o
this.width, mas provocaria falhas no posicionamento visto
que se o painel for aumentado esta actualização do
this.height teria que aguardar pela actualização da
displayList, ou seja, o tamanho final depois de maximizado
apenas estaria disponivel no final da execução desta função.
Colocamos o botão de minimizar à direita do painel, mas
deixamos um espaço em px para o botão de maximizar
(-maxBut.width)**/
var xPos:Number = unscaledWidth - (minBut.width+maxBut.width);
// o botão ficará a 2px do topo
var yPos:Number = 2;
//posicionamos o botão na devida posição
minBut.move(xPos, yPos);
//usamos as mesmas variaveis em cima, mas agora para
//posicionar o botão de maximizar
// como vai ficar à direita subtraimos apenas o seu tamanho ao
//total do nosso painel
xPos=unscaledWidth - maxBut.width;
yPos=2;
//subtraimos 4px para que o botão fiquem mais perto do
//minimizar e mais afastado da lateral direita
maxBut.move(xPos-4,yPos);
}
// chamada para iniciar o drag do panel
private function beginDrag(evt:MouseEvent):void {
this.startDrag();
}
// chamada para parar o drag do panel
private function endDrag(evt:MouseEvent):void {
this.stopDrag();
/**
Ao parar temos que guardar a posição em que o painel foi
largado para que ao restaurar o painel ir para a ultima
posição onde foi deixado.
**/
originalPosX=this.x;
originalPosY=this.y;
}
//chamada quando o botão de minimizar é clicado.
private function minOnClick(evt:MouseEvent):void {
/**
Vamos inicializar alguns efeitos para executar na transição do
nosso painel para o estado minimizado
paralel, usado para exectuatr mais que um efeito ao mesmo tempo
os efeitos executados por este paralel serão so seus child's
(efeitos)**/
var ambos:Parallel = new Parallel;
//efeito de mover
var moveP:Move = new Move;
//efeito de dimensionar
var dim:Resize = new Resize;
//definimos o target, a instancia, que será alvo do nossos efeitos
//dentro do paralel
ambos.target=this;
//movemos o painel para o x=0;
moveP.xTo=0;
// a nivel de y, movemos para o fundo da aplicação deixando apenas
//19px de altura
// que serão os mesmos 19px com que icará o painel de altura depois
//de o efeito resize
moveP.yTo=Application.application.height-19;
//efeito para dimensionar, alture=19, comprimento=150
dim.heightTo=19;
dim.widthTo=150;
//adiciona-mos o efeito de mover e dimensionar ao nosso paralel
ambos.addChild(moveP);
ambos.addChild(dim);
//duração do efeito
ambos.duration=250;
//iniciamos o efeito
ambos.play();
//usamos a variavel para indicar que o estado de minimizado está
//activo
minimizado=true;
// como está minimizado o botão de maximizar para a ser substituido
//pela imagem de restaurar
maxBut.source=rest;
//toolTip informativa
maxBut.toolTip="Restaura";
}
//Funcção chamado quando o botão de maximizar é clicado.
private function onClick(evt:MouseEvent):void {
//usamos as mesmas instancia de efeitos que no minimiza
var ambos:Parallel = new Parallel;
var dim:Resize = new Resize;
var moveP:Move = new Move;
ambos.target=this;
/**
O painel vai-se comportar da mesma maneira caso esteja
minimizado ou maximizado
já que a animação vai ser sempre a mesma = restaurar
**/
if(maximizado==true || minimizado==true ) {
/**
Definimos a altura e posição originais do nosso painel
estas posições podem ser afectadas pelo drop, por isso sao
automaticamente actualizadas.
**/
dim.heightTo=originalSizeH;
dim.widthTo=originalSizeW;
moveP.xTo=originalPosX;
moveP.yTo=originalPosY;
//passa a estar no estado original
maximizado=false;
minimizado=false;
//mudamos a imagem para maximizar
maxBut.source=max;
maxBut.toolTip="Maximiza";
//duração do efeito
ambos.duration=100;
//adicionamos como filhos do nosso paralel
ambos.addChild(dim);
ambos.addChild(moveP);
//iniciamos o efeito
ambos.play();
}
else {
/**usado para maximizar o painel caso o nosso painel esteja na
posição original:
altura em que o maximizado=false; e minimizado=false;
definimos como tamanho a totalidade da area da nossa
aplicação**/
dim.heightTo=Application.application.height;
dim.widthTo=Application.application.width;
//movemos para a posição x=y=0
moveP.xTo=0;
moveP.yTo=0;
//o seu estado passa a ser maximizado
maximizado=true;
maxBut.toolTip="Restaura";
//mudamos para a imagem maximizada
maxBut.source=rest;
//duração do efeito
ambos.duration=100;
//childs
ambos.addChild(dim);
ambos.addChild(moveP);
//play
ambos.play();
}
}
}
}
Como podem ver, o processo é muito lógico e bem simples de executar, neste momento ao adicionares o vosso customPanel a uma aplicação, ele ficará exactamente igual a um painel normal do flex, mas a magia vem na hora da execução da vossa aplicação…querem ver? cliquem aqui para ver o resultado final.
Para que este código funcione correctamente, necessitam de ter as 3 imagens correspondentes ao botão de maximizar, minimizar e restaurar, mas isso fica à vossa escolha, segue a dica do iconfinder para um esquema de icons. Gravem com os nomes: restBut.png, maxBut.png, minBut.png ou alterem o código para os vossos icons. Estes icons devem ser colocados na mesma pasta (com/msdevstudio) que o nosso customPanel.as (ficheiro em cima).
E pronto, têm um painel pronto a ser usado nas vossas aplicações que suporta Drag & Drop, Maximizar, Minimizar e Restaurar… muito simples, pratico e eficiente.
Se conseguiram entender o processo posso afirmar que estão prontos para se aventurar de armas e bagagens pelo mundo do action script e suas classes.
No Próximo tutorial iremos falar de filtros e efeitos….
Duvidas? use o forum.
Abraço.
p.s. O código não fica tabulado devido a uma falha da plugin, alguém conhece uma plugin alternativa para apresentar código as3?? No entanto segue a class customPanel para download.
package com.msdevstudio
{
//imports necessários ao nosso painel / class
//Eventos
import flash.events.Event;
import flash.events.MouseEvent;
import mx.containers.Panel;
import mx.controls.Image;
import mx.core.Application;
import mx.effects.Move;
import mx.effects.Parallel;
import mx.effects.Resize;
//extndemos o nosso painel
public class customPanel extends Panel
{
//incluimos as nossas imagens de maximizar, minimizar e resturar
//para a resposta do carregamento / troca das imagens seja imediata
[Embed(source="maxBut.png")]
public var max:Class;
[Embed(source="minBut.png")]
public var min:Class;
[Embed(source="restBut.png")]
public var rest:Class;
//variaveis
//estados do painel
private var maximizado:Boolean = false;
private var minimizado:Boolean = false;
//imagens dos botões
private var minBut:Image;
private var maxBut:Image;
//usado para guardar os tamanhos e posições originais do nosso panel
private var originalSizeW:int;
private var originalSizeH:int;
private var originalPosX:int;
private var originalPosY:int;
//construtor da nossa class
public function customPanel()
{
//definimos alguns estilos do nosso panel para ficar mais agradável
this.setStyle(“headerHeight”,19);
this.setStyle(“borderThicknessBottom”, 0);
this.setStyle(“borderThicknessLeft”, 0);
this.setStyle(“borderThicknessTop”, 0);
this.setStyle(“borderThicknessRight”, 0);
this.title=“Painel 1″;
}
//re-escrevemos a função createChildren que o componente painel usa //para definir o novo layout que ele terá, ou seja vamos adicionar //os botões
override protected function createChildren():void {
super.createChildren();
//guardamos as posições e tamanhos originais
originalSizeW=this.unscaledHeight;
originalSizeH=this.unscaledHeight;
originalPosX=this.x;
originalPosY=this.y;
//apenas vamos criar os botões se eles não existirem, temos //que fazer isto porque esta função é chamada sempre que é //adicionado um elemento novo ao painel, no caso de //adicionarem uma caixa de texto esta função é chamada de novo //e se não indicasse-mos o “if” ele iria criar novos botões //sempre que fosse chamada
//verificamos se o botão de minimizar existe
if(!minBut){
//criamos a nova imagem
minBut=new Image;
//atribuimos a class (imagem) min ao nosso botão e definimos //alguns parametros
minBut.source=min;
minBut.visible=true;
minBut.toolTip=“Minimiza”;
//a imagem mostra o icon por defeito (seta), usamos os 3 //metodos em baixo para que o botão se comporte como um icon e //apresente o cursor “hand” / mão.
minBut.mouseChildren=false;
minBut.useHandCursor=true;
minBut.buttonMode=true;
//Evento para detectar quando foi clicada.
minBut.addEventListener(MouseEvent.CLICK, minOnClick, false, 0, true);
//adicionamos como filho. Aqui adicionamos no metodo rawChildrem que faz //um “overlay” à nossa imagem e vai apresenta-la em cima do painel, se //usarmos apenas this.addChild() o nosso botão iria aparecer dentro da //area util do painel e não no topo. Poderiamos usar também //this.titleBar.addChild() onde a titlebar é o topo do nosso painel
this.rawChildren.addChild(minBut);
}
//o mesmo procedimento para a imagem de maximizar, notem que //não defini posições, elas serão definidas mais abaixo.
if(!maxBut) {
maxBut=new Image;
maxBut.visible=true;
maxBut.source=max;
maxBut.toolTip=“Maximiza”;
maxBut.mouseChildren=false;
maxBut.useHandCursor=true;
maxBut.buttonMode=true;
maxBut.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
this.rawChildren.addChild(maxBut);
}
//adicionamos um listner para saber quando o titleBar foi //clicado para iniciar o drag e drop
this.titleBar.addEventListener(MouseEvent.MOUSE_DOWN, beginDrag,false,0,true);
this.titleBar.addEventListener(MouseEvent.MOUSE_UP, endDrag,false,0,true);
// actualiza a displayList.
invalidateDisplayList();
}
//aqui vamos subscrever o metdo chamado pelo invalidateDisplayList() //que vai ser chamado sempre que existam modificações a fazer no // nosso layout, em cima como lhe adcionei duas imagens forcei a
//chamada da função em baixo para poder definir as posições dos meus //botões.
protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
//definimos os tamanhos da nossa imagem
//ela por defeito está com 16px por 16px mas vamos certificar- //nos que elas ficam com esses tamanhos
minBut.setActualSize(16,16);
maxBut.setActualSize(16,16);
//vamos definir a posição x e y dos nossos botões
// o unscaledWidth indica-nos o tamanho “on-execution” do //nosso painel, ou seja o tamanho actual, poderiamos usar o // this.width, mas provocaria falhas no posicionamento visto //que se o painel for aumentado esta actualização do //this.height teria que aguardar pela actualização da //displayList, ou seja, o tamanho final depois de maximizado //apenas estaria disponivel no final da execução desta função.
// colocamos o botão de minimizar à direita do painel, mas //deixamos um espaço em px para o botão de maximizar
// (-maxBut.width)
var xPos:Number = unscaledWidth – (minBut.width+maxBut.width);
// o botão ficará a 2px do topo
var yPos:Number = 2;
//posicionamos o botão na devida posição
minBut.move(xPos, yPos);
//usamos as mesmas variaveis em cima, mas agora para //posicionar o botão de maximizar
// como vai ficar à direita subtraimos apenas o seu tamanho ao //total do nosso painel
xPos=unscaledWidth – maxBut.width;
yPos=2;
//subtraimos 4px para que o botão fiquem mais perto do //minimizar e mais afastado da lateral direita
maxBut.move(xPos-4,yPos);
}
// chamada para iniciar o drag do panel
private function beginDrag(evt:MouseEvent):void {
this.startDrag();
}
// chamada para parar o drag do panel
private function endDrag(evt:MouseEvent):void {
this.stopDrag();
//ao parar temos que guardar a posição em que o painel foi //largado para que ao restaurar o painel ir para a ultima //posição onde foi deixado.
originalPosX=this.x;
originalPosY=this.y;
}
//chamada quando o botão de minimizar é clicado.
private function minOnClick(evt:MouseEvent):void {
//vamos inicializar alguns efeitos para executar na transição do //nosso painel para o estado minimizado
//paralel, usado para exectuatr mais que um efeito ao mesmo tempo
//os efeitos executados por este paralel serão so seus child’s //(efeitos)
var ambos:Parallel = new Parallel;
//efeito de mover
var moveP:Move = new Move;
//efeito de dimensionar
var dim:Resize = new Resize;
//definimos o target, a instancia, que será alvo do nossos efeitos //dentro do paralel
ambos.target=this;
//movemos o painel para o x=0;
moveP.xTo=0;
// a nivel de y, movemos para o fundo da aplicação deixando apenas //19px de altura
// que serão os mesmos 19px com que icará o painel de altura depois //de o efeito resize
moveP.yTo=Application.application.height-19;
//efeito para dimensionar, alture=19, comprimento=150
dim.heightTo=19;
dim.widthTo=150;
//adiciona-mos o efeito de mover e dimensionar ao nosso paralel
ambos.addChild(moveP);
ambos.addChild(dim);
//duração do efeito
ambos.duration=250;
//iniciamos o efeito
ambos.play();
//usamos a variavel para indicar que o estado de minimizado está //activo
minimizado=true;
// como está minimizado o botão de maximizar para a ser substituido //pela imagem de restaurar
maxBut.source=rest;
//toolTip informativa
maxBut.toolTip=“Restaura”;
}
//Funcção chamado quando o botão de maximizar é clicado.
private function onClick(evt:MouseEvent):void {
//usamos as mesmas instancia de efeitos que no minimiza
var ambos:Parallel = new Parallel;
var dim:Resize = new Resize;
var moveP:Move = new Move;
ambos.target=this;
//O painel vai-se comportar da mesma maneira caso esteja //minimizado ou maximizado
//já que a animação vai ser sempre a mesma = restaurar
if(maximizado==true || minimizado==true ) {
//definimos a altura e posição originais do nosso painel
//estas posições podem ser afectadas pelo drop, por isso sao //automaticamente actualizadas
dim.heightTo=originalSizeH;
dim.widthTo=originalSizeW;
moveP.xTo=originalPosX;
moveP.yTo=originalPosY;
//passa a estar no estado original
maximizado=false;
minimizado=false;
//mudamos a imagem para maximizar
maxBut.source=max;
maxBut.toolTip=“Maximiza”;
//duração do efeito
ambos.duration=100;
//adicionamos como filhos do nosso paralel
ambos.addChild(dim);
ambos.addChild(moveP);
//iniciamos o efeito
ambos.play();
}
else {
//usado para maximizar o painel caso o nosso painel esteja na //posição original:
//altura em que o maximizado=false; e minimizado=false;
//definimos como tamanho a totalidade da area da nossa //aplicação
dim.heightTo=Application.application.height;
dim.widthTo=Application.application.width;
//movemos para a posição x=y=0
moveP.xTo=0;
moveP.yTo=0;
//o seu estado passa a ser maximizado
maximizado=true;
maxBut.toolTip=“Restaura”;
//mudamos para a imagem maximizada
maxBut.source=rest;
//duração do efeito
ambos.duration=100;
//childs
ambos.addChild(dim);
ambos.addChild(moveP);
//play
ambos.play();
}
}
}
}




4 Comentários
Muito interessante seu exemplo, para ficar melhor só faltou o código estar com identação …
Abraço!
Oi Marcelo, pois é… mas esse é um problema da plugin… no entanto coloquei a class para download no final
Abraço!
Mario,
Não se se vou falar besteira, mas no meu blog, eu estava escrevendo uma série de tutoriais sobre objective-c e tinha vários problemas em relação aos códigos digitados. Ele fica hospedado no blogger, o que resolveu foi colocar o código entre as tags só desta forma eu resolvi.
Abraços.
Pierre
Muito bom…
parabéns pelo tutorial. É muito explicito e útil …