leitura do artigo >

15
nov

Comunicação entre o swf carregado e o principal

Ao adicionar o objeto Loader à DisplayList, o conteúdo carregado por ele através do método load() não tem acesso ao swf principal através da DisplayList. Neste post explico um modo que permite essa comunicação entre o swf carregado e o principal.

Comentários (3) Comentários(13) Categorias Action Script3, Soluções

A classe Loader herda diretamente da classe DisplayObjectContainer, mas ela produz um erro ao tentar usar os métodos: addChild(), addChildAt(), removeChild(), removeChildAt() e setChildIndex(). Quando se usa um objeto Loader, o conteúdo carregado se torna o valor da propiedade content desse objeto, e é por isso que adicionando o objeto Loader na DisplayList é possível visualizar o conteúdo carregado. No entanto, ao adicionar o objeto Loader à DisplayList, o conteúdo carregado não tem acesso ao swf principal através dela.

Vamos fazer um exemplo para mostrar o que acontece quando o objeto Loader é adicionado à DisplayList. Crie um arquivo father1.fla e coloque a DocumentClass como Father1. Crie um arquivo de ActionScript com o nome Father1.as e coloque:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package {
 
    import flash.display.MovieClip;
    import flash.display.Loader;
    import flash.events.Event;
    import flash.net.URLRequest;
 
    public class Father1 extends MovieClip {
 
        private var loader:Loader = new Loader();
 
        public function Father1() {
 
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
            loader.load(new URLRequest("son1.swf"));
 
            function loaderComplete(e:Event) {
                addChild(loader)
            }
        }
    }
}

Agora crie um arquivo son1.fla e coloque a DocumentClass como Son1. Selecione o primeiro frame da timeline, pressione F9 para acessar o painel de ações e coloque:

trace("Timeline > parent/parent.parent: "+parent,parent.parent)

Crie um arquivo de ActionScript com o nome Son1.as e coloque:

1
2
3
4
5
6
7
8
9
10
11
12
package {
 
    import flash.display.Stage;
    import flash.display.MovieClip;
 
    public class Son1 extends MovieClip {
 
        public function Son1() {
            parent is Stage?trace("Constructor Method > parent/parent.parent: "+parent,parent.parent):trace("Constructor Method > parent: "+parent)
        }
    }
}

Feito isso, publique o son1.fla e verá o output:

Constructor Method > parent/parent.parent: [object Stage] null
Timeline > parent/parent.parent: [object Stage] null

Ao criar o son1.swf, como ele é o arquivo principal, é nele que se encontra o Stage principal e pode ser acessado usando parent (tanto pela timeline, como pelo método construtor). E parent.parent retorna null porque o Stage principal é o primeiro objeto da DisplayList.

Agora publique o father1.fla e verá o output:

Constructor Method > parent: null
Timeline > parent/parent.parent: [object Loader] null

Ao criar o father1.swf, ele carrega o son1.swf, que por sua vez é o conteúdo do objeto Loader. Ao adicionar o objeto Loader à DisplayList, ele executa o conteúdo do son1.swf (que gera o output). No output podemos ver que ao tentar acessar parent pelo método construtor de Son, o resultado vai ser null e parent.parent não é lido porque senão geraria um erro de compilação. Por outro lado, ao tentar acessar parent pela timeline, vai acessar o objeto Loader do father1.swf, porém parent.parent não acessa o contêiner do objeto Loader.


O exemplo acima mostra que adicionando o objeto Loader à DisplayList, não há forma do swf carregado se comunicar pela DisplayList com o swf principal.

No entanto, existe um modo de adicionar o conteúdo do swf carregado à DisplayList e permitir que ele se comunique com o swf principal. No lugar de adicionar o objeto Loader à DisplayList, se adiciona a propiedade content desse objeto (loader.content). Logo, você poderia acessar o swf carregado usando casting, MovieClip(loader.content), ou o swf principal também com casting, MovieClip(parent), além disso, ambas DocumentClasses deveriam ser dinâmicas. Mas para evitar tanta complicação, podemos simplificar o processo criando objetos MovieClip de referência.

Vamos fazer um exemplo de como um swf carregado pode se comunicar com o swf principal, e vice-versa, de forma simplificada. Crie um arquivo father2.fla e coloque a DocumentClass como Father2. Crie um arquivo de ActionScript com o nome Father2.as e coloque:

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
package {
 
    import flash.display.MovieClip;
    import flash.display.Loader;
    import flash.events.Event;
    import flash.net.URLRequest;
 
    public class Father2 extends MovieClip {
 
        private var son:MovieClip; 
        private var loader:Loader = new Loader();
 
        public function Father2() {
 
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
            loader.load(new URLRequest("son2.swf"));
 
            function loaderComplete(e:Event) {
                son = loader.content as MovieClip;
                addChild(son)
                son.init()
            }
 
        }
 
        public function traceMc() {
            trace("traceMc: "+son.mc) 
        }
    }
}

Agora crie um arquivo son2.fla e crie um MovieClip no palco com nome de instância mc. Coloque a DocumentClass como Son2. Selecione o primeiro frame da timeline, pressione F9 para acessar o painel de ações e coloque:

1
trace("Timeline > parent/parent.parent: "+parent,parent.parent)

Crie um arquivo de ActionScript com o nome Son2.as e coloque:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package {
 
    import flash.display.Stage;
    import flash.display.MovieClip;
 
    public class Son2 extends MovieClip {
 
        private var father:MovieClip;         
 
        public function Son2() {
            parent is Stage?trace("Constructor Method > parent/parent.parent: "+parent,parent.parent):trace("Constructor Method > parent: "+parent)
        }
        public function init() {
            father = parent as MovieClip;
            trace("init parent/parent.parent: "+parent,parent.parent)
            father.traceMc();
        }
    }
}

Feito isso, publique o son2.fla para criar o son2.swf. Não vou comentar sobre o output gerado nessa publicação porque o resultado é o mesmo do primeiro exemplo deste post. Agora publique o father2.fla e verá o output:

Constructor Method > parent: null
Timeline > parent/parent.parent: [object Loader] null
init parent/parent.parent: [object Father] [object Stage]
traceMc: [object MovieClip]

Ao criar o father2.swf, o MovieClip son é usado como referência para o conteúdo do objeto Loader e se adiciona son à DisplayList. No output podemos ver que as duas primeiras linhas dão o mesmo resultado do primeiro exemplo deste post, ou seja, mesmo adicionando o conteúdo do objeto Loader à DisplayList, não há forma do swf carregado se comunicar através da timeline ou pelo método construtor. Porém, na terceira e quarta linha do output podemos ver que essa comunicação acontece quando se chama o método son.init(), que por sua vez acessa o parent e parent.parent do swf carregado e executa o método father.traceMc() do swf principal.

Conclusão: essa comunicação é possível a partir de qualquer escopo (com exceção da timeline e método construtor) e permite acessar instâncias e métodos (com exceção do construtor) declarados no escopo principal da DocumentClass, e também objetos adicionados ao palco em tempo de edição.

Postado em 15-11-2009 por Igor Amendola
em Action Script3, Soluções

Share/Save/Bookmark

Comentários

  • Bruno Monteiro disse:
    em 15 de novembro de 2009

    preimeiro!
    \o/

    muito bom iguu!!

  • Bruno Monteiro disse:
    em 15 de novembro de 2009

    OO

    merd@! eu disse que não ia ler…

    =/

  • Rodrigo Lucas - Ne disse:
    em 16 de novembro de 2009

    ;D outra otima explicação do Igor
    :)

  • Eder Lima disse:
    em 16 de novembro de 2009

    Ae Igor!!
    Mais um hein, esse é super útil também, interagir swfs carregados e seus ‘pais’ é muito necessário, em quase tudo.

    Excelente! Parabénzão!! =D

  • Igor Amendola disse:
    em 17 de novembro de 2009

    valeuuuuuuuuuu, galera \o/
    :D

  • Álvaro Gomides disse:
    em 17 de novembro de 2009

    iguis é mára XD
    mto bom mesmo!

  • Pedro Lins disse:
    em 18 de novembro de 2009

    Opa!
    Ótima publicação Iguis.
    Eu particularmente acho esse um tópico super especial, e de grande valia!

  • Victor C Tavernari disse:
    em 15 de dezembro de 2009

    Muito bom.. :P

    Parabens

  • Tiago disse:
    em 6 de janeiro de 2010

    Parabéns brow, mto bom mesmo esta sua explicação.. me quebrou uma galháásso!

    Só tenho uma dúvida, e se eu quiser acessar uma função e não um MovieClip? Tentei son.minhaFuncao(); e nao pega.

    vlw

  • Igor Amendola disse:
    em 7 de janeiro de 2010

    Olá Tiago,
    você também pode acessar uma função, mas ela deve ser declarada no escopo da classe e que tenha um namespace que permita o acesso (por exemplo: ‘public’).
    Dá uma olhada no segundo exemplo que mostra como fazer isso.
    Obrigado! :D

  • André Rodrigues disse:
    em 24 de junho de 2010

    Amigo, vendo seu tutorial eu vejo que as vezes as pessoas que criam os “códigos de programação” tem [editado] na cabeça…

    Antigamente em AS2 eu usava simplesmente _root.funcao(); no swf filho e ele executava a funcao q se encontrava no swf pai….

    agora em as3 eu simplesmente estou a 2 dias tentando descobrir um meio de fazer isso, e adivinha soh?! NAUM TEM!

    Essa volta gigante aí pra mim não é meio… não é possível que transformem uma coisa tao simples em algo tão complexo :/

  • André Rodrigues disse:
    em 24 de junho de 2010

    Bom, finalmente achei algo que resolveu meu problema, pra quem tiver a mesma dúvida, simpples, prático e rápido:

    http://forum.imasters.uol.com.br/index.php?/topic/368182-resolvido-container-pai/

  • Eder Lima disse:
    em 24 de junho de 2010

    André, eu estava digitando ainda quando fui chamado pra uma reunião e logo em seguida voltei e vc tinha colocado a resposta, segue uma solução.

    Além de adicionar o pai como objeto (o que nem de longe é uma volta gigante ou algo complexo), você pode usar classes do tipo SingleTon.

    E isso implica em algo semelhante, porém mais organizado e estruturado do que a solução que você viu no Imasters.

    Uma classe Singleton pode ser usada a partir de qualquer nível de uma aplicação, site ou etc, basta você utilizar a instância dela no filme que vc precisar, basicamente funciona assim:
    Você inicia a classe a partir de qualquer filme, passa os parâmetros que ela precisa, e a partir daí qualquer outro filme pode acessar, exemplo didático (uma classe que dê um trace na tela):

    //No filme pai father.swf (iniciamos a classe tracer que tem um método: “trace(message:String)” que será disparado a partir do filho)
    var tracer:Tracer = Tracer.getInstance();

    //filme pai carrega filme filho.swf, adiciona ao palco, etc
    //filme filho utiliza a função tracer
    var tracer:Tracer = Tracer.getInstance();
    tracer.trace(“mensagem disparada do filho”);

    Isso também funciona com eventos, você pode criar uma Classe Singleton somente para disparar eventos, onde dados precisem ser compartilhados entre vários filhos e o pai.
    Métodos existem, você é quem precisa julgar qual método é melhor para sua aplicação.
    Os 3 métodos funcionam, hoje eu prefiro o uso de singletons, outros preferem disparar eventos genéricos, outros preferem o MovieClip(parent.parent.parent).

    Eu uso o padrão que comentei no exemplo do DeepLink, onde a Classe DynamicNavigator pode ser disparada de qualquer parte do site, o que faz o site carregar um novo canal.

    Vou preparar um material básico sobre SingleTons, você verá que é bem melhor:
    http://www.flashpedia.com.br/2010/05/navegacao-dinamica-e-deeplinking-com-swfaddress/

    []‘s

 Escreva um Comentário

Seu nome

E-mail (não será publicado) (obrigatório)

Website

Comente

Spam protection by WP Captcha-Free