Arquivo

Arquivo da Categoria ‘Flex Fast Code’

Criando um Custom Panel - Minimizar - Maximizar - Fechar.

18, maio, 2009 admin 1 comentário

Criando um Custom Panel.

Salve pessoal.
Na maioria dos projetos em que participo ou participei, são comuns os clientes ou usuários finais quererem telas nas quais tenha os botões de maximizar, minimizar, fechar e até mesmo outros tipos de componentes no topo do Panel. Hoje irei demonstrar como criar este componente de uma maneira simples e eficaz. Então vamos ao primeiro passo.
Este componente será similar ao FlexMdi, no qual hoje este faz parte do pacote flexlib.
Passo 1:
Certo primeiramente iremos criar um projeto Flex com a seguinte estrutura de pastas.

Estrutura

Com a estrutura acima criada vamos criar uma classe ‘as’ chamada BaseCustomPanel a qual irá estender um Panel. Esta classe será à base de todas as futuras telas e por sua vez não irá conter os botões de maximizar, minimizar e fechar. Porém a mesma lhe dará a total flexibilidade de adicionar qualquer componente no header (Topo - Cabeçalho) do Panel. Abaixo segue o código AS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.imaster.customPanel {
 
	import flash.display.DisplayObject;
 
	import mx.containers.Panel;
	import mx.core.Application;
	import mx.core.UIComponent;
	import mx.effects.Blur;
	import mx.events.FlexEvent;
	import mx.managers.PopUpManager;
 
	[Style(name="headerHorizontalGap", type="Number", inherit="no")]
	/**
	 * @author Fabiel Prestes
	 */
	public class BaseCustomPanel extends Panel {
 
		/**
		 * Aqui será armazenado todos os componente FILHOS que serão adicionados
		 * ao HEADER
		 */
		[ArrayElementType("mx.core.UIComponent")]
		public var arrayFilhos:Array = [];
 
		private var blurIn:Blur;
 
		/**
		 * Construtor Padrao
		 */
		public function BaseCustomPanel() {
			super();
		}
 
		/**
		 * @inheritDoc
		 */
		override protected function childrenCreated():void {
			super.childrenCreated();
 
			configStyle();
 
			/* Para cada Filho adicionado no objeto 'arrayFilhos'
			 * será realizado algumas configurações como:
			 * Adiciona-lo no HEADER do PANEL
			 * Propriedade buttonMode = true ....*/
			for each (var child:UIComponent in arrayFilhos)
				addTitleBarComponent(child);
		}
 
		/**
		 * @private
		 */
		private function abreComEfeito():void{
			blurIn = new Blur();
			blurIn.blurXFrom = 10;
			blurIn.blurXTo = 0;
			blurIn.blurYFrom = 10;
			blurIn.blurYTo = 0;
			blurIn.duration = 600;
			blurIn.play([this]);
		}
 
		/**
		 * Realizando a configuração padrão dos Estilos
		 */
		private function configStyle():void {
			this.setStyle("headerHorizontalAlign", "rigth");
			this.setStyle("headerVerticalAlign", "middle");
			this.setStyle("headerHorizontalGap", 5);
		}
 
		/**
		 * @inheritDoc
		 */
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
			super.updateDisplayList(unscaledWidth, unscaledHeight);
 
			reposicioneElementosNoCabecalho();
		}
 
		/**
		 * Reposiciona todos os componentes FILHOS ao PAI 'HEADER'
		 */
		protected function reposicioneElementosNoCabecalho():void {
			var componenteFilho:UIComponent;
			var posicaoX:Number = 0;
			var tamanhoPai:Number = 0;
			var posicaoY:Number = 0;
			var headerHorizontalGap:Number = getStyle('headerHorizontalGap');
 
			/* Caso não tenha sido adicionado Nenhum filho, deve apenas retornar e continuar
			 * o processamento natural. */
			if (arrayFilhos.length == 0)
				return;
 
			tamanhoPai = this.width - 10;
 
			/* Para cada filho Definido para ser adicionado no cabeçalho deve ser
			 * verificado seu tamanho para assim ser posicionado no componente HEADER do PANEL. */
			for (var i:int; i < arrayFilhos.length; i++) {
				componenteFilho = UIComponent(arrayFilhos[i]);
				componenteFilho.setActualSize(componenteFilho.getExplicitOrMeasuredWidth(), componenteFilho.getExplicitOrMeasuredHeight());
 
				/* Abaixo é pego a altura do HEADER do PANEL subtraido com a altura do COMPONENTE filho
				 * e DIVIDIDO por 2, afim de pegar o valor que será definido no Y. Desta maneira
				 * o filho ficará no meio do HEADER. */
				posicaoY = (getHeaderHeight() - componenteFilho.getExplicitOrMeasuredHeight()) / 2;
 
				/* Abixo é pego o tomanho total do PANEL subtraido com o tamanho total do COMPONENTE
				 * filho SUBTRAIDO com o HORIZONTAL GAP, afim de pegar o valor que será definido no X.
				 * Desta maneira os componente FILHOS ficarão sempre a DIREITA do PANEL.
				 * A variavel TAMANHOPAI e tambem sempre recebe o resultado desta subtração para que assim
				 * os FILHOS não irão ficar sobre postos um ao outro.*/
				posicaoX = tamanhoPai - componenteFilho.getExplicitOrMeasuredWidth() - headerHorizontalGap;
				tamanhoPai = posicaoX;
 
				/* Move o componente FILHO para o X e Y calculado anteriormente. */
				componenteFilho.move(posicaoX, posicaoY);
			}
		}
 
		/**
		 * Responsavel por Adicionar o Filho ao HEADER e realizar algumas pré configurações
		 */
		public function addTitleBarComponent(child:UIComponent):void {
			child.buttonMode = true;
 
			/* Este metodo é responsavel por adicionar o FILHO ao HEADER do PANEL. */
			titleBar.addChild(child);
 
			invalidateDisplayList();
		}
 
		public function openPanel():void{
			PopUpManager.addPopUp(this, DisplayObject(Application.application));
			PopUpManager.centerPopUp(this);
			abreComEfeito();
		}
	}
}

OK, com a nossa classe base criada iremos agora realizar uma extensão da mesma, fazendo algumas alterações como inclusão dos botões de minimizar, maximizar e fechar.
Segue abaixo o código da classe WindowPanel.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
package com.imaster.customPanel {
	import com.imaster.event.WindowPanelEvent;
 
	import flash.events.MouseEvent;
	import flash.filters.GlowFilter;
 
	import mx.containers.Box;
	import mx.controls.Image;
	import mx.core.UIComponent;
	import mx.effects.Blur;
	import mx.effects.Move;
	import mx.effects.Parallel;
	import mx.effects.Resize;
	import mx.effects.Sequence;
	import mx.events.EffectEvent;
	import mx.managers.PopUpManager;
	import mx.utils.ObjectUtil;
 
	[Event(name="minimixar", type="com.imaster.event.WindowPanelEvent")]
	[Event(name="maximizar", type="com.imaster.event.WindowPanelEvent")]
	[Event(name="fechar", type="com.imaster.event.WindowPanelEvent")]
	/**
	 * @author Fabiel Prestes
	 */
	public class WindowPanel extends BaseCustomPanel {
 
		private var imgFechar:Image;
		private var imgMaximizar:Image;
		private var imgMinimizar:Image;
 
		private var glow:GlowFilter;
 
		private var sequenceMinimizar:Sequence;
 
		private var parallelMaximizar:Parallel;
		private var moveMaximizar:Move;
		private var resizeMaximizar:Resize;
 
		private var parallelMinimizar:Parallel;
		private var resizeMinimizar:Resize;
		private var moveMinimizar:Move;
 
		private var widthOriginal:Number;
		private var heightOriginal:Number;
 
		[Bindable]
		private var xOriginal:Number;
 
		[Bindable]
		private var yOriginal:Number;
 
		public var panelPai:UIComponent;
		public var barra:Box;
 
		/**
		 * Contrutor Padrão
		 */
		public function WindowPanel() {
			super();
		}
 
		/**
		 * @inheritDoc
		 */
		override protected function childrenCreated():void{
			this.setStyle("styleName", "windowpanel");
 
			configBotoes();
 
			super.childrenCreated();
 
			widthOriginal = ObjectUtil.copy(this.width) as Number;
			heightOriginal = ObjectUtil.copy(this.height) as Number;
 
			configEfeitoBotoes();
		}
 
		/**
		 * @private
		 * Metodo responsavel por guarda a posição X e Y atual da tela para que
		 * assim ao maximizar a tela a mesma volte para a sua posição original.
		 */
		private function trateMouseUpMinimizar(evt:MouseEvent):void{
			xOriginal = this.x;
			yOriginal = this.y;
		}
 
		/**
		 * @private
		 * Responsavel por criar e configurar os botoes de Maximizar, Minimizar e Fechar.
		 */
		private function configBotoes():void{
 
			imgMaximizar = new Image();
			imgMaximizar.source = "assets/img/maximizar.png";
			imgMaximizar.width = 20;
			imgMaximizar.height = 20;
 
			imgMinimizar = new Image();
			imgMinimizar.source = "assets/img/minimizar.png";
			imgMinimizar.width = 20;
			imgMinimizar.height = 20;
 
			imgFechar = new Image();
			imgFechar.source = "assets/img/fechar.png";
			imgFechar.width = 20;
			imgFechar.height = 20;
 
			imgMaximizar.addEventListener(MouseEvent.MOUSE_OVER, trateMouseOver);
			imgMaximizar.addEventListener(MouseEvent.MOUSE_OUT, trateMouseOut);
			imgMaximizar.addEventListener(MouseEvent.CLICK, trateMaximizarClick);
 
			imgMinimizar.addEventListener(MouseEvent.MOUSE_OVER, trateMouseOver);
			imgMinimizar.addEventListener(MouseEvent.MOUSE_OUT, trateMouseOut);
			imgMinimizar.addEventListener(MouseEvent.CLICK, trateMinimizarClick);
			imgMinimizar.addEventListener(MouseEvent.MOUSE_UP, trateMouseUpMinimizar);
 
			imgFechar.addEventListener(MouseEvent.MOUSE_OVER, trateMouseOver);
			imgFechar.addEventListener(MouseEvent.MOUSE_OUT, trateMouseOut);
			imgFechar.addEventListener(MouseEvent.CLICK, trateFecharClick);
 
			this.arrayFilhos.push(imgFechar);
			this.arrayFilhos.push(imgMaximizar);
			this.arrayFilhos.push(imgMinimizar);
		}
 
		/**
		 * @private
		 * Responsavel por instanciar e configurar os efeitos que serão realizados
		 * pelo click do mouse nas imagens no HEADER.
		 */
		private function configEfeitoBotoes():void{
			/* Este efeito será utilizado quando o mouse estiver em cima do botoes/imagens
			 * no HEADER */
			glow = new GlowFilter();
            glow.color = 0xffffff;
            glow.blurX = glow.blurY = 20;
		}
 
		/**
		 * @private
		 * Responsavel por instanciar e configurar os efeitos que serão realizados
		 * pelo click do mouse na imagem de Maximizar.
		 */
		private function configEfeitoMaximizar():void{
 
            if(moveMaximizar == null){
            	moveMaximizar = new Move(this);
	            moveMaximizar.duration = 600;
            }
 
			moveMaximizar.xFrom = barra.x;
			moveMaximizar.yFrom = barra.y;
 
            moveMaximizar.xTo = xOriginal;
            moveMaximizar.yTo = yOriginal;
 
            if(resizeMaximizar == null){
	            resizeMaximizar = new Resize(this);
 
	            resizeMaximizar.heightTo = heightOriginal;
	            resizeMaximizar.widthTo = widthOriginal;
	            resizeMaximizar.duration = 600;
            }
 
			if(parallelMaximizar == null){
				parallelMaximizar = new Parallel(this);
 
	            parallelMaximizar.addChild(moveMaximizar);
	            parallelMaximizar.addChild(resizeMaximizar);
   			}
		}
 
		/**
		 * @private
		 * Responsavel por instanciar e configurar os efeitos que serão realizados
		 * pelo click do mouse na imagem de Minimizar.
		 */
		private function configEfeitoMinimizar():void{
			if(resizeMinimizar == null){
	            resizeMinimizar = new Resize(this);
	            resizeMinimizar.widthTo = 200;
	            resizeMinimizar.heightTo = 35;
	            resizeMinimizar.duration = 600;
			}
 
			if(moveMinimizar == null){
	            moveMinimizar = new Move(this);
	            moveMinimizar.duration = 600;
			}
 
			var filhosBarra:int = barra.getChildren().length;
 
			if(filhosBarra >= 1){
				moveMinimizar.xTo = (barra.getChildAt(0).width + 10) * filhosBarra;
			}else{
	            moveMinimizar.xTo = barra.x;
			}
 
            moveMinimizar.yTo = barra.y; 
 
            if(parallelMinimizar == null){
	            parallelMinimizar = new Parallel();
            	parallelMinimizar.addChild(resizeMinimizar);
	            parallelMinimizar.addChild(new Blur());
	            parallelMinimizar.addChild(moveMinimizar);
            }
 
			if(sequenceMinimizar == null){
	            sequenceMinimizar = new Sequence(this);
				sequenceMinimizar.addChild(parallelMinimizar);
	            sequenceMinimizar.addEventListener(EffectEvent.EFFECT_END, trateFimEfeitoMinimizar);
			}
		}
 
		/**
		 * @private
		 * Trata o OVER do mouse nas imagens do HEADER
		 */
		private function trateMouseOver(evt:MouseEvent):void{
            evt.currentTarget.filters =[glow];
		}
 
		/**
		 * @private
		 * Trata o OUT do mouse nas imagens do HEADER
		 */
		private function trateMouseOut(evt:MouseEvent):void{
			evt.currentTarget.filters = [];
		}
 
		/**
		 * @private
		 * Trata o CLICK da imagem maximizar do HEADER
		 */
		private function trateMaximizarClick(evt:MouseEvent):void{
			barra.removeChild(this);
			PopUpManager.addPopUp(this, panelPai);
 
			configEfeitoMaximizar();
			parallelMaximizar.play();
			this.dispatchEvent(new WindowPanelEvent(WindowPanelEvent.MAXIMIZAR));
		}
 
		/**
		 * @private
		 * Trata o CLICK da imagem mniimizar do HEADER
		 */
		private function trateMinimizarClick(evt:MouseEvent):void{
			configEfeitoMinimizar();
			sequenceMinimizar.play();
		}
 
		/**
		 * @private
		 * Trata o CLICK da imagem fechar do HEADER
		 */
		private function trateFecharClick(evt:MouseEvent):void{
			var blur:Blur = new Blur(this);
            blur.blurXFrom = 0;
            blur.blurYFrom = 0;
            blur.blurXTo = 10;
            blur.blurYTo = 10;
            blur.duration = 600;
            blur.addEventListener(EffectEvent.EFFECT_END, trateFimEfeitoFechar);
			blur.play();
		}
 
		/**
		 * @private
		 * Apos terminar o efeito de minimizar, é dispachado o evento do tipo MINIMIZAR
		 */
		private function trateFimEfeitoMinimizar(evt:EffectEvent):void{
			barra.addChild(this);
			this.dispatchEvent(new WindowPanelEvent(WindowPanelEvent.MINIMIZAR));
		}
 
		/**
		 * @private
		 * Apos terminar o efeito de mafechar, é dispachado o evento do tipo FEHCAR
		 * e logo em seguida a tela é removida.
		 */
		private function trateFimEfeitoFechar(evt:EffectEvent):void{
			try{
				PopUpManager.removePopUp(this);
				barra.removeChild(this);
				panelPai.removeChild(this);
			}catch(er:Error){}
			this.dispatchEvent(new WindowPanelEvent(WindowPanelEvent.FECHAR));
		}
	}
}

O grande detalhe desta classe é que esta armazena a referência de seu Parent (Pai) e da barra onde a mesma ficará minimizada.
Na mesma foi incluído efeitos diferentes em cada ação de botão, por exemplo.
Botão Minimizar: Foi aplicado um efeito paralelo no qual a tela vai se movimentando (Move) e se redimensionando (Resize) até atingir a barra de minimização, com um pequeno Blur ao final.
Botão Maximizar: Neste existe apenas o efeito Resize, deixando mais simples.
Botão Fechar: Neste também foi aplicado apenas o efeito Blur simples mais bem atrativo aos olhos do usuário final, pois se assemelha bastante com o efeito que o Windows Vista oferece.
Também foi aplicado nos botões um efeito de Glow, no momento em que o usuário passa o mouse por cima dos botões, efeito bem similar ao Vista.
Todos os botões tem listener Mouse.Click e Mouse.Mouse_Over e para cada um destes possuem seus próprios comportamentos, porem a cada fim de comportamento os mesmos dispacham seus próprios eventos, afim de tornar mais flexível a sua utilização pelos outros desenvolvedores que utilizarão seu coponente.
É um componente relativamente simples para a construção e agora vocês verão que também é de simples aplicação. Vamos as classes de teste.
WindowPanelTeste.mxml, uma simples classe que extende o WindowPanel e adiciona um VBox com um background Cinza.

Main.mxml, uma simples classe de teste. A mesma já é instanciada com duas janela WindowTeste criada como default, também possui um botão para adicionar novas janelas testes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
		<![CDATA[
			import com.imaster.WindowPanelTeste;
			import mx.managers.PopUpManager;
			import mx.controls.PopUpButton;
			import com.imaster.customPanel.WindowPanel;
 
			public var filhos:Number = 1;
 
			private function init():void{
				var tela:WindowPanelTeste = new WindowPanelTeste();
				tela.panelPai = this;
				tela.barra = hbBarra;
				tela.title = "Tela 1";
 
				PopUpManager.addPopUp(tela, this);
				PopUpManager.centerPopUp(tela);
 
				var tela2:WindowPanelTeste = new WindowPanelTeste();
				tela2.panelPai = this;
				tela2.barra = hbBarra;
				tela2.title = "Tela 2";
 
				PopUpManager.addPopUp(tela2, this);
				PopUpManager.centerPopUp(tela2);
			}
 
			private function novaJanela():void{
				var tela:WindowPanelTeste = new WindowPanelTeste();
				tela.panelPai = this;
				tela.barra = hbBarra;
				tela.title = "Nova Janela";
				tela.openPanel();
			}
		]]>

Aí esta um componente simples e flexível. Muitos devem até estar se perguntando, o “porque de se criar este componente se já existe outros.?”. Certamente já existem componentes similares a este, contudo a questão aqui é demonstrar em maneira simples como é possível criar seus próprios componentes e não ficar dependendo da comunidade ou dos criadores do mesmo para resolverem problemas com as lib. E com certeza a partir deste componente você poderá deixá-lo muito mais robusta e atraente basta usar a criatividade.
Espero mais uma vez ter ajudado e até a próxima. Abaixo segue o link do source para download

Exemplo Funcionando:

This movie requires Flash Player 9

Categories: Flex, Flex Fast Code Tags:

Internacionalizando (I18n) Aplicações Flex

3, maio, 2009 admin 1 comentário

Salve pessoal,

Hoje irei demonstrar como deixar sua aplicação multi-idiomas de uma maneira simples e facil.

Em grandes projetos web uma das principais preocupações dos arquitetos é a internacionalização do projeto. Fazer com que os usuários possam acessar e utilizar a aplicação sem ter que se preocupar com com a língua é um dos principais pontos positivos para um projeto se destacar no mercado.Visando isso os arquitetos da Adobe aperfeiçoaram o recurso de internacionalização do Flex 3, este recurso é chamado de ResourceBundle.
Desta maneira ficou muito simples e flexivel aplicar I18n veja porque:

1 - Você pode compilar recursos para várias localidades em uma única aplicação ou módulo.
2 - Você acessar todos os recursos através do ResourceManager, no qual pode gerenciar os recursos para várias localidades.
Você pode mudar em tempo de execução a localidade do recurso.
3 - Você também pode usar imagens, sons, etc, e não apenas Strings

Estes são apenas uns dos melhoramentos e vantagens de utilizar o ResourceBundle do Flex 3. O ResourceBundle possuim algumas exigências como criar um arquivo Locale para cada idioma, contudo existe uma forma de burlar isso utilizando arquivos properties.

Neste artigo irei demonstrar como aplicar I18n usando o ResourceManager sem ter criar arquivos Locales. I18n com ResourceBundle

Primeiramente iremos criar um projeto Flex, irei chama-lo de Flex_I18n_A. No projeto crie uma nova pasta chamada I18n nesta crie os seguintes arquivos XML: pt_BR, en_US e es_ES.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="iso-8859-1"?>
<locale lang="en_US">
	<property key="titulo_app" value="Applying I18n in Flex applications" />
	<property key="usuario" value="Username" />
	<property key="senha" value="Password" />
	<property key="login_erro" value="User credentials are wrong. Please try again" />
	<property key="bt_login" value="Login" />
	<property key="bt_logout" value="Logout" />
	<property key="msg_boas_vindas" value="User logged in successfully." />
	<property key="idioma" value="Language" />
	<property key="selecione_idioma" value="Select a language." />
</locale>
 
<?xml version="1.0" encoding="iso-8859-1"?>
<locale lang="pt_BR">
	<property key="titulo_app" value="Aplicando I18n em aplicações Flex." />
	<property key="usuario" value="Usuário" />
	<property key="senha" value="Senha" />
	<property key="login_erro" value="Dados incorretos. Tente novamente." />
	<property key="bt_login" value="Login" />
	<property key="bt_logout" value="Sair" />
	<property key="msg_boas_vindas" value="Usuário logado com sucesso." />
	<property key="idioma" value="Idioma"/>
	<property key="selecione_idioma" value="Selecione um idioma."/>
</locale>
 
<?xml version="1.0" encoding="iso-8859-1"?>
<locale lang="es_ES">
	<property key="titulo_app" value="Aplicando i18n aplicaciones en Flex." />
	<property key="usuario" value="Nombre de Usuario" />
	<property key="senha" value="Contraseña" />
	<property key="login_erro"
		value="Credenciales de usuario se equivoca. Por favor, inténtelo de nuevo." />
	<property key="bt_login" value="Inicio de sesión" />
	<property key="bt_logout" value="Cerrar sesión" />
	<property key="msg_boas_vindas" value="Usuario conectado correctamente." />
	<property key="idioma" value="Idioma" />
	<property key="selecione_idioma" value="Seleccione un idioma."/>
</locale>

Agora com os três arquivos criados iremos criar a classe que irá fazer o carregamento dos arquivos xml.
Para cada key do XML será setado na propriedade content do ResourceBundle, desta maneira poderemos usar o metodo getString para pegar o value internacionalizado da key.

Agora iremos criar a classe com/flexI18n/utils/ConfigI18n

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.flexI18n.utils {
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
 
	import mx.resources.ResourceBundle;
	import mx.resources.ResourceManager;
 
	/**
	 * @author Fabiel Prestes
	 */
	public class ConfigI18n {
 
		private var resourceBundle:ResourceBundle;
 
		[Bindable]
		public var currentLocale:String = "pt_BR";
 
		public function ConfigI18n() {
			super();
		}
 
		/**
		 * Carrega o xml locale baseado na String passada como parametro.
		 */
		public function loadLocale(locale:String= "pt_BR"):void {
			currentLocale = locale;
			var xmlLoader:URLLoader = new URLLoader();
			xmlLoader.addEventListener(Event.COMPLETE, createBundle);
			xmlLoader.load(new URLRequest("I18n/" + currentLocale + ".xml"));
		}
 
        /**
        * @private
        * Apos o xml ser carregado com sucesso, deve-se pegar cada chave (key) e valor 
        * (value) e adicionar no resourceBundle, para assim ser acessado em qualquer local da aplicação.
        * @eventType Event
        */
        private function createBundle(e:Event):void {
            var propertyList:XMLList = new XML(e.target.data).property;
 
            resourceBundle = new ResourceBundle(currentLocale, "ApplicationResource");
 
            for each (var property:XML in propertyList) {
            	resourceBundle.content[property.@key] = property.@value;
            }
 
            ResourceManager.getInstance().addResourceBundle(resourceBundle);
            ResourceManager.getInstance().update();
            ResourceManager.getInstance().localeChain = [currentLocale,"pt_BR"];
        }
	}
}

Apenas uma observação na classe ConfigI18n, nós criamos uma variavel ResourceBundle aplicamos todas as mensagens internacionalizadas do XML e por final pegamos nosso resource e aplicamos no ResourceManager cujo este é um singleton, lembrando que sempre apos adicionar um novo resource deve-se fazer um update no ResourceManager para que todas as alterações sem efetivadas.

Outro detalhe é que quando XML terminou de ser carregado, foi instanciado o ResourceBundle e assim definido um nome para o Locale e um identificador para o BundleName. É através deste identicador que conceguiremos recurar as mensagens internacionalidas do ResourceManager.

OK, com a classe resposavel por carregar e configurar o ResourceBundle vamos criar uma tela de login para para demonstrar a autilização do ResourceBundle.

Agora iremos criar a classe com/flexI18n/views/LoginUI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="100%" height="100%">
 
	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import mx.managers.PopUpManager;
			import com.flexI18n.utils.ConfigI18n;
 
			[Bindable] public var availableLocales:Array = [ {label:"English", data:"en_US"},
															 {label:"Portuguese", data:"pt_BR"},
			                                                 {label:"Spanish", data:"es_ES"} 
			                                               ];
 
 
			private function onLogin(e:Event):void {
				PopUpManager.removePopUp(this);
				Alert.show(resourceManager.getString('ApplicationResource','msg_boas_vindas'));
			}
 
			private function comboChangeHandler():void {
                var locale:ConfigI18n = new ConfigI18n();
                locale.loadLocale(localeComboBox.selectedItem.data);
                this.localeComboBox.selectedIndex = -1;
			}
 
		]]>
	</mx:Script>
	<mx:Form width="100%">
		<mx:FormItem label="{resourceManager.getString('ApplicationResource','usuario')}">
			<mx:TextInput id="username" width="200"/>
		</mx:FormItem>
		<mx:FormItem label="{resourceManager.getString('ApplicationResource','senha')}" direction="horizontal">
			<mx:TextInput id="password" displayAsPassword="true"  width="200"/>
		</mx:FormItem>
		<mx:FormItem label="{resourceManager.getString('ApplicationResource','idioma')}">
			<mx:ComboBox id="localeComboBox" selectedIndex="-1"
                dataProvider="{availableLocales}"
                change="comboChangeHandler()"
             	width="200" prompt="{resourceManager.getString('ApplicationResource','selecione_idioma')}"/>
		</mx:FormItem>
	</mx:Form>
	<mx:ControlBar width="100%" horizontalAlign="right">
		<mx:Button label="{resourceManager.getString('ApplicationResource','bt_login')}"
			click="onLogin(event)" enabled="{username.text != '' &amp;&amp; password.text != ''}"  x="517" y="118"/>
	</mx:ControlBar>
 
</mx:TitleWindow>

Se vocês olharem a classe acima, não foi em nenhum momento instanciado um objeto ResourceBundle, mais então de onde saiu
a variavel resourceBundle usada. Muito simples estamos usando o atributo da classe UIComponent.

A classe main fica da seguinte maneira.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="initApp()">
 
	<mx:Script>
		<![CDATA[
			import mx.managers.PopUpManager;
			import com.flexI18n.views.LoginUI;
			import com.flexI18n.utils.ConfigI18n;
 
			private function initApp():void{
				new ConfigI18n().loadLocale();
 
				var login:LoginUI = new LoginUI();
				PopUpManager.addPopUp(login, this, true);
				PopUpManager.centerPopUp(login);
			}
		]]>
	</mx:Script>
 
</mx:Application>

É isso aí, uma maneira simples e facil de fazer sua aplicação ficar multi-idioma.
Espero ter ajudado e até a próxima.

Categories: Flex, Flex Fast Code Tags:

Criando Colunas Dinâmicamente em DataGrid

26, março, 2009 admin 1 comentário

Olá pessoal,

Hoje irei postar mais um Flex Fast Code. Neste irei mostrar a aplicação do pattern Factory Method para criação de colunas
de DataGrid, agora não se limitem em apenas colunas. Nesta classe factory poderão conter outros modelos de criação.

Agora vamos ao codigo.

Classe FactoryDataGrid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
 * Visitem www.fabielprestes.com.br, tudo sobre Java e Flex.
 */
package com.fabielprestes.factory{
 
	import mx.controls.dataGridClasses.DataGridColumn;
 
 
	/**
	 * @author Fabiel Prestes
	 */
	public class FactoryDataGrid{
 
		public function FactoryDataGrid(){
		}
 
		/**
		 * metodo responsavel por criar e retornar um DataGridColumn baseado nos parametros
		 * passados.
		 * 
		 * @param String HeaderText of column.
		 * @param String dateFild of column.
		 * @param uint Width of column.
		 * @param String TextAlign of column.
		 * @param Boolean If the column will be editable.
		 * 
		 * @return DataGridColumn 
		 */
		public static function crieColuna(headerText:String, dataField:String, widht:uint, 
			textAlign:String, editable:Boolean = false):DataGridColumn{
 
			var novaColuna:DataGridColumn = new DataGridColumn();
			novaColuna.headerText = headerText;
			novaColuna.dataField = dataField;
			novaColuna.width = widht;
			novaColuna.setStyle("textAlign",textAlign);
			novaColuna.editable = editable;
 
			return novaColuna;
		}
	}
}

Pronto agora vamos criar a classe Application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
 
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import com.fabielprestes.factory.FactoryDataGrid;
 
			private function addColuna():void{
				var colunas:Array = dg.columns;
 
				colunas.push(FactoryDataGrid.crieColuna(tiNomeCol.text, "",Number(tiTamanhoCol.text),cbAlinhamento.selectedLabel,false));
 
				dg.columns = colunas; 
			}
 
		]]>
	</mx:Script>
	<mx:DataGrid id="dg" width="100%" height="50%">
		<mx:columns>
			<mx:DataGridColumn id="colCod" headerText="Código" width="20" textAlign="center"/>
			<mx:DataGridColumn id="colNome" headerText="Nome" width="100" textAlign="center"/>
		</mx:columns>
	</mx:DataGrid>
 
	<mx:Panel horizontalAlign="right" paddingRight="10" paddingBottom="10">
		<mx:Form width="50%">
			<mx:FormItem label="Nome Coluna">
				<mx:TextInput id="tiNomeCol"/>
			</mx:FormItem>
			<mx:FormItem label="Tamanho Coluna">
				<mx:TextInput id="tiTamanhoCol"/>
			</mx:FormItem>
			<mx:FormItem label="Alinhamento">
				<mx:ComboBox id="cbAlinhamento">
					<mx:Array>
						<mx:String>center</mx:String>
						<mx:String>left</mx:String>
						<mx:String>right</mx:String>
					</mx:Array>
				</mx:ComboBox>
			</mx:FormItem>
		</mx:Form>
		<mx:Button label="Adicionar Coluna" click="addColuna()"/>
	</mx:Panel>
 
</mx:Application>

Exemplo Funcionando:

This movie requires Flash Player 9
.

Categories: Flex Fast Code Tags:

Integrando Flex com Java

17, março, 2009 admin 7 comentários

Salve pessoal,

Hojei estarei mostrando como integrar Flex com o Java, ainda vejo bastante pessoas com duvida em como realizar esta integração.
Apesar de ser bastante simples existem alguns detalhes que devem ser levados em consideração.

Para este post iremos criar dois projetos um Java_Integracao e um Flex_Integracao, lembrando que também é possivel realizar a integração utilizando apenas um projeto, no qual contém tanto os fontes Java quanto Flex.

Utilizaremos o projeto OpenSource BlazeDs licença LGPL para fazer a integração e comunicação entre o Java e o Flex. Atualmente o BlazeDs é o projeto Java sever-side mais utilizado pelas empresas e pelas comunidades.

As principais caracteristicas do Blaze são:

  • Facil integração dos projeto Flex e Air com back-end Java.
  • Alto desempenho em trasferências de dados.
  • Free e OpenSource

No Kit de download do Blaze a adobe fornece algumas aplicações de exemplo, vale a pena dar um confirida no arquivoblazeds-samples.war.
Ao extrair o blaze para uma pasta qualquer você deve ter percebido que ele ja vem com um tomcat, contudo iremos utilizar nosso proprio tomcat. A unica diferença entre os dois é que a Adobe já fornece um tomcat com todas a libs do blaze dentro do tomcat, contudo muitas destas libs não são importantes para este exemplo de integração.

Os requisitos para que o Blaze funcione 100% são:

  1. JDK 1.5 or higher.
  2. Java Servlet Container 2.3 or higher.
  3. Flex SDK 3.2
  4. Flash Player 9

Para mais detalhes sobre o BlazeDs entre no site http://opensource.adobe.com/wiki/display/blazeds/BlazeDS/.

Requisitos para a realização da Integração:

  1. Tomcat 6
  2. Java 6
  3. BlazeDs 3.x
  4. Sdk Flex 3.x
  5. Eclipse, FelxBuilder ou NetBeans. Obs: Contudo irei utilizar o Eclipse Ganymed

Neste post irei assumir que você sabe configurar Tomcat, Java e o Eclipse. Neste exemplo de integração não irei fazer o uso persistência a uma base de dados, estaremos utilizando objetos em memoria.

Para instalar o Sdk Flex é muito simples, basta apenas utilizar o padrão NNF (Next > Next > Finish) do windows.

Agora que você já está com todos os requisitos OK, vamos para a melhor parte.

Passo 1: Criação de um projeto java Dynamic Web Project.

ø Com o eclipse aberto vá em File > New > Project ou ctrl + N.
ø Selecione a pasta Web > Dynamic Web Project.
Com isso irá ser aberta um tela de configuração de seu Web Project.

1 - Em Project Name informe: Java_Integracao
2 - Em Target Runtime selecione a configuração de seu Tomcat.
Caso você não tenha um Server configurado faça o seguinte:

2.1 - Selecione New ao lado de Target Runtime, fazendo isso irá aparecer um nova tela de configuração
New Server Runtime Environment.
2.2 - Escolha Apache > Apache Tomcat 6.0 e selecione a opção Create a new local
server
isso nos poupará trabalho futuro pois isso fará com que após a configuração do server o eclipse crie um
novo Project Server, agora clique em next.
2.3 - Nesta segunda você deverá escolher um nome para o seu server, informar onde o seu tomcat esta instalado e escolher a
versão JRE, clique em finish. Pronto agora você tem um Server Runtime configurado.
Após informar o Target Runtime apenas clique em finish, agorá você já tem o seu projeto Java criado e pré configurado.

Passo 2: Configurando um nome de contexto.
ø Quando você terminou de criar seu projeto Java_Integracao o eclipse automaticamente já configurou um nome de contexto, este
alias é utilizado pelo Server para poder executar sua aplicação de dentro da IDE Eclipse. Assim caso voce deseje alterar este
nome sega os seguintes passos:

2.1 - Clique com o botão direito sobre o projeto e clique em Properties.
2.2 - Selecione Web Project Settings. Nesta tela terá apenas um campo chamado Context
Root
o nome default deste campo é proprio nome do projeto no nosso caso “Java_Integracao”.

Passo 3: Adicionando as lib necessárias.
ø Libs do BlazeDs

  1. backport-util-concurrent.jar
  2. commons-fileupload-1.1.jar
  3. commons-httpclient-3.0.1.jar
  4. commons-io-1.1.jar
  5. commons-logging.jar
  6. flex-bootstrap.jar
  7. flex-messaging-common.jar
  8. flex-messaging-core.jar
  9. flex-messaging-remoting.jar

Passo 4: Criando os arquivos de configuração do BlazeDS

ø Na pasta/WebContent/WEB-INF crie uma pasta chamada flex, nesta irtá conter todos os
arquivos que o blazeDS necessita para poder realizar a comunicação de sua aplicação Flex com Java.
Após criar a pasta flex você deve criar 2 arquivos.

1 - remoting-config.xml

O Remoting Service permite uma aplicação cliente o acesso a métodos de objetos do lado do servidor Java, sem configurar
os objetos como serviços web. Para acessar objeto do lado do servidor, o cliente Flex irá utilizar o componente RemoteObjetct
do proprio Sdk do Flex.
O RemoteObject é declatado em classes MXML ou ActionScript para se conecatar com serviços remotos. usa-se o RemoteObject
para chamar metodos em classes Java ou ColdFusion.

Mas para o RemoteObjetc saber qual classe Java buscar, você deve configurar o arquivo remoting-config.xml e incluir uma tag
chamada , esta tag contem um atributo chamado “id” isto define um alias para a sua classe Java e o
seu RemoteObject irá utilizar este alias em suas propriedades. Definido o ID você deve definir o source (caminho) de sua classe
Java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service" class="flex.messaging.services.RemotingService">
 
    <adapters>
        <adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
    </adapters>
 
    <default-channels>
        <channel ref="my-amf"/>
    </default-channels>
 
    <destination id="facadeContato">
        <properties>
            <source>com.fabielprestes.facade.FacadeContato</source>
        </properties>
    </destination>
 
  </service>

2 - services-config.xml

Este é considerado um arquivo de alto nivel, onde se localizam as configurações mais importantes. Neste é possivel definir
esquemas de segurança, difinir canais e outros serviços. Não estarei entrando em detalhes sobre este arquivo.

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
 
    <services>
        <service-include file-path="remoting-config.xml" />
 
    	<!-- 
    	Application level default channels. Application level default channels are 
    	necessary when a dynamic destination is being used by a service component
    	and no ChannelSet has been defined for the service component. In that case,
    	application level default channels will be used to contact the destination.
        -->   
        <default-channels>
           <channel ref="my-amf"/>
        </default-channels>
 
	</services>
 
 
    <channels>
        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
            <properties>
                <polling-enabled>false</polling-enabled>
            </properties>
        </channel-definition>
    </channels>
 
    <logging>
        <!-- You may also use flex.messaging.log.ServletLogTarget -->
        <target class="flex.messaging.log.ConsoleTarget" level="Error">
            <properties>
                <prefix>[BlazeDS] </prefix>
                <includeDate>false</includeDate>
                <includeTime>false</includeTime>
                <includeLevel>true</includeLevel>
                <includeCategory>false</includeCategory>
            </properties>
            <filters>
                <pattern>Endpoint.*</pattern>
                <pattern>Service.*</pattern>
                <pattern>Configuration</pattern>
            </filters>
        </target>
    </logging>
 
    <system>
        <redeploy>
            <enabled>true</enabled>
            <watch-interval>20</watch-interval>
            <watch-file>{context.root}/WEB-INF/flex/services-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/remoting-config.xml</watch-file>
            <touch-file>{context.root}/WEB-INF/web.xml</touch-file>
        </redeploy>
    </system>
 
</services-config>

Pronto agora com todos os arquivos criados podemos continuar a configuração do projeto. Agora iremos alterar o arquivo web.xml de nossa aplicação.

ø web.xml

Neste arquivo você deve indicar ao container que estamos utilizando o BlazeDs. Assim você deve inserir algumas tags de configuração. Edite seu arquivo para ficar desta maneira.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
 
	<display-name>Java_Integracao</display-name>
 
	<!-- MessageBroker Servlet -->
	<servlet>
		<servlet-name>MessageBrokerServlet</servlet-name>
		<servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
		<init-param>
			<param-name>services.configuration.file</param-name>
			<param-value>/WEB-INF/flex/services-config.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>MessageBrokerServlet</servlet-name>
		<url-pattern>/messagebroker/*</url-pattern>
	</servlet-mapping>
 
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>Flex_Integracao.html</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>Flex_Integracao.html</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
</web-app>

Ok, agora seu projeto Java_Integracao esta totalmente configurado esperando apenas para começar a implementação, mais antes disso agora iremos configurar o projeto Flex_Integracao.

Passo 1: Criando Projeto Flex_Integracao

ø Com o eclipse aberto vá em File > New > Project ou ctrl + N.
ø Selecione a pasta Web > Flex Project.
Com isso irá ser aberta um tela de configuração de seu Flex Project.

1 - Em Project Name informe: Flex_Integracao
As outras opções você pode deixar como estão, agora clique em next.

2 - Na proxima tela na opção Output folder URL http://localhost:8080/Java_Integracao

3 - Clique em finish e seu projeto estará criado com sucesso.

Passo 2: Incluindo parametro no compilador do Flex

ø Agora temos de informar ao compilador do Flex que existe um servidor de AMF levantado.

1 - Clique com botão direito no projeto Flex_Integracao > Properties > Selecione
Flex Compiler
> em Additional compiler arguments
adicione a linha -services Caminho real do projeto Java_integracao+”/WebContent/WEB-INF
flex/services-config.xml”
. Ex: c:/dev/Java_integracao//WebContent/WEB-INF/flex/services-config.xml
Clique em OK, prontinho agora o seu projeto Flex já esta totalmente configurado.

Passo 3: Configurando Output Folder

ø Agora temos de informar para o projeto Flex onde ele deve gerar os arquivos swf, html, history e etc, deve-se fazer isso para que consigamos rodar a aplicação de dentro da IDE de desenvolvimento, para isso faça:

1 - Clique em browser. Aqui você irá apontar para a pasta WebContent do seu projeto Java_Integracao, isso fará com que os seus arquivos html template e swf irão ser alocados em seu projeto java.

Final das configurações

Daqui em diante começa a melhor parte, a implementação.

Para este exemplo estaremos criando uma agenda telefônica, onde o usuario poderá inserir um novo contato, excluir um contato existente e alterar um contato existente.

Obs: Lembrando que nesta Agenda não irei utilizar um padrão que pode ser seguido em projetos reais e também não estarei fazendo uso de algum framework como o Carnigorn, Pure MVC etc. Este exemplo é apenas para efeito didático.

Vamos começar com as classes Java

Iremos criar os seguintes pacotes.

  • com.fabielprestes.facade
  • com.fabielprestes.model.entidades

No pacote com.fabielprestes.model.entidades crie as seguintes classes:

Contato.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.fabielprestes.model.entidades;
 
public class Contato {
 
	private String nome;
 
	private String fone;
 
	private String endereco;
 
	public Contato(){
	}
 
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public String getFone() {
		return fone;
	}
	public void setFone(String fone) {
		this.fone = fone;
	}
	public String getEndereco() {
		return endereco;
	}
	public void setEndereco(String endereco) {
		this.endereco = endereco;
	}
}

RespostaRemota.java Esta será a classe responsável pelo trafego de objetos entre o Flex e o Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.fabielprestes.model.entidades;
 
public class RespostaRemota {
 
	private boolean status;
 
	private Object valueObject;
 
	public RespostaRemota(){
		super();
	}	
	public boolean isStatus() {
		return status;
	}
	public void setStatus(boolean status) {
		this.status = status;
	}
	public Object getValueObject() {
		return valueObject;
	}
	public void setValueObject(Object valueObject) {
		this.valueObject = valueObject;
	}
 
	public void crieRespostaErro(Object value) {
		this.setStatus(false);
		this.setValueObject(value);
	}
 
	public void crieRespostaSucesso(Object value) {
		this.setStatus(true);
		this.setValueObject(value);
	}
}

No pacote com.fabielprestes.facade crie a seguinte classe:

FacadeContato.java Esta será a classe que o RemoteObject usará para se comunicar o servidor.
Esta classe não fará nada demais, apenas irá verificar se os campos foram preenchidos caso não preenche com valores default.
No post Parte 2 iremos aplicar persistencia neste projeto.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.fabielprestes.facade;
 
import com.fabielprestes.model.entidades.Contato;
import com.fabielprestes.model.entidades.RespostaRemota;
 
public class FacadeContato {
 
	private RespostaRemota resposta;
 
	public RespostaRemota crieNovoContato(Contato contato) throws Exception{
		resposta = new RespostaRemota();
		try {
			if(contato == null)
				throw new Exception("Contato está nulo.", null);
 
			if(contato.getEndereco().equals(""))
				contato.setEndereco("Endereço desconhecido.");
 
			if(contato.getNome().equals(""))
				contato.setNome("Nome desconhecido.");
 
			if(contato.getFone().equals(""))
				contato.setFone("Telefone desconhecido.");
 
			resposta.crieRespostaSucesso(contato);
		} catch (Exception e) {
			resposta.crieRespostaErro(e.getMessage());
		}
		return resposta;
	}
}

OK! Todas as classes java necessárias para este post são estas acima. Agora iremos criar as classes do Flex.

Como dito anteriomente iremos criar uma agenda de contatos, onde o usuário poderá criar um novo contato inserindo o nome, telefone e seu endereço..

OBS: Nesta primeira parte do post a nossa aplicação apenas irá inserir novos contatos e lista-los em um DataGrid, já na parte back-end nós não iremos persistir este contato em um banco de dados ou algo do genero, nós apenas iremos verificar se todos os atributos foram devidamente preenchidos, caso não estejam iremos inserir dados default. Agora não se preocupem em nossa serie Integrando Flex com Java - Parte 2 iremos modificar este mesmo projeto para realizar as devidas persistencias em um banco de dados, contudo iremos por etapas para sre mais simples de entender a integração.

Agora que todo o “Bla Bla Bla” foi explicado vamos ao enteressa, as classes Flex.

Neste projeto Flex_Integracao teremos dois pacotes.

  • com.fabielprestes.model - Objetos de Negócios
  • com.fabielprestes.view - Objetos de Visão
  • com.fabielprestes.view.ascript - Objetos de Controle da Visão

No pacote com.fabielprestes.model crie as seguintes classes:

ContatoDAO.as classe responsável por criar um objeto RemoteObject, o qual irá abir uma conexão com o servidor Java e disparar uma chamada no mesmo.
Algo a se notar, esta classe extende a classe EventDispatcher, isso foi feito com o seguinte propósito, como nós não estamos utilizando um framework como o Cairngorm o qual tem suas classes Service, Delegate, ModelLocator entre outras que ficam monitorando as respostas do server e assim avisar as classes ou objetos que estas já podem mudar seu comportamento e assim por diante. Não entrarei em discução sobre o Cairngorm neste post, pois este terá um outro post apenas para ele.

Nes post nós iremos fazer tudo o que o Cairngorm faz só que na unha mesmo.
Beleza voltando a classe EventDispatcher, a classe ContatoDAO extente ela para que quando esta receba a resposta de uma chamado do servidor o DAO seja capaz de enviar um aviso a classe controller de origem que o processamento no server foi realizado com sucesso ou não e assim realizar o comportamento configurado.

Se nós não tivessemos extendido esta classe seria impossível amarrarmos um evento a ela, ou seja, sem isso seria impossivel de a classe controler saber o resultado do processamento do server.
Iremos ver a amarração na classe Agenda.as. Mais aí segue um exemplo:

1
2
3
4
5
var contatoDAO:ContatoDAO = new ContatoDAO();
 
/* O "addEventListener" só pode ser feito graças a classe EventDispatcher. */
contatoDAO.addEventListener(ContatoEvent.CONTATO_CRIADO, trateContatoCriado);
contatoDAO.crieNovoContato(crieContatoDaTela());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.fabielprestes.model{
	import flash.events.EventDispatcher;
 
	import mx.controls.Alert;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.remoting.mxml.RemoteObject;
 
	/**
	 * @author Fabiel Prestes 
	 */
	public class ContatoDAO extends EventDispatcher{
 
		private var _remote:RemoteObject;
 
		protected var respostaRemota:RespostaRemota;
 
		private var contatoEvent:ContatoEvent;
 
		public function ContatoDAO(){
			/* Criando uma instancia do objeto RemoteObject, no qual será utilizado para 
			 * enviar uma chamada par ao Java. */
			_remote = new RemoteObject();
 
			/* Alterando o comportamento do mouse */
			_remote.showBusyCursor = true;
 
			/* Setando o alias destino que definimos no arquivo remoting-config.xml anteriormente */
			_remote.destination = "facadeContato";
		}
 
		/**
		 * Metodo responsavel por enviar ao Servidor Java uma requisição para
		 * persistir um objeto Contato.
		 * @param Doenca
		 */
		public function crieNovoContato(contato:ContatoVO):void{
			this._remote.addEventListener(ResultEvent.RESULT, trateContatoCriadoSucesso);
			this._remote.addEventListener(FaultEvent.FAULT, trateErroDAO);
			this._remote.crieNovoContato(contato);
		}
 
		/**
		 * @private
		 * Trate a resposta que o servidor enviou da chamada <b>crieNovoContato</b>
		 */
		private function trateContatoCriadoSucesso(evt:ResultEvent):void{
			respostaRemota = evt.result as RespostaRemota;
 
			/* Caso o Status seja TRUE isso indica que não houve nenhuma Exception disparada
			 * no processamento do metodo 'crieNovoContato' */
			if(respostaRemota.status){
				contatoEvent = new ContatoEvent(ContatoEvent.CONTATO_CRIADO);
				contatoEvent.valueObject = respostaRemota.valueObject as ContatoVO;
			}else{
				contatoEvent = new ContatoEvent(ContatoEvent.CONTATO_ERRO);
				contatoEvent.valueObject = respostaRemota.valueObject.toString();
			}
 
			/* Dispara o nosso evento personalizado */
			this.dispatchEvent(contatoEvent);
		}
 
		/**
		 * @private
		 * Metodo responsavel por escutar a resposta de todos os metodos do DAO 
		 * que o servidor retornou e depois mostar um alerta com o erro.
		 * @eventType FaultEvent
		 */
		protected function trateErroDAO(evt:FaultEvent):void{
			Alert.show(evt.fault.toString());
		}
	}
}

ContatoEvent.as Classe que contém eventos personalizados (não entrarei em detalher sobre eventos personalizados.) e que serão disparados a cada resposta do servidor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.fabielprestes.model{
 
	import flash.events.Event;
 
	public class ContatoEvent extends Event{
 
		public static const CONTATO_CRIADO:String = "contatoCriado";
		public static const CONTATO_ERRO:String = "contatoErro";
 
		public var valueObject:Object;
 
		public function ContatoEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false){
			super(type, bubbles, cancelable);
		}
 
	}
}

ContatoVO.as Esta classe é exatamente o espelho da classe Contato no projeto Java_Integracao, apenas lembrando esta classe ContatoVO não precisa ter exatamente os mesmos atributos que a classe java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.fabielprestes.model{
 
	import flash.events.Event;
 
	/**
	 * @author Fabiel Prestes
	 */
	public class ContatoEvent extends Event{
 
		public static const CONTATO_ALTERADO:String = "contatoAlterado";
		public static const CONTATO_CRIADO:String = "contatoCriado";
		public static const CONTATO_DELETADO:String = "contatoDeletado";
		public static const CONTATO_ERRO:String = "contatoErro";
 
		public var valueObject:Object;
 
		public function ContatoEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false){
			super(type, bubbles, cancelable);
		}
 
	}
}

RespostaRemota.as Esta classe serve apenas para trafegar os objetos entre o Java e o Flex nós poderiamos trafegar o objeto Contato diretamente entre as aplicações, contudo uma classe de transporte pode deixar mais flexível a camada de DAO.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.fabielprestes.model {
 
	/**
	 * @author Fabiel Prestes
	 */
	[RemoteClass(alias="com.fabielprestes.model.entidades.RespostaRemota")] 
	public class RespostaRemota {
 
		private var _status:Boolean;
 
		private var _valueObject:Object;
 
		public function RespostaRemota() {
 
		}
 
		public function get status():Boolean{
			return _status;
		}
 
		public function set status(value:Boolean):void{
			_status = value;
		}
 
		public function get valueObject():Object{
			return _valueObject;
		}
 
		public function set valueObject(value:Object):void{
			_valueObject = value;
		}
 
	}
}

No pacote com.fabielprestes.view crie a seguinte classe:

AgendaUI.mxml Esta classe terá apenas os componentes gráficos do Flex como DataGrid, Botões e etc. Contudo estes componentes não terão nenhum comportamento, esta caracteristica ficará a cargo da classe Agenda.as, já que esta será o controller.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"
	paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5" backgroundColor="#B4D0ED">
 
	<mx:DataGrid width="100%" height="80%" id="dgContato">
		<mx:columns>
			<mx:DataGridColumn headerText="Nome" dataField="nome"/>
			<mx:DataGridColumn headerText="Telefone" dataField="fone"/>
			<mx:DataGridColumn headerText="Endereço" dataField="endereco"/>
		</mx:columns>
	</mx:DataGrid>
 
	<mx:ApplicationControlBar width="100%" height="20%">
		<mx:Form width="50%" height="50%">
			<mx:FormItem label="Nome">
				<mx:TextInput id="tiNome"/>
			</mx:FormItem>
			<mx:FormItem label="Telefone">
				<mx:TextInput id="tiFone"/>
			</mx:FormItem>
			<mx:FormItem label="Endereco">
				<mx:TextInput id="tiEnd"/>
			</mx:FormItem>
		</mx:Form>
 
		<mx:VBox height="50%" width="50%" horizontalAlign="right">
			<mx:Button label="Inserir" width="70" id="btInserir"/>
			<mx:Button label="Limpar" width="70" id="btLimpar"/>
		</mx:VBox>
	</mx:ApplicationControlBar>
</mx:VBox>

No pacote com.fabielprestes.view.ascript crie a seguinte classe:

Agenda.as Nesta classe serão realizados e definidos todos os comportamentos da nossa agenda.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package com.fabielprestes.view.ascript{
 
	import com.fabielprestes.model.ContatoDAO;
	import com.fabielprestes.model.ContatoEvent;
	import com.fabielprestes.model.ContatoVO;
	import com.fabielprestes.view.AgendaUI;
 
	import flash.events.MouseEvent;
 
	import mx.collections.ArrayCollection;
	import mx.controls.Alert;
	import mx.events.FlexEvent;
	import mx.events.ListEvent;
 
	/**
	 * @author Fabiel Prestes
	 */
	public class Agenda extends AgendaUI{
 
		private var contatoDAO:ContatoDAO;
 
		[Bindable]
		private var arrayContato:ArrayCollection = new ArrayCollection();
 
		public function Agenda(){
			super();
 
			this.addEventListener(FlexEvent.CREATION_COMPLETE, init);
		}
 
		/**
		 * @private
		 */
		private function init(evt:FlexEvent):void{
			this.btLimpar.addEventListener(MouseEvent.CLICK, trateLimpar);
			this.btInserir.addEventListener(MouseEvent.CLICK, trateInserir);
 
			this.dgContato.dataProvider = arrayContato;
		}
 
		/**
		 * @private
		 */
		private function trateLimpar(evt:MouseEvent):void{
			limpeForm();
		}
 
		/**
		 * @private
		 * Disparado no clique do botao inserir.
		 * Dispara uma chamada de criar novo contato ao model DAO e amarra um evento de resposta.
		 */
		private function trateInserir(evt:MouseEvent):void{
			contatoDAO = new ContatoDAO();
			contatoDAO.addEventListener(ContatoEvent.CONTATO_CRIADO, trateContatoCriado);
			contatoDAO.crieNovoContato(crieContatoDaTela());
			limpeForm();
		}
 
		/**
		 * @private
		 * Trata a resposta que o model recebeu do servidor.
		 */
		private function trateContatoCriado(evt:ContatoEvent):void{
			if(evt.valueObject is ContatoVO){
				arrayContato.addItem(evt.valueObject as ContatoVO);
				Alert.show("Contato criado com sucesso.","Informação");
			}else{
				Alert.show(evt.valueObject.toString(),"Informação");
			}
		}
 
		/**
		 * @private
		 * Cria um objeto Contato baseado no formulario.
		 */
		private function crieContatoDaTela():ContatoVO{
			var contato:ContatoVO = new ContatoVO();
			contato.nome = this.tiNome.text;
			contato.fone = this.tiFone.text;
			contato.endereco = this.tiEnd.text;
 
			return contato;
		}
 
		/**
		 * Limpa todos os campos do formulario.
		 */
		public function limpeForm():void{
			this.tiEnd.text = "";
			this.tiFone.text = "";
			this.tiNome.text = "";
		}
	}
}

Beleza pessoal agora tando o projet Java_Integracao quanto o Flex_Integracao estão com todas as classes criadas, basta apenas executar a aplicação.

Passos para a execução da aplicação.

  1. Start o servidor TomCat
  2. Clique com o botão direito em cima do Projeto Flex > Run As > Flex Application

Pronto isso fará o seu browser padrãos ser iniciado com a aplicação rodando e agora e só diversão.

Então é isso pessoal, espero ter ajudado a todos e qualquer dúvida ou sugestão entrem em contato. Estarei prontamente para atende-los.

Aqui está o link para baixar os dois projetos.
E fiquem atentos estarei lançando um screencast deste post.
E também logo estarei lançando a segunda parte da serie de “Integrando Flex com Java Parte 2 - Agora fazendo uso de persistencia dos objetos” :)

Categories: Flex Fast Code, Java Tags:

Aplicando efeito de Rotação e Escalamento em imagens

12, março, 2009 admin Sem comentários

Ola pessoal,

Este é mais Flex Fast Code, neste irei mostar como aplicar o efeito de rotação em imagens juntamente irei aplicar um efeito Fade.

Este Flex Code é muito simples tendo grau de dificuldade 1.

  • Resumindo este Code tem 2 HSlider. O primeiro implica diretamente na rotação da imagem conforme for deslizando a barra,

já o segundo implica no tamanho da imagem.

Classe mxml.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
	width="450" height="300" horizontalScrollPolicy="off" viewSourceURL="srcview/index.html">
 
	<mx:HBox id="barra" top="10" left="10" horizontalAlign="center">  
		<mx:HSlider minimum="-30" maximum="30" value="-10" toolTip="Rotação" 
			change="minhaImagem.rotation = event.currentTarget.value" liveDragging="true"/>  
 
		<mx:HSlider minimum="100" maximum="200" value="100" toolTip="Tamanho" 
			change="minhaImagem.height = event.currentTarget.value" liveDragging="true"/>  
 
		<mx:CheckBox label="Visivel" change="minhaImagem.visible = event.currentTarget.selected" selected="true"/>  
	</mx:HBox>  
 
	<mx:Image id="minhaImagem" height="100" top="60" left="30" rotation="-10" source="@Embed('img/Blue hills.jpg')">  
		<mx:filters>  
			<mx:DropShadowFilter/>  
		</mx:filters>  
		<mx:showEffect>  
			<mx:Fade alphaFrom="0" alphaTo="1" duration="1000"/>  
		</mx:showEffect>  
		<mx:hideEffect>  
			<mx:Fade alphaFrom="1" alphaTo="0" duration="1000"/>  
		</mx:hideEffect>  
	</mx:Image> 
</mx:Application>

Exemplo Funcionando:

This movie requires Flash Player 9

Categories: Flex Fast Code Tags:

Criando uma barra de menu similar ao Mac

10, março, 2009 admin 1 comentário

Salve pessoal,

Hoje vou demonstar como criar uma barra de menu similar ao do Mac usando apenas os efeitos nativos do Flex.
Existe uma lib chamada Fish eye que realiza este mesmo processo com algumas melhorias, vale a pena dar uma olhada, segue o link FishEye.

Lembrando que este é um simples exemplo, depois é com vocês a tarefa de adicionar novas melhorias, mas a base esta aí.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	width="355" height="160" verticalAlign="bottom" horizontalAlign="center" 
	viewSourceURL="srcview/index.html">
 
   <mx:Script>
		<![CDATA[
 
			public function mouseOver(evt:MouseEvent):void{
				aumentar.play([evt.currentTarget]);
			}
 
			public function mouseOut(evt:MouseEvent):void{
				diminuir.play([evt.currentTarget]);
			}
 
		]]>
	</mx:Script>
 
	<mx:Resize id="aumentar" duration="150" widthTo="80" heightTo="80"/>
	<mx:Resize id="diminuir" duration="200" widthTo="40" heightTo="40"/>
 
	<mx:HBox id="providerImg" horizontalScrollPolicy="off" verticalScrollPolicy="off" 
		clipContent="true" width="100%" horizontalAlign="center" verticalAlign="bottom">
 
		<mx:Image width="40" height="40" 
			mouseOver="mouseOver(event)" mouseOut="mouseOut(event)"
			buttonMode="true" useHandCursor="true"/>
		<mx:Image source="img/Error.png" width="40" height="40" 
			mouseOver="mouseOver(event)" mouseOut="mouseOut(event)"
			buttonMode="true" useHandCursor="true"/>
		<mx:Image source="img/TimeIntervals.png" width="40" height="40" 
			mouseOver="mouseOver(event)" mouseOut="mouseOut(event)"
			buttonMode="true" useHandCursor="true"/>
		<mx:Image source="img/ChartTypes.png" width="40" height="40" 
			mouseOver="mouseOver(event)" mouseOut="mouseOut(event)"
			buttonMode="true" useHandCursor="true"/>
	</mx:HBox>
 
</mx:Application>

This movie requires Flash Player 9

Categories: Flex Fast Code Tags: