// 
//     Licensed to the Apache Software Foundation (ASF) under one
//     or more contributor license agreements.  See the NOTICE file
//     distributed with this work for additional information
//     regarding copyright ownership.  The ASF licenses this file
//     to you under the Apache License, Version 2.0 (the
//     "License"); you may not use this file except in compliance
//     with the License.  You may obtain a copy of the License at
// 
//       http://www.apache.org/licenses/LICENSE-2.0
// 
//     Unless required by applicable law or agreed to in writing,
//     software distributed under the License is distributed on an
//     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//     KIND, either express or implied.  See the License for the
//     specific language governing permissions and limitations
//     under the License.
//

= Web Service Passando Dados Binários, parte 5: Criando o Cliente Swing
:jbake-type: tutorial
:jbake-tags: tutorials 
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Web Service Passando Dados Binários, parte 5: Criando o Cliente Swing - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Web Service Passando Dados Binários, parte 5: Criando o Cliente Swing

O objetivo deste exercício é criar um cliente para o Web service criado e implantado anteriormente e, em seguida, adicionar uma interface de GUI a esse cliente. A interface exibe as imagens que o Web service passa como dados binários.

É possível fazer download de uma versão completa do cliente a partir do link:https://netbeans.org/projects/samples/downloads/download/Samples%252FWeb%2520Services%252FWeb%2520Service%2520Passing%2520Binary%2520Data%2520--%2520EE6%252FFlowerClient.zip[+Catálogo de Amostras do NetBeans+].

*Lições Deste Tutorial*

image::images/netbeans-stamp-74-73-72.png[title="O conteúdo desta página se aplica ao NetBeans IDE 7.2, 7.3 e 7.4"]

1. link:./flower_overview.html[+Visão Geral+]
2. link:./flower_ws.html[+Criando o Web Service+]
3. link:./flower-code-ws.html[+Codificando e Testando o Web Service+]
4. link:./flower_wsdl_schema.html[+ Modificando o Esquema e os Arquivos WSDL para Passar Dados Binários+]
5. => Criando o Cliente Swing


[start=1]
1. <<create-client-app,Criando a Aplicação Cliente>>


[start=2]
. <<design-jframe,Projetando o JFrame>>

[start=3]
. 
<<bind-jframe,Vinculando os Componentes do JFrame>>


[start=4]
. <<code-main-class,Codificando a Classe Principal>>


== Criando a Aplicação Cliente

Nesta seção, você criará uma aplicação Web. Nessa aplicação, você criará um cliente que consumirá o Web service criado e modificado em tutoriais anteriores.

*Para criar a aplicação cliente:*

1. Selecione Arquivo > Novo Projeto (Ctrl-Shift-N no Linux/Windows, ⌘-Shift-N no MacOS). O Assistente de Novo Projeto será exibido.
2. Selecione Aplicação Java na categoria Java. Clique em Próximo. O assistente de Nova Aplicação Java será exibido. Digite  ``FlowerClient``  em Nome do Projeto. Selecione uma localização para o projeto e clique em Finalizar. O IDE criará um novo projeto de aplicação Java.
3. Clique com o botão direito do mouse no nó do projeto  ``FlowerClient``  e selecione Novo > Cliente de Web Service no menu de contexto. O assistente de Novo Cliente de Web Service será aberto.
4. Selecione o botão de opção URL WSDL e cole o URL do arquivo WSDL nesse campo. (Por default, o URL é  ``http://localhost:8080/FlowerAlbumService/FlowerServiceService?wsdl`` . Localize o URL no browser testando o Web service e substituindo  ``?Tester``  por  ``?wsdl``  no final do URL.) Aceite todos os outros valores default, incluindo um nome de pacote em branco.
image::images/ws-client-wiz.png[]

[start=5]
. Clique em Finalizar. O IDE faz download do arquivo WSDL, adiciona stubs de cliente para interagir com o Web service e adiciona nós à janela Projetos no projeto de aplicação Java.
image::images/client-generated-sources.png[title="Visualização Projetos mostrando o novo cliente do Web Service"]


[[design-jframe]]
== Projetando o Form JFrame

Nesta seção, você adicionará um  ``JFrame``  à aplicação Web e projetará uma interface de GUI dentro dele utilizando componentes Swing. Finalmente, você vinculará os componentes Swing ao código do cliente de Web service.

Se não desejar projetar o form JFrame você mesmo, você poderá fazer download de um arquivo Java do JFrame pré-projetado link:https://netbeans.org/projects/www/downloads/download/webservices%252FFlowerFrame.java[+aqui+].

1. Clique com o botão direito do mouse no nó  ``FlowerClient``  e selecione Novo > Form JFrame. Chame o quadro de  ``FlowerFrame`` . Coloque-o no pacote  ``flowerclient`` .
2.  ``FlowerFrame``  será aberto no editor. Abra a Paleta, se ainda não estiver aberta. Estenda o limite inferior do quadro em aproximadamente um terço.
image::images/opened-flowerform.png[]

[start=3]
. Arraste um JPanel da seção Contêineres Swing da Paleta para o  ``FlowerFrame`` . Expanda-o para preencher o  ``FlowerFrame``  inteiro.
image::images/add-panel.png[]

[start=4]
. Clique com o botão direito do mouse no Painel na View do Design. Selecione Alterar Nome da Variável... no menu de contexto. Defina o nome do painel como  ``gardenFlowersPanel`` .

[start=5]
. Arraste um JLabel da Paleta para o início do  `` gardenFlowersPanel`` . Clique com o botão direito do mouse no label e altere seu nome de variável para  ``titleLabel`` . Clique com o botão direito do mouse novamente em  ``titleLabel``  e selecione Editar Texto. Altere o texto para Flores do Jardim. Talvez você queira explorar as propriedades do  ``titleLabel`` e dar a ele uma fonte de maior expressão.

[start=6]
. Arraste um Grupo de Botões para a view de design. Aceite o nome da variável default do grupo de botões,  ``buttonGroup1`` .

[start=7]
. Arraste quatro Botões de Opções para uma linha horizontal abaixo do  ``titleLabel`` . Nas propriedades de cada botão, defina-o como um membro de  ``buttonGroup1`` . As outras propriedades dos botões são:
|===
|Botões de Opção em ButtonGroup1

|Nome da Variável |Selecionado |Texto 

|asterRadioButton |verdadeiro |Áster 

|honeysuckleRadioButton |falso |Madressilva 

|roseRadioButton |falso |Rosa 

|sunflowerRadioButton |falso |Girassol 
|===

[start=8]
. Arraste um Painel de Rolagem para baixo dos botões de opções. Expanda-o para preencher todo o espaço horizontal e cerca de dois terços do espaço vertical livre. Altere o nome da variável do painel de rolagem para  ``mainScrollPane`` .

[start=9]
. Arraste um Painel para o  ``mainScrollPane`` . Altere o nome da variável do Painel para  ``mainPanel`` .

[start=10]
. Na view Design, clique com o botão direito do mouse no  ``mainPanel``  e selecione Definir layout > Layout da Borda.

[start=11]
. Arraste um Botão para o  ``mainPanel`` . Como o  ``mainPanel``  tem layout de borda, o botão automaticamente preenche todo o painel. Altere o nome da variável do botão para  ``mainPictureButton``  e mude o texto do botão para "Aguardando imagem..."

[start=12]
. Arraste outro Painel de Rolagem para o espaço abaixo do  ``mainScrollPane`` . Expanda o novo painel de rolagem para preencher todo o espaço livre remanescente. Altere o nome da variável do novo painel de rolagem para  ``thumbnailScrollPane`` .

[start=13]
. Arraste um Painel para o  ``thumbnailScrollPane`` . Altere o nome da variável do Painel para  ``thumbnailPanel`` . Defina o layout do  ``thumbnailPanel``  para Layout de Grade.

[start=14]
. Arraste quatro Botões para o  ``thumbnailPanel``  Como o  ``thumbnailPanel``  tem Layout de Grade, os botões são automaticamente de mesmo tamanho e preenchem o painel completamente. As propriedades dos botões são: Botões no thumbnailPanel
|===

|Nome da Variável |Texto 

|asterButton |Aguardando... 

|honeysuckleButton |Aguardando... 

|roseButton |Aguardando 

|sunflowerButton |Aguardando... 
|===

O Form JFrame agora está totalmente projetado. Nesse ponto, o  ``FlowerFrame``  deverá ter a seguinte aparência.
image::images/designed-form.png[title="Quadro de Flores Concluído mostrando os textos do botão em vez de imagens"]


== Vinculando os Componentes do JFrame

Nesta seção, você inicializará os componentes no construtor e vinculará os componentes aos listeners. Os listeners chamam o código que mostra as imagens das flores.


=== [[Inicializando os Componentes]] 

[[Nesta seção, você preencherá o construtor  ``FlowerFrame`` 

]]

1. Alterne para a view de Código-fonte do editor. Localize o início do corpo da classe  ``FlowerFrame``  e o construtor  ``FlowerFrame`` .
image::images/ff-empty-constructor.png[]
. Na parte superior do corpo da classe do  ``FlowerFrame`` , antes do construtor, crie um array de strings dos nomes de cada flor.

[source,java]
----

protected static final String[] FLOWERS = {"aster", "honeysuckle", "rose", "sunflower"};
----
. Entre o array da string FLOWERS e o construtor, adicione uma linha que inicialize um  ``link:http://download.oracle.com/javase/6/docs/api/java/util/Map.html[+java.util.Map+]``  denominado  ``flores`` . O mapa utiliza uma  ``String``  e a mapeia para uma  ``Image`` .

[source,java]
----

private Map<String, Image> flowers;
----
. Adicione instruções de importação para  ``java.util.Map``  e  ``java.awt.Image`` .
. Adicione código ao construtor  ``FlowerFrame``  para associar uma  ``Image``  específica a uma  ``String``  específica de uma instância específica do mapa  ``flowers`` 

[source,java]
----

public FlowerFrame(Map<String, Image> flowers) {

    this.flowers = flowers;
    for (String flower:FLOWERS) {
        flowers.put(flower,null);
    }

    initComponents();    
} 
----

[start=3]
. Inicialize  ``ItemListener`` s para os botões de opções e  ``ActionListener`` s para os quatro botões de flores e defina o título default.

[source,java]
----

public FlowerFrame(Map<String, Image> flowers) {

    this.flowers = flowers;
    for (String flower:FLOWERS) {
        flowers.put(flower,null);
    }

    initComponents(); 
    
    setTitle("Garden Flowers [waiting for picture]");
    
    ItemListener rbListener = new RBListener();
    asterRadioButton.addItemListener(rbListener);
    honeysuckleRadioButton.addItemListener(rbListener);
    roseRadioButton.addItemListener(rbListener);
    sunflowerRadioButton.addItemListener(rbListener);
    
    ActionListener bListener = new ButtonListener();
    asterButton.addActionListener(bListener);
    honeysuckleButton.addActionListener(bListener);
    roseButton.addActionListener(bListener);
    sunflowerButton.addActionListener(bListener);
}
----

[start=4]
. Adicione instruções de importação para  ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ItemListener.html[+java.awt.event.ItemListener+]``  e  ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionListener.html[+java.awt.event.ActionListener+]`` .

Agora, o construtor está completo. Você receberá advertências de erros de compilação no código porque ele não contém as classes  ``RBListener``  e  ``ButtonListener`` . Essas duas classes são implementações personalizadas do  ``ItemListener``  e  ``ActionListener`` , respectivamente. Você escreverá essas duas classes na próxima seção.


=== [[Mostrando as Flores]] 

[[Nesta seção, você escreverá listeners personalizados para os botões de opções e os botões de flores. Você também escreverá um método que determinará qual flor será selecionada pelos botões e obterá uma  ``Image``  daquela flor a partir do mapa  ``flowers`` . Finalmente, você escreverá um método que é chamado pela classe  ``Main``  e que obterá uma  ``Image``  para cada miniatura.

]]

1. Encontre o método  ``public static void main(String args[])``  no corpo da classe  ``FlowerFrame`` . Delete esse método e sua documentação. (A aplicação utilizará a classe  ``Main`` .)
. No lugar do método  ``main`` , escreva um  ``ItemListener``  personalizado para os botões de opções. Esse listener mostrará uma nova imagem de flor quando um botão de opção for selecionado.

[source,java]
----

private class RBListener implements ItemListener {
    public void itemStateChanged(ItemEvent e) {
        showFlower();
    }
}
----
. Adicione uma instrução de importação para  ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ItemEvent.html[+java.awt.event.ItemEvent+]`` .
. Abaixo do  ``ItemListener``  personalizado, escreva um  ``ActionListener``  personalizado para os quatro botões de flores. Quando um botão for clicado, o listener selecionará o botão de opção relacionado:

[source,java]
----

private class ButtonListener implements ActionListener {

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == asterButton) asterRadioButton.setSelected(true);
        else if (e.getSource() == honeysuckleButton) honeysuckleRadioButton.setSelected(true);
        else if (e.getSource() == roseButton) roseRadioButton.setSelected(true);
        else if (e.getSource() == sunflowerButton) sunflowerRadioButton.setSelected(true);
    }
}
----

[start=2]
. Adicione uma instrução de importação para  ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionEvent.html[+java.awt.event.ActionEvent+]`` .

[start=3]
. Abaixo do  ``ActionListener``  personalizado, escreva o método  ``showFlower`` . Esse método determina o botão de opção selecionado e obtém uma  ``Image``  da flor correspondente a partir do mapa  ``flowers`` .

[source,java]
----

void showFlower() {
    Image img = null;
    if (asterRadioButton.isSelected()) {
        img = flowers.get("aster");
        if (img != null) {
            mainPictureButton.setIcon(new ImageIcon(img));
            setTitle("Garden Flowers [Aster]");
        }
    } else if (honeysuckleRadioButton.isSelected()) {
        img = flowers.get("honeysuckle");
        if (img != null) {
            mainPictureButton.setIcon(new ImageIcon(img));
            setTitle("Garden Flowers [Honeysuckle]");
        }

    } else if (roseRadioButton.isSelected()) {
        img = flowers.get("rose");
        if (img != null) {
            mainPictureButton.setIcon(new ImageIcon(img));
            setTitle("Garden Flowers [Rose]");
        }
    } else if (sunflowerRadioButton.isSelected()) {
        img = flowers.get("sunflower");
        if (img != null) {
            mainPictureButton.setIcon(new ImageIcon(img));
            setTitle("Garden Flowers [Sunflower]");
        }
    }
    if (img == null) {
        mainPictureButton.setIcon(null);
        setTitle("Garden Flowers [waiting for picture]");            
    } else mainPictureButton.setText("");
}
----

[start=4]
. Adicione uma instrução de importação para  ``link:http://download.oracle.com/javase/6/docs/api/javax/swing/ImageIcon.html[+javax.swing.ImageIcon+]`` .

[start=5]
. Escreva o método  ``setThumbnails`` . Esse método obtém uma imagem para cada miniatura do mapa  ``flowers`` . A classe  ``Main``  chama esse método.

[source,java]
----

void setThumbnails(Map<String, Image> thumbs) {
    Image img = thumbs.get("aster");
    if (img != null) {
        asterButton.setIcon(new ImageIcon(img));
        asterButton.setText("");
    }
    img = thumbs.get("honeysuckle");
    if (img != null) {
        honeysuckleButton.setIcon(new ImageIcon(img));
        honeysuckleButton.setText("");
    }
    img = thumbs.get("rose");
    if (img != null) {
        roseButton.setIcon(new ImageIcon(img));
        roseButton.setText("");
    }
    img = thumbs.get("sunflower");
    if (img != null) {
        sunflowerButton.setIcon(new ImageIcon(img));
        sunflowerButton.setText("");
    }
}
----

[start=6]
. Corrija as importações em  ``FlowerFrame`` , caso elas não tenham sido corrigidas quando foram coladas no código. É possível corrigir todas de uma vez clicando com o botão direito do mouse no editor e selecionando Corrigir Importações, no menu de contexto. O conjunto completo de instruções de importação é:

[source,java]
----

import java.awt.Image;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.ItemEvent;import java.awt.event.ItemListener;import java.util.Map;import javax.swing.ImageIcon;
----

O  ``FlowerFrame``  agora está completo.


== [[Codificando a Classe Principal]] 

[[Nesta seção, você completará a classe  ``Main``  para que mostre o  ``FlowerFrame`` , estabelecerá uma conexão com o Web service e chamará as operações do Web service.

1. Abra a classe  ``Main.java``  no editor.
image::images/main-empty.png[]

[start=2]
. No corpo da classe, antes do método  ``principal`` , inicialize uma variável  ``int``  para a quantidade de imagens obtidas por download.

[source,java]
----

 private static int downloadedPictures;
----

[start=3]
. No corpo do método  ``main`` , crie um  ``HashMap``  de quatro flores e outro  ``HashMap``  de quatro miniaturas.

[source,java]
----

final Map<String,Image> flowers = new HashMap<String,Image>(4);
final Map<String,Image> thumbs = new HashMap<String,Image>(4);
----

[start=4]
. Adicione instruções de importação para  ``java.awt.Image`` ,  ``java.util.Map``  e  ``java.util.HashMap`` .

[start=5]
. No corpo do método  ``main`` , adicione código para mostrar o  ``FlowerFrame`` .*// Show the FlowerFrame.*

[source,java]
----

final FlowerFrame frame = new FlowerFrame(flowers);
frame.setVisible(true);  
----

[start=6]
. No corpo do método  ``main`` , adicione o código para conectar o cliente ao serviço.*// The client connects to the service with this code.*

[source,java]
----

FlowerServiceService service = new FlowerServiceService();
final FlowerService port = service.getFlowerServicePort();
----

[start=7]
. Adicione instruções de importação para  ``org.flower.service.FlowerService``  e  ``org.flower.service.FlowerServiceService`` .

[start=8]
. No corpo do método  ``main`` , adicione o código que cria um array de quatro threads  ``Runnable``  e chama a operação  ``getFlower``  do Web service uma vez em cada thread.*// The web service getFlower operation
// is called 4 times, each in a separate thread.
// When the operation finishes the picture is shown in
// a specific button.*

[source,java]
----

Runnable[] tasks = new Runnable[4];

for (int i=0; i<4;i++) {
    final int index = i;
    tasks[i] = new Runnable() {
        public void run() {
            try {
            
                *// Call the getFlower operation
                // on the web service:*
                Image img = port.getFlower(FlowerFrame.FLOWERS[index]);
                System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]);
                     
                *// Add strings to the hashmap:*
                flowers.put(FlowerFrame.FLOWERS[index],img);
                        
                *// Call the showFlower operation
                // on the FlowerFrame:*
                frame.showFlower();
                        
            } catch (IOException_Exception ex) {
                ex.printStackTrace();
            }
            downloadedPictures++;
        }
    };
    new Thread(tasks[i]).start();
}
----

[start=9]
. Adicione uma instrução de importação para  ``org.flower.service.IOException_Exception`` .

[start=10]
. No corpo do método  ``principal`` , adicione o código que chama a operação  ``getThumbnails``  do Web service em um thread separado.*// The web service getThumbnails operation is called
// in a separate thread, just after the previous four threads finish.
// When the images are downloaded, the thumbnails are shown at 
// the bottom of the frame.*

[source,java]
----

Runnable thumbsTask = new Runnable() {
    public void run() {
        try {
            while (downloadedPictures < 4) {                        
                try {Thread.sleep(100);} catch (InterruptedException ex) {}
            }
                 
            *// Call the getThumbnails operation
            // on the web service:*
            List<Image> images = port.getThumbnails();
            System.out.println("thumbs downloaded");
                    
            if (images != null &amp;&amp; images.size() == 4) {
                for (int i=0;i<4;i++) {
                    thumbs.put(FlowerFrame.FLOWERS[i],images.get(i));
                }
                frame.setThumbnails(thumbs);
            }
        } catch (IOException_Exception ex) {
            ex.printStackTrace();
        }
    }            
};
new Thread(thumbsTask).start();

----

[start=11]
. Corrija as importações em  ``Main.java`` , caso elas não tenham sido corrigidas quando foram coladas no código. É possível corrigir todas de uma vez clicando com o botão direito do mouse no editor e selecionando Corrigir Importações, no menu de contexto. Você verá uma Lista de classes para importação; selecione  ``java.util.List`` . O conjunto completo de instruções de importação é:

[source,java]
----

import flower.album.FlowerService;import flower.album.FlowerService_Service;import flower.album.IOException_Exception;import java.awt.Image;import java.util.HashMap;import java.util.List;import java.util.Map;
----

A classe  ``Main``  agora está completa.


[source,java]
----

public class Main {

     private static int downloadedPictures;
    
     public static void main(String[] args) {
    
        final Map<String,Image> flowers = new HashMap<String,Image>(4);
        final Map<String,Image> thumbs = new HashMap<String,Image>(4);
        
        *// Show the FlowerFrame.*
        final FlowerFrame frame = new FlowerFrame(flowers);
        frame.setVisible(true);
        *        // The client connects to the service with this code.*
        FlowerService_Service service = new FlowerService_Service();
        final FlowerService port = service.getFlowerServicePort();
        
        Runnable[] tasks = new Runnable[4];
        
        *// The web service getFlower operation
        // is called 4 times, each in a separate thread.
        // When the operation finishes the picture is shown in
        // a specific button.*
        for (int i=0; i<4;i++) {
            final int index = i;
            tasks[i] = new Runnable() {
                public void run() {
                    try {
                    
                        *// Call the getFlower operation
                        // on the web service:*
                        Image img = port.getFlower(FlowerFrame.FLOWERS[index]);
                        System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]);
                        
                        *// Add strings to the hashmap:*
                        flowers.put(FlowerFrame.FLOWERS[index],img);
                        
                        *// Call the showFlower operation
                        // on the FlowerFrame:*
                        frame.showFlower();
                        
                    } catch (IOException_Exception ex) {
                        ex.printStackTrace();
                    }
                    downloadedPictures++;
                }
            };
            new Thread(tasks[i]).start();
        }
        *// The web service getThumbnails operation is called
        // in a separate thread, just after the previous four threads finish.
        // When the images are downloaded, the thumbnails are shown at 
        // the bottom of the frame.*
        Runnable thumbsTask = new Runnable() {
            public void run() {
                try {
                    while (downloadedPictures < 4) {                        
                        try {Thread.sleep(100);} catch (InterruptedException ex) {}
                    }
                    
                    *// Call the getThumbnails operation
                    // on the web service:*
                    List<Image> images = port.getThumbnails();
                    System.out.println("thumbs downloaded");
                    
                    if (images != null &amp;&amp; images.size() == 4) {
                        for (int i=0;i<4;i++) {
                            thumbs.put(FlowerFrame.FLOWERS[i],images.get(i));
                        }
                        frame.setThumbnails(thumbs);
                    }
                } catch (IOException_Exception ex) {
                    ex.printStackTrace();
                }
            }            
        };
        new Thread(thumbsTask).start();
    }

}
----

A aplicação cliente agora está completa, com o código que interage com o Web service que é delegado ao módulo EJB para a exposição de suas imagens. Clique com o botão direito do mouse no cliente e selecione Executar. A aplicação Swing é iniciada e, depois de um tempo, é preenchida com as imagens recebidas do Web service. Se as imagens não aparecerem, limpe e construa o projeto FlowerService e execute-o novamente. Observe que é possível alterar a imagem exibida no quadro principal selecionando um botão de opção ou clicando em uma miniatura.

]]

link:/about/contact_form.html?to=3&subject=Feedback:%20Flower%20Swing%20Client%20EE6[+Enviar Feedback neste Tutorial+]

Para enviar comentários e sugestões, obter suporte e se manter informado sobre os mais recentes desenvolvimentos das funcionalidades de desenvolvimento Java EE do NetBeans IDE, link:../../../community/lists/top.html[+inscreva-se na lista de notícias nbj2ee@netbeans.org+].

