Problemas com TabNavigator Customizado

Pessoal, eu comecei a mexer com Flex há pouco tempo, e estou tentando usá-lo pra fazer a interface de um trabalho de facul - um webmessenger. Pra manter o código organizado, resolvi customizar alguns componentes, separando a lógica de cada um… Só que por alguma razão, quando eu acrescento meu VBox customizado ao TabNavigator, os labels estão invisíveis e o Rich Text Editor não aceita texto, como se estivesse tudo desabilitado ou com algum erro.

Tenho a impressão de que deve ser algum esquecimento bobo, mas como não conheço muito de Flex, não sei o que está faltando. Segue o código (a parte de mensageria está comentada porque estava testando só a parte gráfica mesmo).

COMPONENTE QUE EU USO PRAS TABS:

[code]package myComp
{
import flash.events.MouseEvent;

import mx.containers.VBox;
import mx.controls.Button;
import mx.controls.RichTextEditor;
import mx.controls.Spacer;
import mx.controls.Text;
import mx.controls.TextArea;
import mx.core.ContainerCreationPolicy;
import mx.messaging.messages.AsyncMessage;


public class UserWindow extends VBox {

	private var outputArea:Text;
	private var inputArea:RichTextEditor;
	private var send:Button;
	private var _userOwner:String;
	private var _interlocutor:String;
	//private var producer:Producer;
	
	
	public function UserWindow(interlocutor:String, userOwner:String) {
	
		super();
		
		this.creationPolicy = ContainerCreationPolicy.ALL;
		_interlocutor = interlocutor;
		_userOwner = userOwner;
		this.label = interlocutor;
		this.id = interlocutor;
		this.name = userOwner;
		this.setStyle("horizontalAlign", "center");
		
		outputArea = new Text();
		outputArea.percentHeight = 70;
		outputArea.percentWidth = 100;
		outputArea.id = interlocutor + "WindowOutput";
		outputArea.name = interlocutor + "WindowOutput";
		this.addChild(outputArea);
		
		inputArea = new RichTextEditor();
		inputArea.height = 100;
		inputArea.percentWidth = 100;
		inputArea.setStyle("fontSize", 12);
		inputArea.setStyle("fontFamily", "Verdana");
		inputArea.id = interlocutor + "WindowInput";
		inputArea.name = interlocutor + "WindowInput";
		this.addChild(inputArea);
		
		this.addChild(new Spacer());
		
		send = new Button();
		send.label = "send message";
		send.id = interlocutor + "SendButton";
		send.name = interlocutor + "SendButton";
		send.addEventListener(MouseEvent.CLICK, sendMessage);
		this.addChild(send);
		
		/* producer = new Producer();
		producer.id = interlocutor + "Producer";
		producer.destination = "onemessenger";
		producer.subtopic = "messenger." + interlocutor; */
	}
	
	
	public function sendMessage(mouseClick:MouseEvent) : void {
		
		var message:AsyncMessage = new AsyncMessage();
		message.body = inputArea.htmlText;
		message.headers["sender"] = _userOwner;
		//producer.send(message);
		
		inputArea.textArea.setSelection(0, 0);
		inputArea.textArea.setFocus();
	}
	
	
	public function receiveMessage(messageBody:String) : void {
		
		outputArea.htmlText += "<P align=\"left\">";
		outputArea.htmlText += "<FONT face=\"Verdana\" size=\"12\" color=\"#000000\">";
		outputArea.htmlText += _interlocutor + " says: </FONT>";
		outputArea.htmlText += messageBody;
		outputArea.htmlText += "</P>";
	}
}

}[/code]

TABNAVIGATOR

[code]package myComp
{
import mx.containers.TabNavigator;
import mx.core.ContainerCreationPolicy;
import mx.messaging.MultiTopicConsumer;
import mx.messaging.events.MessageEvent;
import mx.messaging.messages.AsyncMessage;

public class SendReceiveUI extends TabNavigator {
	
	private var allUserWindows:Object;
	//private var consumer:MultiTopicConsumer;
	private var _userOwner:String;
	
	
	public function SendReceiveUI(userOwner:String) {
		
		super();
		
		_userOwner = userOwner;
		allUserWindows = new Object();
		this.id = userOwner + "SendReceive";
		this.name = userOwner + "SendReceive";
		this.creationPolicy = ContainerCreationPolicy.AUTO;
		
		/* consumer = new MultiTopicConsumer();
		consumer.id = userOwner + "Consumer";
		consumer.destination = "onemessenger";
		consumer.addEventListener(MessageEvent.MESSAGE, receiveGenericMessage);
		consumer.addSubscription("messenger." + userOwner);
		consumer.addSubscription("control");
		consumer.subscribe(); */
	}
	
	 
	public function userWindowExists(user:String) : Boolean {
		
		return allUserWindows.hasOwnProperty(user);
	}
	
	
	public function receiveGenericMessage(messageEvt:MessageEvent) : void {
		
		var received:AsyncMessage = messageEvt.message as AsyncMessage;
		var msgHeaders:Object = received.headers;
		
		if (msgHeaders[AsyncMessage.SUBTOPIC_HEADER] == "control") {
			
			// mensagem de controle.
		
		} else {
			
			var sender:String = msgHeaders["sender"];
			var senderWindow:UserWindow = null;
			
			if (!userWindowExists(sender)) {
				
				senderWindow = new UserWindow(sender, _userOwner);
				allUserWindows[sender] = senderWindow;
				this.addChild(senderWindow);
			
			} else senderWindow = allUserWindows[sender];
			
			senderWindow.receiveMessage(received.body as String);
		}
	} 
}

}[/code]

APLICAÇÃO TESTE

[code]<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx=“http://www.adobe.com/2006/mxml” layout=“vertical” verticalAlign=“top"
horizontalAlign=“center” backgroundGradientColors=”[0x000000,0x323232]"
paddingTop=“0” viewSourceURL=“srcview/index.html” xmlns:myComp=“myComp.*” creationComplete=“onLoad()”>

<mx:Script>
	<![CDATA[
		import mx.containers.TabNavigator;
		import myComp.SendReceiveUI;
		import myComp.UserWindow;
		import mx.collections.ArrayCollection;
		import mx.controls.Label;
		import mx.containers.VBox;
		
		private var abas:Object;
		private var teste:SendReceiveUI;
		
		
		public function onLoad() : void {
			
			teste = new SendReceiveUI("Wozniak");
			teste.percentHeight = 100;
			teste.percentWidth = 100;
			pan.addChild(teste);
		}
		
		
		public function addTab() : void {
			
			var aba:UserWindow = new UserWindow("Tanenbaum", "Wozniak");
			teste.addChild(aba);
		}
		
		
		public function msg() : void {
			
			var aba:UserWindow = teste.getChildAt(0) as UserWindow;
			aba.receiveMessage("<FONT face=\"Tahoma\" size=\"14\" color=\"#000000\">Hello World!</FONT>");
		}
		
	]]>
</mx:Script>


<mx:Panel title="TabNavigator Container" layout="vertical" color="0xffffff" borderAlpha="0.15" height="100%" width="100%"
     paddingTop="10" paddingRight="10" paddingBottom="10" paddingLeft="10" horizontalAlign="center" id="pan">

    <mx:HBox>
        <mx:Button label="Criar Tab" click="addTab()" color="0x545454" />
        <mx:Button label="Enviar Mensagem Fake" click="msg()" color="0x545454" />
    </mx:HBox>
    
</mx:Panel>

</mx:Application>[/code]

Se alguém puder me dar um help, agradeço muito! =)

Só para iniciar, eu pessoalmente não faria o seu vbox em actionScript. Ele tem muita propriedade visual que seria muito mais simples e menos trabalhoso se fosse um mxml, de qualquer forma vamos seguir!

O que eu vou comentar aqui é referente ao ciclo de componentes em flex, logo não vai fazer muito sentido caso você veja esse caso isolado.

O ideal para se fazer no seu vbox, seria, dar override no métodos createChildren, e nesse método adicionar toda a criação de componentes. Só a criação mesmo, como no código abaixo. Esse método é chamado no tempo correto da criação do componente, fazendo assim seus novos objetos serem adicionados no ciclo correto.

[code]private var _b:Button;
private var _componentesCriados:Boolean = false;
override protected function createChildren():void
{
super.createChildren();
_b = new Button();
this.addChild(_b);

_componentesCriados = true;
}[/code]

Porém, só adicionar o componente não ajuda muito, pois você vai precisar arrumar sua largura, altura, estilos, etc. Para isso usamos o método updateDisplayList. Ele é chamado no ciclo correto e serve exatamente para tratar essas propriedades referente ao “visual” do componente.

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); if (_componentesCriados) { _componentesCriados = false; _b.width = _b.height = 100; } }

Note que a flag _componentesCriados é importante pois o método updateDisplayList é chamado frequentemente pela sdk, e não queremos aumentar o processamento desse método para fazer operações desnecessárias.

Pronto, com isso seu código vai ficar melhor. Mas precisamos de mais algumas coisas.

. Não adicione as propriedades id e name para seu componente. Id só é utilizado no mxml para “nomear” o objeto, e o name é gerado pela sdk.
. Os componentes, quando criados via ActionScript, eles não assumem valores de largura e altura padrão, então você precisa setar isso em algum lugar, tais como o x e o y.

Acho que isso resolverá.

[code]# <mx:Application xmlns:mx=“http://www.adobe.com/2006/mxml” layout=“vertical” verticalAlign=“top”

horizontalAlign=“center” backgroundGradientColors="[0x000000,0x323232]"

paddingTop=“0” viewSourceURL=“srcview/index.html” xmlns:myComp=“myComp.*” creationComplete=“onLoad()”>[/code]

Acredito que se voce mudar essa parte para:

[code]# <mx:Application xmlns:mx=“http://www.adobe.com/2006/mxml” layout=“vertical” verticalAlign=“top”

horizontalAlign=“center” backgroundGradientColors="[0x000000,0x323232]"

paddingTop=“0” viewSourceURL=“srcview/index.html” xmlns:myComp=“myComp.*” creationComplete=“onLoad()” creationPolicy=“All”>[/code]

Resolva

Nossa, não coloque creationPolicy=“All” na sua aplicação não.

Isso fará com que todos os objetos de todas as telas em todos os lugares, sejam criados no momento que o usuário carregar a aplicação, assim travando o browser TODO do usuário até que os componentes tenham sido criados. Essa é uma péssima experiência ao usuário.

Obrigada pela ajuda, eu finalmente consegui fazer os componentes funcionarem - embora eu tenha que confessar que mexi desordenadamente em um punhado de coisas, e por isso eu não sei bem o que foi que resolveu o problema. :oops:

Eu segui um pouco a sua sugestão, Bruno, mas transformei o tab navigator customizado em um componente mxml, ao invés do meu vbox. Isso pode ter contribuído, talvez ele tenha passado a fazer alguma inicialização que não estava sendo feita antes. O mais estranho é que em um momento eu troquei o SendReceiveUI por um TabNavigator normal e não funcionava nem assim… Aí eu peguei uma aplicação pronta com um TabNavigator e coloquei o meu componente no lugar, ajustando uns detalhezinhos estéticos como tamanho e cor, e funcionou perfeitamente.

Ah, eu experimentei sem sucesso setar a creationPolicy do SendReceiveUI e do UserWindow para ALL… Só não tentei fazer o mesmo na aplicação. Agora está funcionando, mesmo sem isso. Um dia eu descubro onde estava o galho…

Mais uma vez, agradeço pelo auxílio. :slight_smile: