Neste tutorial vai ser explicado como utilizar os metodos Drag & Drop no Flex. Em muitos dos objectos/componentes do flex, estas propriedades estão já implementadas e a sua utilização é bem simples nesses mesmos componentes com suporte nativo Drag & Drop.
As coisas podem ficar um bocado mais complicadas se formos trabalhar com outros componentes, mas este não vai ser o caso. O tutorial vai então passar a explicar como efectuar um Drag & Drop entre e componentes que já têm o suporte nativo drag & drop, podemos escolher um dos seguintes:
Datagrid
List
HorizontalList
PrintDatagGrid
TileList
Tree
Vamos então usar neste momento duas datagrid’s, e fazer um exemplo de um simples sistema de carrinho de compras, criando um novo projecto e colocando o código seguinte:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="510" height="349" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]">
<mx:DataGrid id="mercado" x="37" y="86" width="204" height="142" alternatingItemColors="[#F6F0F0, #FFFFFF]">
<mx:columns>
<mx:DataGridColumn headerText="Objeto" dataField="objeto"/>
<mx:DataGridColumn headerText="Preço" dataField="preco"/>
</mx:columns>
<mx:dataProvider>
<mx:Object objeto="Livro A" preco="25 €"/>
<mx:Object objeto="Livro B" preco="30 €"/>
<mx:Object objeto="Errata LA" preco="15 €"/>
</mx:dataProvider>
</mx:DataGrid>
<mx:DataGrid id="carrinho" x="276" y="86">
<mx:columns>
<mx:DataGridColumn headerText="Objeto" dataField="objeto"/>
<mx:DataGridColumn headerText="Preço" dataField="preco"/>
</mx:columns>
</mx:DataGrid>
<mx:Label x="37" y="60" text="Mercado" width="140"/>
<mx:Label x="276" y="60" text="Carrinho de compras" width="140"/>
</mx:Application>
Em que muito possivelmente ficarão com o design grafico como a imagem:
O nosso objectivo é passar elementos da datagrid “Mercado” para a datarid “Carrinho de compras”, para isso podemos usar os metodos drag & drop nativos destas mesmas datagrid’s, mas para isso temos que efectuar algumas alterações no código, indicando que eles vão suportar operações desse tipo. Vamos então alterar na datagrid da esquerda (mercado) para isso adicionando o parametro dragEnabled e defini-lo como true.:
e fazendo o mesmo na datagrid da direita, mas com o parametro dropEnabled:
e pronto, as nossas datagrids estão prontas a enviar e receber items, e podem salvar e correr a vossa aplicação que verão já o drag & drop em funcionamento.
O funcionamento do drag & drop em componentes que já têm o seu suporte nativo é tão simples como aqui foi explicado, mas vamos agora fazer algo mais elaborado, usando o mesmo código. Vamos colocar uma lixeira no nosso layout para poder-mos eliminar items do nosso carrinho de compras. Para isso a seguir à ultima colocamos o seguinte:
e ficamos com algo muito parecido ao seguinte:
Sendo que como uma imagem não têm nativamente suportado o drag & drop temos que arranjar maneira de o fazer. Primeiro temos que indicar à datagrid que também pode ser objecto de drag, e vamos também permitir selecionar varias linhas ao mesmo tempo, para isso acrescentamos na datagrid “carrinho” 3 parametros como o dragEnabled=”true” , o allowMultipleSelection=”true” e dragMoveEnabled=”true” ficando a nossa datagrid assim:
Com estes parametros estou a indicar que essa datagrid (alem de já aceitar drop) está a aceitar drag também, bem como muiltipla selecção de items e a quando do drag&drop dessa datagrid para outro alvo, ela vai permiter que o seu conteudo selecionado seja movido e não copiado como acontecia antes…
Se repararem nos parametros da tag mx:image existem alguns elementos Drag, que permitem que nós possamos fazer com que o objecto lide com darg & drop, e é precisamente uma dessas propriedades que vamos utilizar, escrevendo na tag da nossa imagem lixeira, o seguinte:
dragEnter=”lidaEnter(event)”
ficando a tag mx:image assim:
Estes dois parametros dragEnter e dragDrop são eventos que são disparados quando o objecto é alvo de operações drag&drop, neste caso a função lidaEnter() será chamada quando um objecto alvo de drag passar em cima da nossa imagem, aqui temos que indicar ao flex que ela se encontra apta para drag.
Falta apenas criar a funçao para lidar com este evento, mais precisamente a lidaEnter() para isso colocamos o seguinte código logo a seguir à 2 linha (a seguir à tag mx:application):
<![CDATA[
import mx.events.DragEvent;
import mx.managers.DragManager;
private function lidaEnter(event:DragEvent):void{
var dropTarget:Image = event.currentTarget as Image;
DragManager.acceptDragDrop(dropTarget);
DragManager.showFeedback(DragManager.MOVE);
}
]]>
</mx:Script>
E pronto, temos o nosso Mercado com carrinho de compras e lixeira para eleminar um ou mais items do carrinho de compras.
Como podem reparar não têm nenhuma dificuldade, Por isso, usem e abusem!
Código Final:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="510" height="349" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]">
<mx:Script>
<![CDATA[
import mx.events.DragEvent;
import mx.managers.DragManager;
private function lidaEnter(event:DragEvent):void{
var dropTarget:Image = event.currentTarget as Image;
DragManager.acceptDragDrop(dropTarget);
DragManager.showFeedback(DragManager.MOVE);
}
]]>
</mx:Script>
<mx:DataGrid id="mercado" x="37" y="86" width="204" height="142" alternatingItemColors="[#F6F0F0, #FFFFFF]" dragEnabled="true">
<mx:columns>
<mx:DataGridColumn headerText="Objeto" dataField="objeto"/>
<mx:DataGridColumn headerText="Preço" dataField="preco"/>
</mx:columns>
<mx:dataProvider>
<mx:Object objeto="Livro A" preco="25 €"/>
<mx:Object objeto="Livro B" preco="30 €"/>
<mx:Object objeto="Errata LA" preco="15 €"/>
</mx:dataProvider>
</mx:DataGrid>
<mx:DataGrid id="carrinho" x="276" y="86" dropEnabled="true" dragEnabled="true" allowMultipleSelection="true" dragMoveEnabled="true">
<mx:columns>
<mx:DataGridColumn headerText="Objeto" dataField="objeto"/>
<mx:DataGridColumn headerText="Preço" dataField="preco"/>
</mx:columns>
</mx:DataGrid>
<mx:Label x="37" y="60" text="Mercado" width="140"/>
<mx:Label x="276" y="60" text="Carrinho de compras" width="140"/>
<mx:Image x="219.5" y="256" source="http://www.msdevstudio.com/mywork/recicle.png" maintainAspectRatio="false" width="76" height="73" id="lixeira" dragEnter="lidaEnter(event)" />
</mx:Application>
Podem ver o resultado final online com o código fonte disponivel aqui
Abraço e espero que seja util e esclarecedor.











13 Comentários
Valeu Mario!!
Cara , eu tava procurando por isto faz tempo!! E nao tinha encontrado nada legal.
Parabens pelos seus tutoriais e pela iniciativa de contribuir , continue assim!!
Oupa George, ainda bem que ajudou…
Obrigado..
Abraço.
Muito bom, gostei do artigo, me deu ideia para uma tela que eu estava fazendo em flex, acabou que não consegui finalizar, no caso o meu problema e que as colunas do outro grid(drop) por necessidade são labelfunctin e não dataField, neste caso não funcionou, tem alguma dica?
Boas janderson, mas voce usa uma labelFunction para que? nunca testei assim (mas deverá funcionar), mas penso que em vez de label function pode usar um item renderer que assim deverá funcionar… mas explique melhor o que faz a sua label function, e se esta está apenas na datagrid ou também em cada coluna…
Para optimizar o conteudo da sua grid (drop) pode usar o dragDrop=”função(event)” para optimizar o seu conteudo…
veja:
http://blog.flexmonkeypatches.com/2008/03/24/nested-item-renderers-with-scrollbars-and-drag-and-drop-enabled-scroll-dont-drag-please/
e o melhor exemplo:
http://www.adobe.com/devnet/flex/quickstart/adding_drag_and_drop/
Tente explicar um pouco melhor…
Abraço.
Mário, vlw pela atenção, eu até abrir um tópico no forum do flexbrasil, acho que lá expliquei melhor o que eu preciso.
http://forum.flexbrasil.com.br/viewtopic.php?f=4&t=532
a tela é a seguinte, formação de preço, quando o cara arrastar uma tabela de preço para o grid onde tem o preco do produto, vou gravar no banco essa tabela de preco para esse produto, e logo em seguida listar essa tabela já com o valor sugerido de venda. mais para isso, tenho que verificar se a tabela já não foi cadastrada por exemplo, por isso preciso “interceptar” o evento, para fazer algumas verificações e calculos.
Vlw.
ah! e vlw pelo os links, vou estudar o item rederer e analisar melhor como funciona, obrigado
Muito obrigado por compartilhar seu conhecimento gratuitamente, foi de grande utilidade.
Só tenho uma dúvida, há algum maneira de fazer funcionar no Opera ?
Mais uma vez, muito obrigado.
Ola Brian, não funciona no Opera? isso é muito estranho… não tenho conhecimento de tal problema… mas dá problema apenas nesse exemplo ? ou já teve problemas no flex antes ?
Cumprimentos.
Olá, Mário. Ao fazer esse seu exemplo deu problema no Opera mas nos outros browsers funcionava normalmente. Então refiz ele (sem copiar o código, mas fazendo a mesma coisa) e funcionou perfeitamente em todos os browsers, com um pequeno detalhe: Se, por exemplo, eu copiar a pasta onde o arquivo está salvo e passar para outro computador, ou até mesmo colar em outro diretório do meu computador, começa a dar um problema. O drag and drop entre Mercado e Carrinho funciona mas ao tentar arrastar do carrinho para a lixeira, simplismente não vai. Isso acontece em todos os browsers, exeto no Internet explorer.
Outro problema, fora do contexto, com o Opera não estou conseguindo deixar comentários aqui.
Muito obrigado pela atenção, continue com o ótimo trabalho.
Bem Brian, me deixou de boca aberta, nunca tinha passado por tal coisa… mas dá algum erro ?
Quanto aos comentários, talvez não tenha o javascript activo no Opera, já que para deixar comentários necessita do javascript autorizado a correr…
Abraço.
Não, nenhum erro, mas ao arrastar do carrinho para a lixeira o item retorna ao carrinho, como se a lixeira não estivesse abilitada a recebê-lo.
Eu verifiquei e o javascript está abilitado no Opera, realmente muito estranho.
Mesmo assim, obrigado pela ajuda.
Abraço.
Consegui -com ajuda- descobrir o que estava acontecendo. Eu havia deixado a lixeira estática, adicionei-a com Embed e funcionou. Erros de principiante…
Obrigado pela atenção.
Humm… o meu exemplo usa a lixeira sem ser embed… estranho, mas ainda bem que funcionou..
Abraço.