Skip to content

5. Interfaces gráficas de utilizador

O objetivo aqui é mostrar como construir interfaces gráficas de utilizador com Java. Primeiro, analisaremos as classes básicas que nos permitem construir uma interface gráfica de utilizador. Inicialmente, não utilizaremos quaisquer ferramentas de geração automática. Posteriormente, utilizaremos o JBuilder, uma ferramenta de desenvolvimento da Borland/Inprise que facilita o desenvolvimento de aplicações Java e, em particular, a construção de interfaces gráficas de utilizador.

5.1. Noções básicas sobre interfaces gráficas de utilizador

5.1.1. Uma janela simples

Considere o seguinte código:


// imported classes
import javax.swing.*;
import java.awt.*;
    
    // the form class
  public class form1 extends JFrame {
    
      // the manufacturer
      public form1() {
            // window title
            this.setTitle("Mon premier formulaire");
            // window dimensions
            this.setSize(new Dimension(300,100));
      }//manufacturer
  
      // test function
      public static void main(String[] args) {
            // the form is displayed
            new form1().setVisible(true);
      }
  }//class

A execução do código acima exibe a seguinte janela:

Image

Uma interface gráfica de utilizador geralmente estende a classe base JFrame:


  public class form1 extends JFrame {

A classe base JFrame define uma janela básica com botões para fechar, maximizar/minimizar, tamanho ajustável, etc., e lida com eventos nestes objetos gráficos. Aqui, especializamos a classe base definindo o seu título, a sua largura (300 píxeis) e a sua altura (100 píxeis). Isto é feito no seu construtor:


      // le constructeur
      public form1() {
            // titre de la fenêtre
            this.setTitle("Mon premier formulaire");
            // dimensions de la fenêtre
            this.setSize(new Dimension(300,100));
      }//constructeur

O título da janela é definido pelo método setTitle e as suas dimensões pelo método setSize. Este método recebe como parâmetro um objeto Dimension (width, height), em que width e height são a largura e a altura da janela expressas em pixels.

O método main inicia a aplicação gráfica da seguinte forma:


            new form1().setVisible(true);

É então criado um formulário do tipo form1 (new form1()) e exibido (setVisible(true)), após o que a aplicação fica à espera de eventos que ocorram no formulário (cliques, movimentos do rato, etc.) e executa aqueles que o formulário processa. Aqui, o nosso formulário não lida com quaisquer eventos além daqueles tratados pela classe base JFrame (cliques nos botões de fechar, maximizar/minimizar, redimensionamento da janela, movimentação da janela, etc.).

Ao testar este programa, executando-o a partir de uma janela do DOS utilizando:

java form1

para executar o ficheiro form1.class, reparamos que, ao fechar a janela que foi exibida, não «recuperamos o controlo» da janela do DOS, como se o programa não tivesse terminado. É efetivamente esse o caso. O programa executa-se da seguinte forma:

  • Inicialmente, é lançada uma primeira thread de execução para executar o método main
  • quando este método cria o formulário e o exibe, é criada uma segunda thread para tratar especificamente dos eventos relacionados com o formulário
  • após essa criação, e no nosso exemplo, a thread do método main termina, deixando apenas a thread de execução da GUI.
  • Quando a janela é fechada, ela desaparece, mas não interrompe a thread na qual estava a ser executada
  • Por enquanto, somos obrigados a parar esta thread premindo Ctrl-C na janela do DOS a partir da qual o programa foi iniciado.

Vamos verificar a existência de dois threads distintos: um no qual o método main é executado e outro no qual a janela da GUI é executada:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
 
// the form class
 public class form1 extends JFrame {
    
// the manufacturer
 public form1() {
   // window title
   this.setTitle("Mon premier formulaire");
   // window dimensions
   this.setSize(new Dimension(300,100));
}//manufacturer
  
// test function
 public static void main(String[] args) {
   // follow-up
   System.out.println("Début du thread main");
   // the form is displayed
   new form1().setVisible(true);
   // follow-up
   System.out.println("Fin du thread main");  
}//hand
}//class

A execução produz os seguintes resultados:

Image

Podemos ver que o segmento principal terminou enquanto a janela ainda está a ser apresentada. Fechar a janela não encerra o segmento no qual estava a ser executado. Para parar este segmento, prima Ctrl-C novamente na janela do DOS.

Para concluir este exemplo, repare nos pacotes importados:

  • javax.swing para a classe JFrame
  • java.awt para a classe Dimension

5.1.2. Tratamento de um evento

No exemplo anterior, teríamos de tratar nós próprios do fecho da janela para que, quando isso ocorresse, a aplicação parasse — o que não é o caso atualmente. Para tal, precisamos de criar um objeto que «escute» os eventos que ocorrem na janela e detete o evento «fecho da janela». Este objeto é chamado de «ouvinte» ou manipulador de eventos. Existem diferentes tipos de ouvintes para os vários eventos que podem ocorrer nos componentes de uma interface gráfica de utilizador. Para o componente JFrame, o ouvinte chama-se WindowListener e é uma interface que define os seguintes métodos (ver documentação Java)

Resumo dos métodos
 
void
windowActivated(WindowEvent e)
          A janela torna-se a janela ativa
 
void
windowClosed(WindowEvent e)
          A janela foi fechada
 
void
windowClosing(WindowEvent e)
          O utilizador ou o programa solicitou que a janela fosse fechada
 
void
windowDeactivated(WindowEvent e)
          A janela já não é a janela ativa
 
void
windowDeiconified(WindowEvent e)
          A janela muda do estado minimizado para o estado normal
 
void
windowIconified(WindowEvent e)
          A janela muda do estado normal para o estado minimizado
 
void
windowOpened(WindowEvent e)
          A janela torna-se visível pela primeira vez
 

Existem, portanto, sete eventos que podem ser tratados. Todos os manipuladores recebem um objeto WindowEvent como parâmetro, que iremos ignorar por enquanto. O evento de interesse aqui é o fecho da janela, que deve ser tratado pelo método windowClosing. Para tratar este evento, podemos criar um objeto WindowListener utilizando uma classe anónima da seguinte forma:


   // création d'un gestionnaire d'événements
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//définition win

O nosso manipulador de eventos que implementa a interface WindowListener deve definir todos os sete métodos desta interface. Como queremos apenas lidar com o fecho da janela, definimos apenas o código para o método windowClosing. Quando os outros eventos ocorrerem, seremos notificados, mas não tomaremos nenhuma ação. O que faremos quando formos notificados de que a janela está a fechar (windowClosing)? Encerraremos a aplicação:


     public void windowClosing(WindowEvent e){System.exit(0);}

Aqui temos um objeto capaz de lidar com eventos de janela em geral. Como o associamos a uma janela específica? A classe JFrame possui um método addWindowListener(WindowListener win) que nos permite associar um manipulador de eventos de "janela" a uma determinada janela. Portanto, aqui, no construtor da janela, escreveremos:


   // création d'un gestionnaire d'événements
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//définition win
   // ce gestionnaire d'événements va gérer les évts de la fenêtre courante
   this.addWindowListener(win);

O programa completo é o seguinte:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
 
// the form class
 public class form2 extends JFrame {
    
// the manufacturer
 public form2() {
   // window title
   this.setTitle("Mon premier formulaire");
   // window dimensions
   this.setSize(new Dimension(300,100));
   // creation of an event manager
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//definition win
   // this event handler will manage the events of the current window
   this.addWindowListener(win);
}//manufacturer
  
// test function
 public static void main(String[] args) {
   // the form is displayed
   new form2().setVisible(true);
}//hand
}//class

O pacote java.awt.event contém a interface WindowListener. Quando executamos este programa e fechamos a janela que apareceu, verificamos na janela do DOS onde o programa foi iniciado que o programa terminou a sua execução, o que não acontecia anteriormente.

No nosso programa, criar o objeto responsável por lidar com eventos de janela é um pouco complicado, pois somos obrigados a definir métodos mesmo para eventos que não queremos tratar. Neste caso, em vez de utilizar a interface WindowListener, podemos utilizar a classe WindowAdapter. Esta classe implementa a interface WindowListener com sete métodos vazios. Ao derivar da classe WindowAdapter e redefinir apenas os métodos que nos interessam, obtemos o mesmo resultado que com a interface WindowListener, mas sem necessidade de definir os métodos que não nos interessam. A sequência

  • que define o manipulador de eventos
  • associar o manipulador à janela

pode ser realizada da seguinte forma no nosso exemplo:


   // création d'un gestionnaire d'événements
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//définition win
   // ce gestionnaire d'événements va gérer les évts de la fenêtre courante
   this.addWindowListener(win);

Aqui utilizamos uma classe anónima que estende a classe WindowAdapter e sobrescreve o seu método windowClosing. O programa passa então a ser:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
 
// the form class
 public class form2 extends JFrame {
    
// the manufacturer
 public form2() {
   // window title
   this.setTitle("Mon premier formulaire");
   // window dimensions
   this.setSize(new Dimension(300,100));
   // creation of an event manager
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//definition win
   // this event handler will manage the events of the current window
   this.addWindowListener(win); }//manufacturer
  
// test function
 public static void main(String[] args) {
   // the form is displayed
   new form2().setVisible(true);
}//hand
}//class

Produz os mesmos resultados que o programa anterior, mas é mais simples de escrever.

5.1.3. Um formulário com um botão

Agora vamos adicionar um botão à nossa janela:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
 
// the form class
 public class form3 extends JFrame {
 
     // a button
  JButton btnTest=null;
  Container conteneur=null;
 
  // the manufacturer
  public form3() {
     // window title
    this.setTitle("Formulaire avec bouton");
     // window dimensions
    this.setSize(new Dimension(300,100));
    // creation of an event manager
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//definition win
     // this event handler will manage the events of the current window
    this.addWindowListener(win);
     // retrieve the window container
    conteneur=this.getContentPane();
     // select a layout manager for components in this container
    conteneur.setLayout(new FlowLayout());
    // create a button
    btnTest=new JButton();
    // we set the wording
    btnTest.setText("Test");
    // add the button to the container
    conteneur.add(btnTest);
  }//manufacturer
 
  // test function
 public static void main(String[] args) {
    // the form is displayed
   new form3().setVisible(true);
}//hand
}//class

Uma janela JFrame possui um contentor no qual podem ser colocados componentes gráficos (botões, caixas de seleção, listas suspensas, etc.). Este contentor é acessível através do método getContentPane da classe JFrame:


  Container conteneur=null;
..........
    // on récupère le conteneur de la fenêtre
    conteneur=this.getContentPane();

Qualquer componente é colocado no contentor utilizando o método add da classe Container. Assim, para colocar o componente C no objeto contentor acima, escrevemos:

conteneur.add(C)

Onde é que este componente é colocado no contentor? Existem vários gestores de layout de componentes denominados XXXLayout, em que XXX pode ser Border, Flow, etc. Cada gestor de layout tem as suas próprias características. Por exemplo, o gestor FlowLayout organiza os componentes numa linha a partir do topo do formulário. Quando uma linha fica cheia, os componentes são colocados na linha seguinte. Para associar um gestor de layout a uma janela JFrame, utilize o método setLayout da classe JFrame da seguinte forma:

    setLayout(objet XXXLayout);

Assim, no nosso exemplo, para associar um gestor FlowLayout à janela, escrevemos:


    // on choisit un gestionnaire de mise en forme des composants dans ce conteneur
    conteneur.setLayout(new FlowLayout());

Pode optar por não utilizar um gestor de layout e escrever:

    setLayout(null);

Neste caso, temos de especificar as coordenadas exatas do componente dentro do contentor na forma (x,y,width,height), em que (x,y) são as coordenadas do canto superior esquerdo do componente dentro do contentor. Este é o método que iremos utilizar com mais frequência daqui em diante.

Agora sabemos como os componentes são adicionados ao contentor (add) e onde são colocados (setLayout). Resta apenas identificar os

componentes que podem ser colocados num contentor. Aqui, colocamos um botão modelado pela classe javax.swing.JButton:


 
  JButton btnTest=null;
..........
    // on crée un bouton
    btnTest=new JButton();
    // on fixe son libellé
    btnTest.setText("Test");
    // on ajoute le bouton au conteneur
    conteneur.add(btnTest);

Ao executar este programa, obtém-se a seguinte janela:

Image

Se redimensionar o formulário acima, o gestor de layout do contentor é automaticamente chamado para reposicionar os componentes:

Image

Esta é a principal vantagem dos gestores de layout: manter um layout consistente dos componentes à medida que o tamanho do contentor muda. Vamos utilizar o gestor de layout nulo para ver a diferença. O botão é agora colocado no contentor utilizando as seguintes instruções:


// on choisit un gestionnaire de mise en forme des composants dans ce conteneur
conteneur.setLayout(null);
    // on crée un bouton
btnTest=new JButton();
    // on fixe son libellé
btnTest.setText("Test");
    // on fixe son emplacement et ses dimensions
btnTest.setBounds(10,20,100,20);
    // on ajoute le bouton au conteneur
conteneur.add(btnTest);

Aqui, colocamos explicitamente o botão no ponto (10,20) do formulário e definimos as suas dimensões para 100 píxeis de largura e 20 píxeis de altura. A nova janela fica assim:

Image

Se redimensionarmos a janela, o botão permanece no mesmo lugar.

Image

Se clicarmos no botão Test, nada acontece. Isto acontece porque ainda não associamos um manipulador de eventos ao botão. Para descobrir que tipos de manipuladores de eventos estão disponíveis para um determinado componente, podemos procurar na definição da sua classe os métodos addXXXListener, que nos permitem associar um manipulador de eventos ao componente. A classe javax.swing.JButton estende a classe javax.swing.AbstractButton, que contém os seguintes métodos:

Resumo dos métodos
 
void
addActionListener(ActionListener l)
 
void
addChangeListener(ChangeListener l)
 
void
addItemListener(ItemListener l)
 

Aqui, é necessário consultar a documentação para determinar qual o manipulador de eventos que trata do clique no botão. Trata-se da interface ActionListener. Esta interface define apenas um método:

Resumo do método
 
void
actionPerformed(ActionEvent e)
 

O método recebe um parâmetro ActionEvent, que iremos ignorar por enquanto. Para tratar o clique no botão btntest no nosso programa, primeiro associamos um ouvinte de eventos a ele:


        btnTest.addActionListener(new ActionListener()
         {
                public void actionPerformed(ActionEvent evt){
                  btnTest_clic(evt);
              }
            }//anonymous class
    );//evt manager

Aqui, o método actionPerformed chama o método btnTest_clic, que definimos da seguinte forma:


public void btnTest_clic(ActionEvent evt){
  // console monitoring
System.out.println("clic sur bouton");
}//btnTest_click

Sempre que o utilizador clica no botão Test, é escrita uma mensagem na consola. Isto é demonstrado na seguinte execução:

Image

O programa completo é o seguinte:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
 
// the form class
 public class form4 extends JFrame {
 
     // a button
  JButton btnTest=null;
  Container conteneur=null;
 
  // the manufacturer
  public form4() {
     // window title
    this.setTitle("Formulaire avec bouton");
     // window dimensions
    this.setSize(new Dimension(300,100));
    // creation of an event manager
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//definition win
     // this event handler will manage the events of the current window
    this.addWindowListener(win);
     // retrieve the window container
    conteneur=this.getContentPane();
     // select a layout manager for components in this container
    conteneur.setLayout(null);
    // create a button
    btnTest=new JButton();
    // we set the wording
    btnTest.setText("Test");
    // determine its location and dimensions
    btnTest.setBounds(10,20,100,20);
     // we associate it with an event manager
    btnTest.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt){
              btnTest_clic(evt);
          }
        }//anonymous class
    );//evt manager
     // add the button to the container
    conteneur.add(btnTest);
  }//manufacturer
 
    public void btnTest_clic(ActionEvent evt){
       // console monitoring
    System.out.println("clic sur bouton");
  }//btnTest_click
 
  // test function
 public static void main(String[] args) {
    // the form is displayed
   new form4().setVisible(true);
}//hand
}//class

5.1.4. Manipuladores de eventos

Os principais componentes do Swing que iremos abordar são janelas (JFrame), botões (JButton), caixas de seleção (JCheckBox), botões de opção (JButtonRadio), listas suspensas (JComboBox), listas (JList), barras de rolagem (JScrollBar), rótulos (JLabel), campos de texto de linha única (JTextField) ou campos de texto de várias linhas (JTextArea), menus (JMenuBar) e itens de menu (JMenuItem).

As tabelas seguintes enumeram alguns manipuladores de eventos e os eventos a que estão associados.

Manipulador
Componente(s)
Método de registo
Evento
ActionListener
JButton, JCheckbox, JButtonRadio, JMenuItem
public void addActionListener(ActionListener)
Clique no botão, na caixa de seleção, no botão de opção ou no item de menu
 
JTextField
ItemListener
JComboBox, JList
public void addItemListener(ItemListener)
O item selecionado foi alterado
InputMethodListener
JTextField, JTextArea
public void addMethodInputListener(InputMethodListener)
O texto no campo de entrada foi alterado ou o cursor de entrada foi movido
CaretListener
JTextField, JTextArea
public void addCaretListener(CaretListener)
O cursor de entrada mudou de posição
AdjustmentListener
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
O valor do controlo deslizante mudou
MouseMotionListener
 
public void addMouseMotionListener(MouseMotionListener)
O rato moveu-se
WindowListener
JFrame
public void addWindowListener(WindowListener)
evento da janela
MouseListener
 
public void addMouselistener(MouseListener)
eventos do rato (clique, entrar/sair da área de um componente, botão pressionado, soltar)
FocusListener
 
public void addFocusListener(FocusListener)
eventos de foco (ganho, perdido)
KeyListener
 
public void addKeyListener(KeyListener)
evento de teclado (tecla digitada, pressionada, solta)
Componente
Método para registar manipuladores de eventos
JButton
public void addActionListener(ActionListener)
JCheckbox
public void addItemListener(ItemListener)
JCheckboxMenuItem
public void adicionarOuvinteDeItem(OuvinteDeItem)
JComboBox
public void adicionarOuvinteDeItem(OuvinteDeItem)
public void adicionarOuvinteDeAção(OuvinteDeAção)
Container
public void addContainerListener(ContainerListener)
JComponent
public void adicionarOuvinteDeComponente(OuvinteDeComponente)
public void adicionarOuvinteDeFoco(OuvinteDeFoco)
public void addKeyListener(KeyListener)
public void adicionarOuvinteDoRato(OuvinteDoRato)
public void adicionarOuvinteDeMovimentoDoRato(OuvinteDeMovimentoDoRato)
JFrame
public void addWindowListener(WindowListener)
JList
public void addItemListener(ItemListener)
JMenuItem
public void adicionarOuvinteDeAção(OuvinteDeAção)
JPanel
como Container
JScrollPane
como Container
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
JTextComponent
public void addInputMethodListener(InputMethodListener)
public void addCaretListener(CaretListener)
JTextArea
semelhante a JTextComponent
JTextField
como JTextComponent
public void addActionListener(ActionListener)

Todos os componentes, exceto os do tipo TextXXX, derivam da classe JComponent e, por isso, também possuem os métodos associados a essa classe.

5.1.5. Métodos de tratamento de eventos

A tabela seguinte lista os métodos que os vários manipuladores de eventos devem implementar.

Interface
Métodos
ActionListener
public void actionPerformed(ActionEvent)
AdjustmentListener
public void adjustmentValueChanged(AdjustmentEvent)
ComponentListener
public void componenteOcultado(EventoComponente)
public void componenteMovido(EventoComponente)
public void componenteRedimensionado(EventoComponente)
public void componenteMostrado(EventoComponente)
ContainerListener
public void componenteAdicionado(ContainerEvent)
public void componenteRemovido(EventoContenedor)
FocusListener
public void focusGained(FocusEvent)
public void focusLost(FocusEvent)
Ouvinte de Item
public void itemStateChanged(ItemEvent)
KeyListener
public void teclaPressionada(KeyEvent)
public void teclaSoltada(KeyEvent)
public void teclaDigitada(KeyEvent)
MouseListener
public void mouseClicked(MouseEvent)
public void mouseEntrou(MouseEvent)
public void mouseExited(MouseEvent)
public void mousePressed(MouseEvent)
public void mouseReleased(MouseEvent)
MouseMotionListener
public void mouseDragged(MouseEvent)
public void mouseMoved(MouseEvent)
Ouvinte de Texto
public void textValueChanged(TextEvent)
InputMethodListener
public void InputMethodTextChanged(InputMethodEvent)
public void posiçãoDoCursorAlterada(InputMethodEvent)
CaretListener
public void atualizarCaret(CaretEvent)
WindowListener
public void janelaAtivada(EventoJanela)
public void janelaFechada(EventoJanela)
public void windowClosing(WindowEvent)
public void windowDeactivated(WindowEvent)
public void windowDeiconified(WindowEvent)
public void janelaIconificada(WindowEvent)
public void janelaAberta(EventoJanela)

5.1.6. Classes adaptadoras

Tal como vimos com a interface WindowListener, existem classes denominadas XXXAdapter que implementam as interfaces XXXListener com métodos vazios. Um manipulador de eventos derivado de uma classe XXXAdapter pode, assim, implementar apenas um subconjunto dos métodos da interface XXXListener — especificamente, aqueles exigidos pela aplicação.

Suponhamos que queremos tratar cliques do rato num componente Frame f1. Poderíamos associar-lhe um manipulador de eventos utilizando:

    f1.addMouseListener(new gestionnaireSouris());

e escrever:


    public class gestionnaireSouris implements MouseListener{
         // we write the 5 methods of the MouseListener interface
        // mouseClicked, ..., mouseReleased)
    }// end of class

Como queremos apenas tratar os cliques do rato, é melhor escrever:


public class gestionnaireSouris extends MouseAdapter{
        // we write a single method that handles mouse clicks
        public void mouseClicked(MouseEvent evt){

        }
}// end of class

A tabela seguinte lista as classes adaptadoras para os vários manipuladores de eventos:

Manipulador de eventos
Adaptador
ComponentListener
ComponentAdapter
Ouvinte de contentor
Adaptador de contentor
Ouvinte de Foco
Adaptador de Foco
Ouvinte de Tecla
Adaptador de Teclas
Ouvinte do Rato
Adaptador de rato
Ouvinte de Movimento do Rato
Adaptador de movimento do rato
Ouvinte de janela
Adaptador de janela

5.1.7. Conclusão

Acabámos de apresentar os conceitos básicos da criação de interfaces gráficas de utilizador em Java:

  • criar uma janela
  • criação de componentes
  • associação de componentes à janela utilizando um gestor de layout
  • associar manipuladores de eventos aos componentes

Agora, em vez de construir interfaces gráficas de utilizador «manualmente», como acabámos de fazer, vamos utilizar o JBuilder, uma ferramenta de desenvolvimento Java da Borland/Inprise, versão 4 e superior. Vamos utilizar componentes da biblioteca java.swing, atualmente recomendada pela Sun, a criadora do Java.

5.2. Construir uma interface gráfica de utilizador com o JBuilder

5.2.1. O nosso primeiro projeto no JBuilder

Para nos familiarizarmos com o JBuilder, vamos criar uma aplicação muito simples: uma janela vazia.

  1. Inicie o JBuilder e selecione Ficheiro/Novo Projeto. A primeira página do assistente será então apresentada:

Image

  1. Preencha os seguintes campos:
Nome do projeto
start
Isto irá criar um ficheiro de projeto com o nome start.jpr na pasta especificada no campo «Nome do diretório do projeto»
Caminho Raiz
Especifique a pasta onde a pasta do projeto que está prestes a criar ficará localizada.
Nome do diretório do projeto
Especifique o nome da pasta onde todos os ficheiros do projeto serão colocados. Esta pasta será criada no diretório especificado no campo "Caminho Raiz"

Os ficheiros de origem (.java, .html, ...), os ficheiros de destino (.class, ...) e os ficheiros de cópia de segurança podem ser colocados em diretórios diferentes. Se deixar os respetivos campos em branco, serão colocados no mesmo diretório que o projeto.

Clique em [Seguinte]

  1. Um ecrã confirma as escolhas feitas no passo anterior

Image

Clique em [Seguinte]

  1. Uma nova janela solicita que descreva o seu projeto:

Image

Clique em [Concluir]

  1. Verifique se a opção Exibir/Projeto está marcada. Deverá ver a estrutura do seu projeto no painel esquerdo.

Image

  1. Agora vamos criar uma interface gráfica de utilizador neste projeto. Selecione a opção Ficheiro/Novo/Aplicação:

Image

No campo Classe, introduza o nome da classe a ser criada. Aqui, utilizámos o mesmo nome do projeto.

Clique em [Seguinte]

  1. Aparece o seguinte ecrã:

Image

Classe
interfaceStart
Este é o nome da classe correspondente à janela que será criada
Título
Este é o texto que aparecerá na barra de título da janela

Note que, acima, especificámos que a janela deve ser centrada no ecrã quando a aplicação for iniciada.

Clique em [Concluir]

  1. É aqui que o JBuilder se torna útil.
  • Ele gera os ficheiros de código-fonte .java para as duas classes que nomeámos: a classe da aplicação e a classe da GUI. Estes dois ficheiros aparecem na estrutura do projeto, na janela à esquerda

Image

  • Para aceder ao código gerado para as duas classes, basta clicar duas vezes no ficheiro .java correspondente. Voltaremos ao código gerado mais tarde.
  • Certifique-se de que a opção «Ver/Estrutura» está marcada. Isto permite-lhe visualizar a estrutura da classe atualmente selecionada (clique duas vezes no ficheiro .java). Aqui, por exemplo, está a estrutura da classe «début»:

Image

Aqui aprendemos sobre:

  • as bibliotecas importadas (imports)

  • que existe um construtor start()

  • que existe um método estático main()

  • que existe um atributo packFrame

Qual é a vantagem de ter acesso à estrutura de uma classe?

  • Obtém-se uma visão geral da mesma. Isto é útil se a sua classe for complexa.

  • Pode aceder ao código de um método clicando nele na janela da estrutura da classe. Mais uma vez, isto é útil se a sua classe tiver centenas de linhas. Não precisa de percorrer todas as linhas para encontrar o código que procura.

O código gerado pelo JBuilder já está pronto a usar. Clique em Run/Run Project ou prima F9 e verá a janela que solicitou:

Image

Além disso, ela fecha corretamente quando clica no botão Fechar da janela. Acabámos de criar a nossa primeira interface gráfica de utilizador. Podemos guardar o nosso projeto utilizando a opção Ficheiro/Fechar Projetos:

Image

Ao clicar em «All», todos os projetos na janela acima serão selecionados. Clicar em «OK» irá fechá-los. Se estivermos curiosos o suficiente para navegar, utilizando o Explorador do Windows, até à pasta do nosso projeto (aquela especificada ao assistente no início da configuração do projeto), encontraremos os seguintes ficheiros lá:

Image

No nosso exemplo, especificámos que todos os ficheiros (.java de código-fonte, .class de saída, .jpr de backup) devem estar na mesma pasta que o projeto .jpr.

5.2.2. Ficheiros gerados pelo JBuilder para uma interface gráfica

Vamos agora dar uma olhadela aos ficheiros de código-fonte .java gerados pelo JBuilder. É importante saber como interpretar o que é gerado, uma vez que, na maioria das vezes, teremos de adicionar código ao que já existe. Comecemos por abrir o nosso projeto: Ficheiro/Abrir Projeto e selecionemos o projeto debut.jpr. Veremos o projeto que criámos anteriormente.

5.2.2.1. A classe principal

Vamos examinar a classe debut.java clicando duas vezes no seu nome na janela que exibe a lista de ficheiros do projeto. Temos o seguinte código:

import javax.swing.UIManager;
import java.awt.*;

public class début {
  boolean packFrame = false;

   /**Building the application*/
  public début() {
    interfaceDébut frame = new interfaceDébut();

     //Validate frames with predefined sizes
     //Compact frames with preferred size information - e.g. from their layout
    if (packFrame) {
      frame.pack();
    }
    else {
      frame.validate();
    }
    //Center window
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = frame.getSize();
    if (frameSize.height > screenSize.height) {
      frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
      frameSize.width = screenSize.width;
    }
    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
    frame.setVisible(true);
  }
   /**Main method*/
  public static void main(String[] args) {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    new début();
  }
}

Vamos comentar o código gerado:

  1. A função principal define a aparência da janela (setLookAndFeel) e cria uma instância da classe début.
  2. O construtor début() é então executado. Cria uma instância de frame da classe window (new interfaceDébut()). Esta instância é construída, mas não é apresentada.
  3. A janela é então dimensionada com base nas informações disponíveis para cada um dos seus componentes (frame.validate). Em seguida, inicia a sua existência independente, exibindo-se e respondendo às entradas do utilizador.
  4. A janela é centrada no ecrã porque solicitámos isso ao configurar a janela com o assistente.

Vamos ver o que aconteceria se reduzíssemos o código do début.java ao seu mínimo, tal como fizemos no início do capítulo. Vamos criar uma nova classe. Selecione Ficheiro/Nova Classe:

Image

Dê à nova classe o nome «start2» e clique em [Concluir]. Um novo ficheiro aparece no projeto:

Image

O ficheiro début2.java é reduzido à sua forma mais simples:

public class début2 {
}

Vamos completar a classe da seguinte forma:

public class début2 {
   // main function
  public static void main(String args[]){
    // creates the
    new interfaceDébut().show();    // or new interfaceDébut.setVisible(true);
  }//hand
}//class start2

A função main cria uma instância da janela interfaceDébut e exibe-a (show). Antes de executar o nosso projeto, precisamos de especificar que a classe que contém a função main a ser executada é agora a classe début2. Clique com o botão direito do rato no projeto début.jpr e selecione a opção Propriedades, depois o separador Execução:

21

Image

Aqui, está indicado que a classe principal é «début» (1). Clique no botão (2) para selecionar uma classe principal diferente:

Image

Selecione «début2» e clique em [OK].

Image

Clique em [OK] para confirmar esta escolha e, em seguida, execute o projeto selecionando Run/Run Project ou premindo F9. Aparece a mesma janela que com a classe «start», exceto que não está centrada, uma vez que isso não foi solicitado aqui. A partir de agora, já não apresentaremos a classe principal gerada pelo JBuilder, porque esta faz sempre a mesma coisa: criar uma janela. A partir de agora, iremos concentrar-nos na classe da janela.

5.2.2.2. A classe da janela

Vamos agora analisar o código que foi gerado para a classe interfaceDébut:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceDébut extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

  /**Building the frame*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Ma première interface graphique avec Jbuilder");
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
}

5.2.2.2.1. Bibliotecas importadas
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

Estas são as bibliotecas java.awt, java.awt.event e javax.swing. As duas primeiras eram as únicas disponíveis para a criação de interfaces gráficas de utilizador nas primeiras versões do Java. A biblioteca javax.swing é mais recente. Aqui, é necessária para a janela JFrame utilizada neste exemplo.

5.2.2.2.2. Os atributos
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

O JPanel é um tipo de contentor no qual podem ser colocados componentes. O BorderLayout é um dos gestores de layout disponíveis para colocar componentes dentro do contentor. Em todos os nossos exemplos, não utilizaremos um gestor de layout e colocaremos nós próprios os componentes num local específico dentro do contentor. Para tal, utilizaremos o gestor de layout nulo.

5.2.2.2.3. O construtor da janela
   /**Building the frame*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Ma première interface graphique avec Jbuilder");
  }
  1. O construtor começa por indicar que irá tratar os eventos na janela (enableEvents) e, em seguida, chama o método jbInit.
  2. O contentor (JPanel) da janela (JFrame) é obtido (getContentPane)
  3. O gestor de layout é definido (setLayout)
  4. O tamanho da janela é definido (setSize)
  5. O título da janela é definido (setTitle)

5.2.2.2.4. O manipulador de eventos
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }

O construtor indicou que a classe iria lidar com eventos de janela. O método processWindowEvent executa esta tarefa. Começa por passar o WindowEvent recebido para a sua classe pai (JFrame); depois, se o evento for WINDOW_CLOSING — acionado ao clicar no botão de fechar da janela — a aplicação é encerrada.

5.2.2.2.5. Conclusão

O código da classe da janela difere do apresentado no exemplo no início do capítulo. Se estivéssemos a utilizar um gerador de código Java diferente do JBuilder, provavelmente teríamos um código ainda mais diferente. Na prática, aceitaremos o código gerado pelo JBuilder para construir a janela, de modo a podermos concentrar-nos exclusivamente na escrita dos manipuladores de eventos para a interface gráfica do utilizador.

5.2.3. Desenhar uma GUI

5.2.3.1. Um exemplo

No exemplo anterior, não colocámos quaisquer componentes na janela. Vamos agora criar uma janela com um botão, um rótulo e um campo de entrada:

Image

Os campos são os seguintes:

N.º
nome
tipo
função
1
lblInput
JLabel
um rótulo
2
txtInput
JTextField
um campo de entrada
3
cmdDisplay
JButton
para exibir o conteúdo do campo de texto txtSaisie numa caixa de diálogo

Seguindo o mesmo procedimento do projeto anterior, compile o projeto interface2.jpr sem adicionar nenhum componente à janela por enquanto.

Image

Na janela acima, selecione a classe interface2.java. À direita desta janela encontra-se uma pasta com separadores:

Image

A guia «Source» dá acesso ao código-fonte da classe interface2.java. A guia «Design» permite-lhe construir visualmente a janela. Selecione esta guia. Agora vê o contentor da janela, que irá conter os componentes que nele colocar. Atualmente, está vazio. A janela à esquerda mostra a estrutura da classe:

Image

isto
representa a janela
contentPane
o seu contentor, no qual iremos colocar componentes, bem como o modo de disposição desses componentes dentro do contentor (BorderLayout por predefinição)
borderLayout1
uma instância do gestor de layout

Selecione este objeto. A janela de propriedades aparecerá então à direita:

Image

Algumas destas propriedades merecem destaque:

fundo
para definir a cor de fundo da janela
foreground
para definir a cor do texto e dos botões na janela
JMenuBar
para associar um menu à janela
title
para atribuir um título à janela
resizable
para definir o tipo de janela
font
para definir o tipo de letra do texto na janela

Com este objeto ainda selecionado, pode redimensionar o contentor exibido no ecrã arrastando os pontos de ancoragem à volta do contentor:

Image

Estamos agora prontos para colocar componentes no contentor acima. Antes de o fazer, vamos alterar o gestor de layout. Selecione o objeto contentPane na janela de estrutura:

Image

Em seguida, na janela de propriedades deste objeto, selecione a propriedade layout e escolha o valor null entre as opções disponíveis:

Image

Esta ausência de um gestor de layout permitirá-nos colocar livremente os componentes dentro do contentor. Chegou a altura de os selecionar.

Quando o painel Design está selecionado, os componentes ficam disponíveis numa pasta com separadores na parte superior da janela de design:

Image

Para construir a interface gráfica do utilizador, dispomos de componentes Swing (1) e componentes AWT (2). Aqui, iremos utilizar os componentes Swing. Na barra de componentes acima, selecione um componente JLabel (3), um componente JTextField (4) e um componente JButton (5), e coloque-os no contentor da janela Design.

Image

Agora vamos personalizar cada um destes três componentes:

  • o rótulo (JLabel) jLabel1

Selecione o componente para abrir a janela Propriedades. Na janela Propriedades, modifique as seguintes propriedades: nome: lblSaisie, texto: Saisie

  • o campo de texto (JTextField) jTextfield1

Selecione o componente para abrir a janela de propriedades. Na janela, modifique as seguintes propriedades: nome: txtSaisie, texto: deixe em branco

  • o botão (JButton): nome: cmdAfficher, texto: Exibir

Temos agora a seguinte janela:

Image

e a seguinte estrutura:

Image

Podemos executar (F9) o nosso projeto para ter uma primeira visão da janela em ação:

Image

Feche a janela. Ainda precisamos de escrever o procedimento associado a um clique no botão Mostrar. Selecione o botão para aceder à janela Propriedades. Esta janela tem dois separadores: Propriedades e Eventos. Selecione Eventos.

Image

A coluna da esquerda da janela lista os eventos possíveis para o botão. Um clique num botão corresponde ao evento actionPerformed. A coluna da direita contém o nome do procedimento chamado quando o evento correspondente ocorre. Clique na célula à direita do evento actionPerformed:

Image

O JBuilder gera um nome predefinido para cada manipulador de eventos no formato ComponentName_EventName, neste caso cmdDisplay_actionPerformed. Pode eliminar o nome predefinido e introduzir um nome diferente. Para aceder ao código do manipulador cmdDisplay_actionPerformed, basta clicar duas vezes no seu nome acima. Será então automaticamente direcionado para o painel de código-fonte da classe, posicionado no esqueleto do código do manipulador de eventos:

  void cmdAfficher_actionPerformed(ActionEvent e) {
 }

Resta apenas completar este código. Aqui, queremos apresentar uma caixa de diálogo com o conteúdo do campo txtSaisie:

  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), 
"Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
 }

JOptionPane é uma classe da biblioteca javax.swing. Permite-lhe apresentar mensagens acompanhadas por um ícone ou solicitar informações ao utilizador. Aqui, estamos a utilizar um método estático da classe:

Image

parentComponent
o objeto contêiner "pai" da caixa de diálogo: aqui, this.
message
um objeto a ser exibido. Aqui, o conteúdo do campo de entrada
title
o título da caixa de diálogo
messageType
o tipo de mensagem a apresentar. Determina o ícone que será apresentado na caixa ao lado da mensagem. Valores possíveis:
INFORMATION_MESSAGE, QUESTION_MESSAGE, ERROR_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE

Vamos executar a nossa aplicação (F9):

Image

Image

5.2.3.2. O código da classe da janela

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import javax.swing.event.*;


public class interface2 extends JFrame {
  JPanel contentPane;
  JLabel lblSaisie = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmdAfficher = new JButton();

  /**Building the frame*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
    lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }
}

5.2.3.2.1. Os atributos
  JPanel contentPane;
  JLabel lblSaisie = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmdAfficher = new JButton();

Aqui temos o contêiner de componentes JPanel e os três componentes.

5.2.3.2.2. O construtor
   /**Building the frame*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
    lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }

O construtor interface2 é semelhante ao construtor da interface gráfica anterior que estudámos. As diferenças encontram-se no método jbInit: o código de construção da janela depende dos componentes colocados no seu interior. Podemos reutilizar o código jbInit adicionando os nossos próprios comentários:

  private void jbInit() throws Exception  {
       // the window itself (size, title)
this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
         // the component container
    contentPane = (JPanel) this.getContentPane();
         // no formatting manager for this container
    contentPane.setLayout(null);
         // label lblSaisie (label, position, size)
         lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
        // input field (position, size)
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
         // display button (label, position, size)
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
         // button event manager
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
         // add the 3 components to the container
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }//jbInit

Há dois pontos que merecem destaque:

  • este código poderia ter sido escrito manualmente. Isto significa que o JBuilder não é necessário para criar uma interface gráfica de utilizador.
  • a forma como o manipulador de eventos do botão cmdAfficher está definido. O manipulador de eventos do componente cmdAfficher poderia ter sido declarado utilizando `cmdAfficher.addActionListener(new handler())`, em que `handler` seria uma classe com um método público `actionPerformed` responsável por tratar o clique no botão Mostrar. Aqui, o JBuilder utiliza uma instância de uma classe anónima como manipulador:
 new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }

É criada uma nova instância da interface ActionListener com o seu método actionPerformed definido no momento. Este método simplesmente chama um método da classe interface2. Tudo isto é apenas uma solução alternativa para definir os procedimentos de tratamento de eventos para os componentes da janela dentro da mesma classe que a própria janela. Poderíamos fazê-lo de forma diferente:

cmdAfficher.addActionListener(this)

o que faz com que o método actionPerformed seja procurado nesta, ou seja, na classe da janela. Este segundo método parece mais simples, mas o primeiro tem uma vantagem: permite diferentes manipuladores para diferentes botões, ao passo que o segundo método não o permite. Neste último caso, o único método actionPerformed tem de tratar cliques de diferentes botões e, por isso, tem de identificar primeiro qual o botão que desencadeou o evento antes de poder começar o processamento.

5.2.3.2.3. Manipuladores de eventos

Vemos os que já abordámos:

   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }

     // click on View button
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }

5.2.3.3. Conclusão

A partir dos dois projetos estudados, podemos concluir que, uma vez construída a interface gráfica do utilizador com o JBuilder, a tarefa do programador consiste em escrever os manipuladores de eventos para os eventos que pretende tratar nessa interface gráfica do utilizador.

5.2.4. Procurar ajuda

Com Java, muitas vezes é necessário recorrer à ajuda, especialmente devido ao grande número de classes disponíveis. Aqui ficam algumas dicas para encontrar ajuda sobre uma classe. Selecione a opção Ajuda/Tópicos de Ajuda no menu.

Image

O ecrã de Ajuda tem geralmente duas janelas:

  • a da esquerda, onde introduz o que procura. Tem três separadores: Índice, Índice remissivo e Pesquisa.
  • a janela à direita, que apresenta os resultados da pesquisa

Está disponível ajuda sobre como utilizar o sistema de ajuda do JBuilder. Na ajuda do JBuilder, selecione a opção Ajuda/Utilizar a Ajuda. Isto irá explicar como utilizar o sistema de ajuda. Por exemplo, irá mostrar-lhe os diferentes componentes do visualizador de ajuda:

Image

Vamos dar uma olhadela mais atenta às páginas Índice e Índice.

5.2.4.1. Ajuda: Índice

Image

5.2.4.1.1. Índice: Introdução ao Java

Aqui encontrará os conceitos básicos de Java, mas não só isso, como mostra a lista de tópicos abordados nesta secção:

Image

5.2.4.1.2. Índice: Tutoriais

Se selecionarmos a opção Tutoriais no índice acima, a janela à direita exibe uma lista dos tutoriais disponíveis:

Image

Os tutoriais básicos são particularmente úteis para começar a utilizar o JBuilder. Existem muitos outros além dos apresentados acima e, quando pretender desenvolver uma aplicação, pode ser útil verificar primeiro se existe algum tutorial que o possa ajudar.

5.2.4.1.3. Índice: O JDK

Ao selecionar a opção Java 2 JDK 1.3, tem acesso a todas as bibliotecas do JDK. Geralmente, este não é o local certo para procurar se precisar de informações sobre uma classe específica e não souber em que biblioteca ela se encontra. No entanto, esta opção é útil se estiver interessado em obter uma visão geral das bibliotecas Java.

5.2.4.2. Ajuda: Índice

Selecione o separador Índice no painel esquerdo da janela Ajuda. Esta opção permite-lhe, por exemplo, encontrar ajuda sobre uma classe. Suponha, por exemplo, que deseja conhecer os métodos dos campos de entrada JTextField do Swing. Digite JTextField no campo de pesquisa:

Image

A Ajuda irá apresentar entradas do índice que comecem com o texto que digitou:

Image

Basta clicar duas vezes na entrada que lhe interessa, neste caso a classe JTextField. A ajuda para esta classe aparecerá então na janela à direita:

Image

É então fornecida uma descrição completa da classe.

5.2.5. Alguns componentes Swing

Apresentaremos agora várias aplicações que utilizam os componentes Swing mais comuns para explorar os seus principais métodos e propriedades. Para cada aplicação, apresentaremos a interface gráfica e o código relevante, em particular o dos manipuladores de eventos.

5.2.5.1. Componentes JLabel e JTextField

Já nos deparámos com estes dois componentes. O JLabel é um componente de texto e o JTextField é um componente de campo de entrada. Os seus dois métodos principais são

String getText()
para recuperar o conteúdo do campo de entrada ou o texto do rótulo
void setText(String text)
para definir o texto no campo ou no rótulo

Os eventos normalmente utilizados para o JTextField são os seguintes:

actionPerformed
indica que o utilizador confirmou (ao premir Enter) o texto introduzido
caretUpdate
indica que o utilizador moveu o cursor de entrada
inputMethodChanged
indica que o utilizador alterou o campo de entrada

Aqui está um exemplo que utiliza o evento caretUpdate para acompanhar as alterações num campo de entrada:

Image

N.º
tipo
nome
função
1
JTextField
txtInput
campo de entrada
2
JTextField
txtControl
exibe o texto de 1 em tempo real
3
JButton
cmdClear
para limpar os campos 1 e 2
4
JButton
cmdExit
para sair da aplicação

O código relevante para esta aplicação é o seguinte:

import java.awt.*;
....


public class Cadre1 extends JFrame {
  JPanel contentPane;
  JTextField txtSaisie = new JTextField();
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JTextField txtControle = new JTextField();
  JButton CmdEffacer = new JButton();
  JButton CmdQuitter = new JButton();

  /**Building the frame*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
    ....
    txtSaisie.addCaretListener(new javax.swing.event.CaretListener() {
      public void caretUpdate(CaretEvent e) {
        txtSaisie_caretUpdate(e);
      }
    });

...
    CmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdEffacer_actionPerformed(e);
      }
    });
...
    CmdQuitter.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdQuitter_actionPerformed(e);
      }
    });
....
}

   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_caretUpdate(CaretEvent e) {
         // the input cursor has moved
    txtControle.setText(txtSaisie.getText());
  }

  void CmdQuitter_actionPerformed(ActionEvent e) {
        // quit the application
    System.exit(0);
  }

  void CmdEffacer_actionPerformed(ActionEvent e) {
        // delete the contents of the input field
    txtSaisie.setText("");
  }
}

Eis um exemplo de execução:

Image

5.2.5.2. Componente JComboBox

Image

Image

Um componente JComboBox é uma lista suspensa combinada com um campo de entrada: o utilizador pode selecionar um item (2) ou digitar texto (1). Por predefinição, os JComboBoxes não são editáveis. Deve chamar explicitamente o método setEditable(true) para torná-los editáveis. Para saber mais sobre a classe JComboBox, digite JComboBox no índice da ajuda.

O objeto JComboBox pode ser criado de várias formas:

new JComboBox()
cria uma caixa de combinação vazia
new JComboBox (Object[] items)
cria uma caixa de combinação contendo uma matriz de objetos
new JComboBox(Vector items)
igual ao anterior, mas com um vetor de objetos

Pode parecer surpreendente que uma caixa de combinação possa conter objetos quando normalmente contém cadeias de caracteres. Visualmente, é de facto esse o caso. Se um JComboBox contiver um objeto obj, exibe a cadeia de caracteres obj.toString(). Recorde-se que todos os objetos têm um método toString herdado da classe Object, que devolve uma cadeia de caracteres que «representa» o objeto.

Os métodos úteis da classe JComboBox são os seguintes:

void addItem(Object anObject)
adiciona um objeto à caixa de combinação
int getItemCount()
retorna o número de itens no combo
Object getItemAt(int i)
retorna o i-ésimo objeto na caixa de combinação
void insertItemAt(Object anObject, int i)
Inserir o objeto anObject na posição i na caixa de combinação
int getSelectedIndex()
retorna o índice do item selecionado na caixa de combinação
Object getSelectedItem()
retorna o item selecionado na caixa de combinação
void setSelectedIndex(int i)
seleciona o item i na caixa de combinação
void setSelectedItem(Object anObject)
seleciona o objeto especificado na caixa de combinação
void removeAllItems()
limpa a caixa de combinação
void removeItemAt(int i)
remove o item número i da caixa de combinação
void removeItem(Object anObject)
remove o objeto especificado da caixa de combinação
void setEditable(boolean val)
torna a caixa de combinação editável (val=true) ou não (val=false)

Quando um item é selecionado da lista suspensa, o evento actionPerformed é acionado, o qual pode então ser usado para detetar a alteração na seleção dentro da caixa de combinação. Na aplicação a seguir, usamos este evento para exibir o item que foi selecionado da lista.

Image

Estamos a mostrar apenas o código relevante para a janela.

public class Cadre1 extends JFrame {
  JPanel contentPane;
  JComboBox jComboBox1 = new JComboBox();
  JLabel jLabel1 = new JLabel();

   /**Building the frame*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // treatment - fill the combo
    String[] infos={"un","deux","trois","quatre"};
    for(int i=0;i<infos.length;i++)
      jComboBox1.addItem(infos[i]);
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
        ....

    jComboBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jComboBox1_actionPerformed(e);
      }
    });
       .... 
  }

  void jComboBox1_actionPerformed(ActionEvent e) {
        // a new element has been selected - it is displayed
    JOptionPane.showMessageDialog(this,jComboBox1.getSelectedItem(),
"actionPerformed",JOptionPane.INFORMATION_MESSAGE);
  }

}

5.2.5.3. Componente JList

O componente JList do Swing é mais complexo do que o seu equivalente na biblioteca AWT. Existem duas diferenças importantes:

  • O conteúdo da lista é gerido por um objeto separado da própria lista. Aqui, utilizaremos um objeto DefaultListModel, que funciona como um Vector, mas também notifica o objeto JList sempre que o seu conteúdo muda, para que a apresentação visual da lista seja atualizada em conformidade.
  • A lista não rola por predefinição. Deve colocar a lista dentro de um contentor ScrollPane, o que permite a rolagem.

No código-fonte, uma lista pode ser definida da seguinte forma:

      // the vector of list values 
DefaultlistModel valeurs=new DefaultListModel();
// the list itself, to which we associate the vector of its values
  JList jList1 = new JList(valeurs);
     // the scrolling container in which the list is placed to obtain a scrolling list
  JScrollPane jScrollPane1 = new JScrollPane(jList1);

Para incluir a lista jList1 no contentor jScrollPane1, o código gerado pelo JBuilder procede de forma diferente:

  • declaração do contentor nos atributos da janela
  JScrollPane jScrollPane1 = new JScrollPane();
  • Em seguida, no código jbInit, a lista é adicionada ao contentor
    jScrollPane1.getViewport().add(jList1, null);

Para adicionar valores à lista JList1 acima, basta adicioná-los à sua matriz de valores:

    // init liste
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);

e verá então a seguinte janela:

Image

Como é que esta interface foi criada?

  • Selecione um componente JScrollPane na página «Swing Containers» dos componentes e arraste-o para a janela, redimensionando-o para as dimensões desejadas
  • Selecione um componente JList na página "Swing" dos componentes e solte-o no contentor JScrollPane, onde ocupará todo o espaço.

O código gerado pelo JBuilder precisa de ser ligeiramente modificado para produzir o seguinte código:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  DefaultListModel valeurs=new DefaultListModel();
  JList jList1 = new JList(valeurs);
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel2 = new JLabel();


   /**Building the frame*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // treatment
     // include the list in the scrollPane
    // init list
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);
  }

   /**Initialize component*/
  private void jbInit() throws Exception  {
        ....
         // the jList1 list is associated with the jcrollPane1 container
    jScrollPane1.getViewport().add(jList1, null);
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
        ....
  }
}

Vamos agora explorar os principais métodos da classe JList, pesquisando por JList no índice de ajuda. O objeto JList pode ser construído de várias maneiras:

Image

Um método simples é aquele que utilizámos: criar um DefaultListModel V vazio e, em seguida, associá-lo à lista a ser criada utilizando new JList(V). O conteúdo da lista não é gerido pelo objeto JList, mas pelo objeto que contém os valores da lista. Se o conteúdo tiver sido construído utilizando um objeto DefaultListModel baseado na classe Vector, os métodos da classe Vector podem ser utilizados para adicionar, inserir e remover elementos da lista. Uma lista pode suportar seleção única ou múltipla. Isto é definido pelo método setSelectionMode:

Image

Pode determinar o modo de seleção atual utilizando getSelectionMode:

Image

Os itens selecionados podem ser obtidos utilizando os seguintes métodos:

Image

Sabemos como associar um vetor de valores a uma lista utilizando o construtor JList(DefaultListModel). Por outro lado, podemos obter o objeto DefaultListModel a partir de um JList da seguinte forma:

Image

Agora sabemos o suficiente para escrever a seguinte aplicação:

Image

Os componentes desta janela são os seguintes:

N.º
tipo
nome
função
1
JTextField
txtInput
campo de entrada
2
JList
jList1
lista contida num contentor jScrollPane1
3
JList
jList2
lista contida num contentor jScrollPane2
4
JButton
cmd1To2
transfere os itens selecionados da lista 1 para a lista 2
5
JButton
cmd2To1
faz o contrário
6
JButton
cmdRaz1
limpa a lista 1
7
JButton
cmdRaz2
limpa a lista 2

O utilizador digita texto no campo (1) e envia-o. Isto aciona o evento actionPerformed no campo de entrada, que é utilizado para adicionar o texto introduzido à lista 1. Aqui está o código para esta primeira função:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Building the frame*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Initialize component*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // Jlist1 is placed in the jScrollPane1 container
    jScrollPane1.getViewport().add(jList1, null);
        // Jlist2 is placed in the jScrollPane2 container
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     // the input text has been validated
     // we recover it free of its start and end spaces
    String texte=txtSaisie.getText().trim();
     // if it's empty, we don't want it
    if(texte.equals("")){
      // error msg
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // end
      return;
    }//if
    // if it is not empty, it is added to the values in list 1
    v1.addElement(texte);
     // and empty the input field
    txtSaisie.setText("");
  }/// txtSaisie_actionperformed
}//class

O código para transferir os itens selecionados de uma lista para outra é o seguinte:

  void cmd1To2_actionPerformed(ActionEvent e) {
    // transfer items selected in list 1 to list 2
    transfert(jList1,jList2);
  }//cmd1To2

  void cmd2To1_actionPerformed(ActionEvent e) {
    // transfer selected items in jList2 to jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  private void transfert(JList L1, JList L2){
      // transfer items selected in list 1 to list 2
       // retrieve the array of indices of the elements selected in L1
      int[] indices=L1.getSelectedIndices();
      // anything to do?
      if (indices.length==0) return;
      // we retrieve the values of L1
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      // and L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // the values selected in L1 are added to L2
        v2.addElement(v1.elementAt(indices[i]));
        // l1 elements copied into L2 must be deleted from L1
        v1.removeElementAt(indices[i]);
      }//for
  }//transfer

O código associado aos botões Raz é muito simples:

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // empty list 1
    v1.removeAllElements();
  }//cmd Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // empty list 2
    v2.removeAllElements();
  }///cmd Raz2

5.2.5.4. Caixas de seleção JCheckBox, botões de opção JButtonRadio

Propomos escrever a seguinte aplicação:

Image

Os componentes da janela são os seguintes:

N.º
tipo
nome
função
1
JButtonRadio
jButtonRadio1
jButtonRadio2
jButtonRadio3
3 botões de opção que fazem parte do grupo buttonGroup1
2
JCheckBox
jCheckBox1
jCheckBox2
jCheckBox3
3 caixas de seleção
3
JList
jList1
uma lista num contentor jScrollPane1
4
ButtonGroup
buttonGroup1
componente não visível - utilizado para agrupar os três botões de opção, de modo que, quando um é selecionado, os outros são desmarcados.

Um grupo de botões de opção pode ser criado da seguinte forma:

  • Coloque cada botão de opção sem se preocupar em agrupá-los
  • Coloque um componente Swing ButtonGroup no contentor. Este componente é não visual. Por isso, não aparece no designer de janelas. No entanto, aparece na sua estrutura:

Image

Acima, no ramo Outros, pode ver os atributos não visuais da janela. Depois de criado um grupo de botões de opção, pode associar cada botão de opção a ele. Para tal, selecione as propriedades do botão de opção:

Image

e, na propriedade buttonGroup do botão de opção, introduza o nome do grupo no qual pretende colocar o botão de opção, neste caso buttonGroup1. Repita este passo para os 3 botões de opção.

O método principal para botões de opção e caixas de seleção é o método isSelected(), que indica se a caixa de seleção ou o botão está selecionado. O texto associado ao componente pode ser recuperado usando getText() e definido usando setText(String text). A caixa de seleção ou o botão de opção pode ser selecionado usando o método setSelected(boolean value).

Quando um botão de opção ou uma caixa de seleção é clicado, o evento actionPerformed é acionado. No código a seguir, usamos este evento para acompanhar as alterações nos valores dos botões de opção e das caixas de seleção:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JRadioButton jRadioButton1 = new JRadioButton();
  JRadioButton jRadioButton2 = new JRadioButton();
  JRadioButton jRadioButton3 = new JRadioButton();
  JCheckBox jCheckBox1 = new JCheckBox();
  JCheckBox jCheckBox2 = new JCheckBox();
  JCheckBox jCheckBox3 = new JCheckBox();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel valeurs=new DefaultListModel();
  JList jList1 = new JList(valeurs);

   /**Building the frame*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
    jRadioButton1.setSelected(true);
    jRadioButton1.setText("un");
    jRadioButton1.setBounds(new Rectangle(57, 31, 49, 23));
    jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });

    jRadioButton2.setBounds(new Rectangle(113, 30, 49, 23));
    jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });
    jRadioButton2.setText("deux");

    jRadioButton3.setBounds(new Rectangle(168, 30, 49, 23));
    jRadioButton3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });
    jRadioButton3.setText("trois");

// radio buttons are grouped together
    buttonGroup1.add(jRadioButton1);
    buttonGroup1.add(jRadioButton2);
    buttonGroup1.add(jRadioButton3);

// checkboxes
    jCheckBox1.setText("A");
    jCheckBox1.setBounds(new Rectangle(58, 69, 32, 17));
    jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });

    jCheckBox2.setBounds(new Rectangle(112, 69, 40, 17));
    jCheckBox2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });
    jCheckBox2.setText("B");

    jCheckBox3.setText("C");
    jCheckBox3.setBounds(new Rectangle(170, 69, 37, 17));
    jCheckBox3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });

    ....
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
        ...
  }

  private void afficheRadioButtons(ActionEvent e){
     // displays the values of the 3 radio buttons
    valeurs.addElement("boutons radio=("+jRadioButton1.isSelected()+","+
      jRadioButton2.isSelected()+","+jRadioButton3.isSelected()+")");
  }//afficheRadioButtons

  void afficheCases(ActionEvent e) {
     // displays checkbox values
    valeurs.addElement("cases à cocher=["+jCheckBox1.isSelected()+","+
      jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
  }//afficheCases

}//class

Aqui está um exemplo de execução:

Image

5.2.5.5. Componente JScrollBar

Vamos criar a seguinte aplicação:

Image

N.º
tipo
nome
função
1
JScrollBar
jScrollBar1
uma barra de deslocamento horizontal
2
JScrollBar
jScrollBar2
um controlador deslizante vertical
3
JTextField
txtvalueHS
exibe o valor do controlo deslizante horizontal 1 - também permite definir este valor
4
JTextField
txtVSvalue
exibe o valor do controlo deslizante vertical 2 - permite também definir este valor
  • Um controlo deslizante JScrollBar permite ao utilizador selecionar um valor a partir de um intervalo de valores inteiros representados pela «barra» do controlo deslizante, ao longo da qual um cursor se move.
  • Para um controlo deslizante horizontal, a extremidade esquerda representa o valor mínimo do intervalo, a extremidade direita o valor máximo e o cursor o valor atualmente selecionado. Para um controlo deslizante vertical, o mínimo é representado pela extremidade superior e o máximo pela extremidade inferior. O par (min,max) tem como valor predefinido (0,100).
  • Clicar nas extremidades do controlo deslizante altera o valor em um incremento (positivo ou negativo), dependendo da extremidade clicada, conforme definido pelo parâmetro unitIncrement, cujo valor padrão é 1.
  • Clicar em qualquer um dos lados do controlador deslizante altera o valor em um incremento (positivo ou negativo), dependendo da extremidade clicada, conhecido como blockIncrement, cujo valor padrão é 10.
  • Estes cinco valores (min, max, value, unitIncrement, blockIncrement) podem ser recuperados utilizando os métodos getMinimum(), getMaximum(), getValue(), getUnitIncrement() e getBlockIncrement(), todos os quais devolvem um inteiro, e podem ser definidos utilizando os métodos setMinimum(int min), setMaximum(int max), setValue(int val), setUnitIncrement(int uInc) e setBlockIncrement(int bInc)

Há algumas coisas a saber ao utilizar componentes JScrollBar. Primeiro, pode ser encontrado na paleta de componentes do Swing:

Image

Quando o arrasta para o contentor, este fica na orientação vertical por predefinição. Pode torná-lo horizontal utilizando a propriedade de orientação abaixo:

Image

Na janela de propriedades acima, pode ver que tem acesso às propriedades minimum, maximum, value, unitIncrement e blockIncrement da JScrollBar. Pode, portanto, definir estas propriedades em tempo de design. Quando coloca uma barra de deslocamento no contentor, a sua «barra de deslocamento» não aparece:

Image

Pode resolver este problema adicionando uma borda ao componente. Isto é feito utilizando a sua propriedade border, que pode assumir vários valores:

Image

Aqui está um exemplo de RaisedBevel:

Image

Quando clica na extremidade superior de um controlador deslizante vertical, o seu valor diminui. Isto pode surpreender o utilizador comum, que normalmente espera ver o valor «aumentar». Resolvemos este problema definindo unitIncrement e blockIncrement com valores negativos.

Como é que se acompanham as alterações num controlador deslizante? Quando o seu valor muda, o evento adjustmentValueChanged é acionado. Basta associar um procedimento a este evento para ser notificado de todas as alterações no valor da barra de deslocamento.

Image

O código relevante para a nossa aplicação é o seguinte:

....

public class cadreAppli extends JFrame {
  JPanel contentPane;
  JScrollBar jScrollBar1 = new JScrollBar();
  Border border1;
  JTextField txtValeurHS = new JTextField();
  JScrollBar jScrollBar2 = new JScrollBar();
  JTextField txtValeurVS = new JTextField();
  TitledBorder titledBorder1;

   /**Building the frame*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
...

// a border for scrollbars
    border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.white,Color.white,new Color(134, 134, 134),new Color(93, 93, 93));
        // no border title
    titledBorder1 = new TitledBorder("");

    jScrollBar1.setOrientation(JScrollBar.HORIZONTAL);
    jScrollBar1.setBorder(BorderFactory.createRaisedBevelBorder());
    jScrollBar1.setAutoscrolls(true);
    jScrollBar1.setBounds(new Rectangle(37, 17, 218, 20));
    jScrollBar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar1_adjustmentValueChanged(e);
      }
    });

    txtValeurHS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValeurHS_actionPerformed(e);
      }
    });

    jScrollBar2.setBounds(new Rectangle(39, 51, 30, 27));
    jScrollBar2.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar2_adjustmentValueChanged(e);
      }
    });
    jScrollBar2.setAutoscrolls(true);
    jScrollBar2.setUnitIncrement(-1);
    jScrollBar2.setBorder(BorderFactory.createRaisedBevelBorder());

    txtValeurVS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValeurVS_actionPerformed(e);
      }
    });

    ......
  }

   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
    // the value of scrollbar 1 has changed
    txtValeurHS.setText(""+jScrollBar1.getValue());
  }

  void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
    // scrollbar 2 value has changed
    txtValeurVS.setText(""+jScrollBar2.getValue());
  }

  void txtValeurHS_actionPerformed(ActionEvent e) {
    // set the horizontal scrollbar value
    setValeur(jScrollBar1,txtValeurHS);
  }

  void txtValeurVS_actionPerformed(ActionEvent e) {
    // set the vertical scrollbar value
    setValeur(jScrollBar2,txtValeurVS);
  }

  private void setValeur(JScrollBar jS, JTextField jT){
     // sets the scrollbar value jS with the field text jT
    int valeur=0;
    try{
      valeur=Integer.parseInt(jT.getText());
      jS.setValue(valeur);
    }
    catch (Exception e){
      // error is displayed
      afficher(""+e);
    }//try-catch
  }//setValeur

  void afficher(String message){
    // displays a message in a box
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//display

}

Aqui está um exemplo de execução:

Image

5.2.5.6. Componente JTextArea

O componente JTextArea é um componente onde é possível introduzir várias linhas de texto, ao contrário do componente JTextField, onde só é possível introduzir uma única linha. Se este componente for colocado num contentor com rolagem (JScrollPane), obtém-se um campo de introdução de texto com rolagem. Este tipo de componente pode ser encontrado, por exemplo, numa aplicação de e-mail, onde o texto da mensagem a enviar é digitado num componente JTextArea. Os métodos padrão são String getText() para recuperar o conteúdo da área de texto, setText(String text) para definir o texto na área de texto e append(String text) para acrescentar texto ao texto já presente na área de texto. Considere a seguinte aplicação:

Image

N.º
tipo
nome
função
1
JTextArea
txtText
uma área de texto com várias linhas
2
JButton
cmdDisplay
exibe o conteúdo de 1 numa caixa de diálogo
3
JButton
cmdClear
limpa o conteúdo de 1
4
JTextField
txtAdd
texto adicionado ao texto em 1 quando validado premindo a tecla Enter.
5
JScrollPane
jScrollPane1
recipiente rolável no qual a caixa de texto 1 foi colocada para criar uma caixa de texto rolável.

O código relevante é o seguinte:

.....

public class cadreAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JButton cmdAfficher = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtTexte = new JTextArea();
  JLabel jLabel2 = new JLabel();
  JTextField txtAjout = new JTextField();
  JButton cmdEffacer = new JButton();

  /**Building the frame*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {

    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    txtAjout.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtAjout_actionPerformed(e);
      }
    });
    cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdEffacer_actionPerformed(e);
      }
    });
    .......
    jScrollPane1.getViewport().add(txtTexte, null);
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
        ........
  }

  void cmdAfficher_actionPerformed(ActionEvent e) {
    // displays the contents of TextArea
    afficher(txtTexte.getText());
  }

    void afficher(String message){
     // displays a message in a box
    JOptionPane.showMessageDialog(this,message,"Suivi",JOptionPane.INFORMATION_MESSAGE);
  }// display

  void cmdEffacer_actionPerformed(ActionEvent e) {
    txtTexte.setText("");
  }//cmdEffacer_actionPerformed

  void txtAjout_actionPerformed(ActionEvent e) {
    // add text
    txtTexte.append(txtAjout.getText());
     // raz addition
    txtAjout.setText("");
  }//
}

5.2.6. Eventos do rato

Ao desenhar num contentor, é importante saber a posição do rato, por exemplo, para exibir um ponto quando clicado. Os movimentos do rato desencadeiam eventos no contentor dentro do qual se move. Aqui estão, por exemplo, os eventos fornecidos pelo JBuilder para um contentor JPanel:

Image

mouseClicked
clique do rato
mouseDragged
o rato está a mover-se, botão esquerdo pressionado
mouseEntered
o rato acabou de entrar na área do contentor
mouseExited
o rato acabou de sair da área do contentor
mouseMoved
o rato está a mover-se
mousePressed
Botão esquerdo do rato pressionado
mouseReleased
Botão esquerdo do rato solto

Aqui está um programa para o ajudar a compreender melhor quando ocorrem os vários eventos do rato:

Image

N.º
tipo
nome
função
1
JTextField
txtPosition
para exibir a posição do rato no contentor (possivelmente MouseMoved)
2
JList
lstDisplay
para exibir eventos do rato que não sejam MouseMoved
3
JButton
cmdClear
para limpar o conteúdo de 2

Quando executar este programa, eis o que obtém ao clicar:

Image

Os eventos são empilhados a partir do topo da lista. Portanto, a captura de ecrã acima mostra que um clique desencadeia três eventos, na seguinte ordem:

  1. MousePressed quando o botão é pressionado
  2. MouseReleased quando o botão é solto
  3. MouseClicked, o que indica que a sequência dos dois eventos anteriores é considerada um clique. Isto pode ser um clique duplo. Mas acima, a informação clickCount=1 indica que se trata de um clique único.

Agora, se clicar no botão, mover o rato e soltar o botão:

Image

Aqui vemos os três eventos:

  1. MousePressed quando o botão é pressionado inicialmente
  2. MouseDragged quando se move o rato com o botão premido
  3. MouseReleased quando se solta o botão

Nos dois exemplos acima, vemos que um evento do rato contém várias informações, incluindo as coordenadas do rato (x, y), por exemplo (408,65) na primeira linha acima.

Se continuarmos desta forma, descobrimos que o evento MouseExited é acionado assim que o rato sai do contentor ou passa por cima de um dos seus componentes. Neste último caso, o contentor recebe o evento MouseExited e o componente recebe o evento MouseEntered. O oposto ocorrerá quando o rato sair do componente para regressar ao contentor.

O que acontece durante um clique duplo?

Image

Recebemos exatamente os mesmos eventos que num clique simples. A única diferença é que o evento contém a informação clickCount=2 (ver acima), indicando que ocorreu efetivamente um duplo clique.

O código relevante para esta aplicação é o seguinte:

public class Cadre1 extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtPosition = new JTextField();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel valeurs=new DefaultListModel();
  JList lstAffichage = new JList(valeurs);
  JButton cmdEffacer = new JButton();

  /**Building the frame*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {

    contentPane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
      public void mouseMoved(MouseEvent e) {
        contentPane_mouseMoved(e);
      }
      public void mouseDragged(MouseEvent e) {
        contentPane_mouseDragged(e);
      }
    });

    contentPane.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseEntered(MouseEvent e) {
        contentPane_mouseEntered(e);
      }
      public void mouseExited(MouseEvent e) {
        contentPane_mouseExited(e);
      }
      public void mousePressed(MouseEvent e) {
        contentPane_mousePressed(e);
      }
      public void mouseClicked(MouseEvent e) {
        contentPane_mouseClicked(e);
      }
      public void mouseReleased(MouseEvent e) {
        contentPane_mouseReleased(e);
      }
    });

    cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdEffacer_actionPerformed(e);
      }
    });

    jScrollPane1.getViewport().add(lstAffichage, null);

...............
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    .........
  }

  void contentPane_mouseMoved(MouseEvent e) {
    txtPosition.setText("("+e.getX()+","+e.getY()+")");
  }

  void contentPane_mouseDragged(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseEntered(MouseEvent e) {
    afficher(e);
  }

  void afficher(MouseEvent e){
     // displays the event in the lstAffichage list
    valeurs.insertElementAt(e,0);
  }

  void contentPane_mouseExited(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mousePressed(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseClicked(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseReleased(MouseEvent e) {
    afficher(e);
  }

  void cmdEffacer_actionPerformed(ActionEvent e) {
     // deletes the list
    valeurs.removeAllElements();
  }
}

5.2.7. Criar uma janela com um menu

Agora vamos ver como criar uma janela com um menu utilizando o JBuilder. Iremos criar a seguinte janela:

Image

Image

Crie um novo projeto a partir de uma janela vazia. Na lista de componentes «Swing Containers», selecione o componente JMenuBar (ver Figura 1 abaixo) e arraste-o para a janela que está a desenhar.

Image

Não aparece nada na janela de design, mas o componente JMenuBar aparece no painel de estrutura da sua janela:

Image

Clique duas vezes no elemento jMenuBar1 acima para aceder ao menu no modo de design:

Image

1
Inserir um item de menu
2
Inserir um separador
3
Inserir um menu aninhado
4
Remover um item do menu
5
Desativar um item de menu
6
Item de menu com caixa de seleção
7
Alternar o botão de opção

Para criar o seu primeiro item de menu, digite «Opções A» na caixa A acima e, em seguida, abaixo, na seguinte ordem: A1, A2, separador, A3, A4.

Image

Em seguida, ao lado:

Image

Utilize a ferramenta 3 para indicar que B3 é um submenu aninhado.

À medida que desenhamos o menu, a estrutura lógica da nossa janela evolui:

Image

Se executarmos a nossa aplicação agora, veremos uma janela vazia sem menu. Precisamos de associar o menu criado à nossa janela. Para tal, na estrutura da janela, selecione o objeto «this»:

Image

Terá então acesso às propriedades deste:

Image

Uma delas é a JMenuBar, que é utilizada para definir o menu que será associado à janela. Clique na célula à direita de JMenuBar. Todos os menus que criou serão então apresentados. Aqui, teremos apenas a jMenuBar1. Selecione-a.

Execute a aplicação (F9):

Image

Agora temos um menu, mas as opções ainda não fazem nada. As opções do menu são tratadas como componentes: têm propriedades e eventos. Na estrutura do menu, selecione a opção jMenuItem1:

Image

Agora tem acesso às suas propriedades e eventos:

Image

Selecione a página de eventos e clique na célula à direita do evento actionPerformed: este é o evento que ocorre quando clica num item do menu. É fornecido um procedimento de tratamento por predefinição. Clique duas vezes nele para aceder ao seu código:

Image

Vamos escrever o seguinte código simples:

  void jMenuItem1_actionPerformed(ActionEvent e) {
    afficher("L'option A1 a été sélectionnée");
  }

  void afficher(String message){
     // displays a message in a box
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//display

Execute a aplicação e selecione a opção A1 para ver a seguinte mensagem:

Image

O código relevante para esta aplicação é o seguinte:

.....

public class Cadre1 extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem jMenuItem1 = new JMenuItem();
  JMenuItem jMenuItem2 = new JMenuItem();
  JMenuItem jMenuItem3 = new JMenuItem();
  JMenuItem jMenuItem4 = new JMenuItem();
  JMenu jMenu2 = new JMenu();
  JMenuItem jMenuItem5 = new JMenuItem();
  JMenuItem jMenuItem6 = new JMenuItem();
  JMenu jMenu3 = new JMenu();
  JMenuItem jMenuItem7 = new JMenuItem();
  JMenuItem jMenuItem8 = new JMenuItem();
  JMenuItem jMenuItem9 = new JMenuItem();

  /**Building the frame*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Initialize component*/
  private void jbInit() throws Exception  {
        // the window is associated with a menu
    this.setJMenuBar(jMenuBar1);

    jMenu1.setText("Options A");
    jMenuItem1.setText("A1");
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jMenuItem1_actionPerformed(e);
      }
    });
    jMenuItem2.setText("A2");
    jMenuItem3.setText("A3");
    jMenuItem4.setText("A4");
    jMenu2.setText("Options B");
    jMenuItem5.setText("B1");
    jMenuItem6.setText("B2");
    jMenu3.setText("B3");
    jMenuItem7.setText("B31");
    jMenuItem8.setText("B32");
    jMenuItem9.setText("B4");
    jMenuBar1.add(jMenu1);
    jMenuBar1.add(jMenu2);
    jMenu1.add(jMenuItem1);
    jMenu1.add(jMenuItem2);
    jMenu1.addSeparator();
    jMenu1.add(jMenuItem3);
    jMenu1.add(jMenuItem4);
    jMenu2.add(jMenuItem5);
    jMenu2.add(jMenuItem6);
    jMenu2.add(jMenu3);
    jMenu2.add(jMenuItem9);
    jMenu3.add(jMenuItem7);
    jMenu3.add(jMenuItem8);
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
....
  }

  void jMenuItem1_actionPerformed(ActionEvent e) {
    afficher("L'option A1 a été sélectionnée");
  }

  void afficher(String message){
     // displays a message in a box
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//display

}

5.3.1. Caixas de mensagem

Já utilizámos a classe JOptionPane para apresentar mensagens. Assim, o código seguinte:

import javax.swing.*;

public class dialog1 {
  public static void main(String arg[]){
    JOptionPane.showMessageDialog(null,"Un message","Titre de la boîte",JOptionPane.INFORMATION_MESSAGE);
  }
}

exibe a seguinte caixa de diálogo:

Image

Quando esta janela é fechada, ela desaparece, mas o segmento de execução em que estava a ser executada não é interrompido. Este fenómeno não ocorre normalmente. As caixas de diálogo são utilizadas dentro de uma aplicação que, em algum momento, utiliza uma instrução System.exit(n) para interromper todos os segmentos. Teremos isto em mente nos exemplos seguintes, todos eles construídos com base no mesmo modelo. No DOS, a aplicação pode ser interrompida com Ctrl-C. Com o JBuilder, utilize a opção Run/Reset Program (Ctrl-F2). Além disso, o primeiro argumento de showMessageDialog é nulo aqui. Normalmente, não é este o caso; é tipicamente isto, onde isto se refere à janela principal da aplicação.

5.3.2. Aparência e Sensação

A aparência da caixa de diálogo acima poderia ser diferente. Pode configurar esta aparência utilizando a classe javax.swing.UIManager. Quando comentámos o código gerado pelo JBuilder para a nossa primeira janela, deparámo-nos com uma instrução na qual não nos detivemos:

      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

O método setLookAndFeel da classe UIManager (UI = Interface do Utilizador) permite definir a aparência das interfaces gráficas. A classe UIManager possui um método que permite determinar as possíveis «aparências» das interfaces:

static UIManager.LookAndFeelInfo[]
getInstalledLookAndFeels()

O método devolve uma matriz de objetos LookAndFeelInfo. Esta classe possui um método:

String
getClassName()

que devolve o nome da classe que «implementa» um determinado look and feel. Vamos experimentar o seguinte programa:

import javax.swing.*;

public class LookAndFeels {
  // displays available looks and feels
  public static void main(String[] args) {
    // iste of installed look and feels
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    // display
    for(int i=0;i<lf.length;i++){
      System.out.println(lf[i].getClassName());
    }//for
  }//hand
}//class

Isso produz os seguintes resultados:

javax.swing.plaf.metal.MetalLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel

Parece, portanto, haver três «aspectos» «diferentes». Vamos revisitar o nosso programa de exibição de mensagens, experimentando os diferentes aspectos possíveis:

import javax.swing.*;

public class LookAndFeel2 {
  // displays available looks and feels
  public static void main(String[] args) {
    // list of installed look and feels
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    // display
    for(int i=0;i<lf.length;i++){
      // appearance manager
      try{
        UIManager.setLookAndFeel(lf[i].getClassName());
      }catch(Exception ex){
        System.err.println(ex.getMessage());
      }//catch
      // message
      JOptionPane.showMessageDialog(null,"Un message",lf[i].getClassName(),JOptionPane.INFORMATION_MESSAGE);
    }//for
  }//hand
}//class

A execução produz as seguintes exibições:

correspondentes, da direita para a esquerda, aos «temas» Metal, Padrão, Windows.

5.3.3. Caixas de confirmação

A classe JOptionPane possui um método showConfirmDialog para exibir caixas de diálogo de confirmação com os botões Sim, Não e Cancelar. Existem várias versões sobrecarregadas do método showConfirmDialog. Vamos examinar uma delas:

static int
showConfirmDialog(Component parentComponent, Object message, String title, int optionType)
parentComponent
o componente pai da caixa de diálogo. Frequentemente, a janela ou o valor null
message
a mensagem a apresentar
título
o título da caixa de diálogo
optionType
JOptionPane.YES_NO_OPTION: botões Sim, Não
JOptionPane.YES_NO_CANCEL_OPTION: Botões Sim, Não, Cancelar

O resultado devolvido pelo método é:

JOptionPane.YES_OPTION
o utilizador clicou em Sim
JOptionPane.NO_OPTION
o utilizador clicou em Não
JOptionPane.CANCEL_OPTION
o utilizador clicou em Cancelar
JOptionPane.CLOSED_OPTION
O utilizador fechou a caixa de diálogo

Eis um exemplo:

import javax.swing.*;

public class confirm1 {
  public static void main(String[] args) {
    // displays confirmation boxes
    int réponse;
    affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_OPTION));
    affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_CANCEL_OPTION));
  }//hand

  private static void affiche(int réponse){
     // indicates the type of response
    switch(réponse){
      case JOptionPane.YES_OPTION :
        System.out.println("Oui");
        break;
      case JOptionPane.NO_OPTION :
        System.out.println("Non");
        break;
      case JOptionPane.CANCEL_OPTION :
        System.out.println("Annuler");
        break;
      case JOptionPane.CLOSED_OPTION :
        System.out.println("Fermeture");
        break;
    }//switch
  }//poster
}//class

No console, são exibidas as mensagens «Não» e «Cancelar».

5.3.4. Caixa de entrada

A classe JOptionPane também permite introduzir dados utilizando o método showInputDialog. Mais uma vez, existem vários métodos sobrecarregados. Apresentamos um deles:

static String
showInputDialog(Component parentComponent, Object message, String title, int messageType)

Os argumentos são os mesmos que já vimos várias vezes anteriormente. O método devolve a cadeia de caracteres digitada pelo utilizador. Aqui está um exemplo:

import javax.swing.*;

public class input1 {
  public static void main(String[] args) {
    // input
    System.out.println("Chaîne saisie ["+
      JOptionPane.showInputDialog(null,"Quel est votre nom","Saisie du nom",JOptionPane.QUESTION_MESSAGE )
      + "]");
  }//hand
}//class

A exibição da caixa de diálogo de entrada:

Image

Saída da consola:

Chaîne saisie [dupont]

5.4. Caixas de seleção

Vamos agora analisar várias caixas de diálogo de seleção de ficheiros predefinidas no Java 2:

JFileChooser
uma caixa de diálogo de seleção de ficheiros para selecionar um ficheiro na árvore de ficheiros
JColorChooser
uma caixa de diálogo de seleção para escolher uma cor

5.4.1. Caixa de diálogo de seleção JFileChooser

Vamos criar a seguinte aplicação:

Image

Os controlos são os seguintes:

N.º
Tipo
nome
função
0
JScrollPane
jScrollPane1
Recipiente rolável para caixa de texto 1
1
O próprio JTextArea dentro do JScrollPane
txtText
texto digitado pelo utilizador ou carregado a partir de um ficheiro
2
JButton
btnSave
guarda o texto de 1 num ficheiro de texto
3
JButton
btnLoad
permite carregar o conteúdo de um ficheiro de texto para 1
4
JButton
btnClear
limpa o conteúdo de 1

É utilizado um controlo não visual: jFileChooser1. Este é selecionado a partir da paleta de contentores Swing do JBuilder:

Image

Colocamos o componente na janela de design, mas fora do formulário. Ele aparece na lista de componentes:

Image

Vamos agora apresentar o código de programa relevante para dar uma visão geral:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;

public class dialogues extends JFrame {
   // frame components
  JPanel contentPane;
  JButton btnSauvegarder = new JButton();
  JButton btnCharger = new JButton();
  JButton btnEffacer = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtTexte = new JTextArea();
  JFileChooser jFileChooser1 = new JFileChooser();

  // file filters
  javax.swing.filechooser.FileFilter filtreTxt = null;

   //Building the frame
  public dialogues() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
       // other initializations
      moreInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

   // moreInit
  private void moreInit(){
     // window construction initializations
     // filter *.txt
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // do we accept f?
        return f.getName().toLowerCase().endsWith(".txt");
      }//accept
      public String getDescription(){
        // filter description
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // we add the filter
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // we also want to filter all files
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // set the start directory of the FileChooser box to the current directory
    jFileChooser1.setCurrentDirectory(new File("."));
  }

   //Initialize component
  private void jbInit() throws Exception  {
.......................
  }
   //Replaced, so we can get out when the window is closed
  protected void processWindowEvent(WindowEvent e) {
......................
    }
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // file selection using a JFileChooser object

     // we set the initial filter
    jFileChooser1.setFileFilter(filtreTxt);
     // the selection box is displayed
    int returnVal = jFileChooser1.showOpenDialog(this);
    // did the user choose anything?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // put the file in the text field
       lireFichier(jFileChooser1.getSelectedFile());
    }//if
  }//btnCharger_actionPerformed

  // lireFichier
  private void lireFichier(File fichier){
     // displays the contents of the text file file in the text field

     // delete the text field
    txtTexte.setText("");

     // some data
    BufferedReader IN=null;
    String ligne=null;
    try{
      // open file in read mode
      IN=new BufferedReader(new FileReader(fichier));
      // read the file line by line
      while((ligne=IN.readLine())!=null){
        txtTexte.append(ligne+"\n");
      }//while
       // close file
      IN.close();
    }catch(Exception ex){
       // an error has occurred
      txtTexte.setText(""+ex);
    }//catch
  }

  // delete
  void btnEffacer_actionPerformed(ActionEvent e) {
    // delete the text box
    txtTexte.setText("");
  }

   // save
  void btnSauvegarder_actionPerformed(ActionEvent e) {
     // saves the contents of the text box to a file

     // we set the initial filter
    jFileChooser1.setFileFilter(filtreTxt);
     // the backup selection box is displayed
    int returnVal = jFileChooser1.showSaveDialog(this);
    // did the user choose anything?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // we write the contents of the text box to file
       écrireFichier(jFileChooser1.getSelectedFile());
    }//if
  }

   // lireFichier
  private void écrireFichier(File fichier){
     // writes the contents of the text box to file

     // some data
    PrintWriter PRN=null;
    try{
       // open file for writing
      PRN=new PrintWriter(new FileWriter(fichier));
      // write the contents of the text box
      PRN.print(txtTexte.getText());
       // close file
      PRN.close();
    }catch(Exception ex){
       // an error has occurred
      txtTexte.setText(""+ex);
    }//catch
  }

Não iremos comentar o código dos métodos btnEffacer_Click, lireFichier e écrireFichier, uma vez que não introduzem nada de novo. Iremos concentrar-nos na classe JFileChooser e na forma de a utilizar. Esta classe é complexa — um pouco «confusa». Aqui, iremos utilizar apenas os seguintes métodos:

addChoosableFilter(FileFilter)
define os tipos de ficheiros disponíveis para seleção
setAcceptAllFileFilterUsed(boolean)
indica se o tipo «Todos os ficheiros» deve ser oferecido para seleção ou não
File getSelectedFile()
o ficheiro (File) selecionado pelo utilizador
int showSaveDialog()
método que exibe a caixa de diálogo de gravação. Retorna um resultado do tipo int. O valor jFileChooser.APPROVE_OPTION indica que o utilizador efetuou uma seleção válida. Caso contrário, o utilizador cancelou a seleção ou ocorreu um erro.
setCurrentDirectory
para definir o diretório inicial a partir do qual o utilizador começará a explorar o sistema de ficheiros
setFileFilter(FileFilter)
para definir o filtro ativo

O método showSaveDialog exibe uma caixa de diálogo de seleção semelhante à seguinte:

Image

1
lista suspensa criada com o método addChoosableFilter. Contém os chamados filtros de seleção, representados pela classe FileFilter. Cabe ao programador definir esses filtros e adicioná-los à lista 1.
2
diretório atual, definido pelo método setCurrentDirectory, caso esse método tenha sido utilizado; caso contrário, o diretório atual será a pasta «Meus Documentos» no Windows ou o diretório home no Unix.
3
Nome do ficheiro selecionado ou digitado diretamente pelo utilizador. Estará disponível através do método getSelectedFile()
4
Botões Guardar/Cancelar. Se o botão Guardar for utilizado, o método showSaveDialog devolve o resultado jFileChooser.APPROVE_OPTION

Como são construídos os filtros de ficheiros na lista suspensa 1? Os filtros são adicionados à lista 1 utilizando o método:

addChoosableFilter(FileFilter)
define os tipos de ficheiro disponíveis para seleção

da classe JFileChooser. Ainda precisamos de compreender a classe FileFilter. Trata-se, na verdade, da classe javax.swing.filechooser.FileFilter, que é uma classe abstrata — ou seja, uma classe que não pode ser instanciada, mas apenas derivada. Está definida da seguinte forma:

FileFilter()
construtor
boolean accept(File)
indica se o ficheiro f corresponde ao filtro ou não
String getDescription()
cadeia de caracteres com a descrição do filtro

Vejamos um exemplo. Queremos que a lista suspensa 1 ofereça um filtro para selecionar ficheiros *.txt com a descrição «Ficheiros de texto (*.txt)».

  • Precisamos de criar uma classe derivada da classe FileFilter
  • Use o método booleano accept(File f) para devolver true se o nome do ficheiro f terminar em .txt
  • Use o método String getDescription() para definir a descrição como "Ficheiros de texto (*.txt)"

Este filtro poderia ser definido na nossa aplicação da seguinte forma:

  javax.swing.filechooser.FileFilter filtreTxt = new javax.swing.filechooser.FileFilter(){
    public boolean accept(File f){
      // do we accept f?
      return f.getName().toLowerCase().endsWith(".txt");
    }//accept
    public String getDescription(){
      // filter description
      return "Fichiers Texte (*.txt)";
    }//getDescription
  };

Este filtro seria adicionado à lista de filtros do objeto jFileChooser1 utilizando a seguinte instrução:

    // on ajoute le filtre *.txt
    jFileChooser1.addChoosableFileFilter(filtretxt);

Tudo isto e algumas outras inicializações são realizadas no método moreInit, que é executado quando a janela é criada (ver o programa completo acima). O código para o botão Guardar é o seguinte:

  void btnSauvegarder_actionPerformed(ActionEvent e) {
    // saves the contents of the text box to a file

     // we set the initial filter
    jFileChooser1.setFileFilter(filtreTxt);
     // the backup selection box is displayed
    int returnVal = jFileChooser1.showSaveDialog(this);
    // did the user choose anything?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // we write the contents of the text box to file
       écrireFichier(jFileChooser1.getSelectedFile());
    }//if
  }

A sequência de operações é a seguinte:

  • Definimos o filtro ativo como *.txt para permitir que o utilizador procure principalmente este tipo de ficheiro. O filtro «Todos os ficheiros» também está presente. Foi adicionado no procedimento moreInit. Portanto, temos dois filtros.
  • A caixa de diálogo de seleção de ficheiros é apresentada. Aqui, o controlo é passado para o utilizador, que utiliza a caixa de diálogo para selecionar um ficheiro do sistema de ficheiros.
  • Quando o utilizador sai da caixa de seleção, verificamos o valor de retorno para ver se devemos ou não guardar a caixa de texto. Se for o caso, ela deve ser guardada no ficheiro obtido através do método getSelectedFile.

O código associado ao botão «Carregar» é muito semelhante ao código do botão «Guardar».

  void btnCharger_actionPerformed(ActionEvent e) {
    // file selection using a JFileChooser object

     // we set the initial filter
    jFileChooser1.setFileFilter(filtreTxt);
     // the selection box is displayed
    int returnVal = jFileChooser1.showOpenDialog(this);
    // did the user choose anything?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // put the file in the text field
       lireFichier(jFileChooser1.getSelectedFile());
    }//if
  }//btnCharger_actionPerformed

Existem duas diferenças:

  • Para exibir a caixa de diálogo de seleção de ficheiros, utilizamos o método showOpenDialog em vez do método showSaveDialog. A caixa de diálogo exibida é semelhante à exibida pelo método showSaveDialog.
  • Se o utilizador tiver selecionado um ficheiro com sucesso, chamamos o método readFile em vez do método writeFile.

5.4.1.1. Caixas de diálogo de seleção JColorChooser e JFontChooser

Continuamos o exemplo anterior adicionando dois novos botões:

Image

Não
tipo
nome
função
6
JButton
btnColor
para definir a cor do texto da caixa de texto
7
JButton
btnFont
para definir o tipo de letra da caixa de texto

O componente JColorChooser, que exibe uma caixa de diálogo de seleção de cores, pode ser encontrado na lista de componentes Swing no JBuilder:

Image

Colocamos este componente na janela de design, mas fora do formulário. Não é visível no formulário, mas está, no entanto, presente na lista de componentes da janela:

Image

A classe JColorChooser é muito simples. Exibimos a caixa de diálogo de seleção de cor utilizando o método int showDialog:

static Color
showDialog(Component component, String title, Color initialColor)
Component component
o componente pai do seletor de cores, normalmente uma janela JFrame
String título
o título na barra de título da caixa de seleção
Cor intialColor
A cor inicialmente selecionada no seletor de cores

Se o utilizador selecionar uma cor, o método devolve uma cor; caso contrário, devolve null. O código associado ao botão Cor é o seguinte:

  void btnCouleur_actionPerformed(ActionEvent e) {
     // choice of text color using JColorChooser component
    Color couleur;
    if((couleur=jColorChooser1.showDialog(this,"Choix d'une couleur",Color.BLACK))!=null){
       // set the color of the characters in the text box
      txtTexte.setForeground(couleur);
    }//if
  }

A classe Color está definida em java.awt.Color. Nessa classe estão definidas várias constantes, incluindo Color.BLACK para a cor preta. A caixa de diálogo de seleção apresentada é a seguinte

Image

Curiosamente, a biblioteca Swing não fornece uma classe para selecionar um tipo de letra. Felizmente, existem recursos Java disponíveis online. Ao pesquisar a palavra-chave «JFontChooser», que parece ser um nome provável para tal classe, encontramos várias opções. O exemplo seguinte dar-nos-á a oportunidade de configurar o JBuilder para utilizar pacotes não incluídos na sua configuração inicial.

O pacote recuperado chama-se swingextras.jar e foi colocado na pasta <jdk>\jre\lib\perso, onde <jdk> se refere ao diretório de instalação do JDK utilizado pelo JBuilder. Poderia ter sido colocado em qualquer outro local.

Vejamos o conteúdo do pacote SwingExtras.jar:

Image

Contém o código-fonte Java dos componentes incluídos no pacote. Contém também as próprias classes:

Image

Neste arquivo, repare que a classe JFontChooser se chama, na verdade, com.lamatek.swingextras.JFontChooser. Se não quiser escrever o nome completo, terá de incluir o seguinte no início do seu programa:

import com.lamatek.swingextras.*;

Como é que o compilador e a Máquina Virtual Java irão encontrar este novo pacote? No caso da utilização direta do JDK, isto já foi explicado, e o leitor pode encontrar os detalhes na secção sobre pacotes Java. Aqui, detalhamos o método a utilizar com o JBuilder. Os pacotes são configurados no menu Options/Configure JDKs:

Image

1
O botão Editar (1) permite indicar ao JBuilder qual o JDK a utilizar. Neste exemplo, o JBuilder veio incluído com o JDK 1.3.1. Quando o JDK 1.4 foi lançado, foi instalado separadamente do JBuilder, e utilizámos o botão Editar para indicar ao JBuilder que utilizasse o JDK 1.4 a partir de agora, especificando o seu diretório de instalação
2
Diretório base do JDK atualmente utilizado pelo JBuilder
3
Lista de arquivos Java (.jar) utilizados pelo JBuilder. Pode adicionar mais utilizando o botão Adicionar (4)
4
O botão Adicionar (4) permite-lhe adicionar novos pacotes que o JBuilder utilizará tanto para compilar como para executar programas. Utilizámo-lo aqui para adicionar o pacote SwingExtras.jar (5)

Agora o JBuilder está devidamente configurado para utilizar a classe JFontChooser. No entanto, precisaríamos de aceder à definição desta classe para a utilizar corretamente. O arquivo swingextras.jar contém ficheiros HTML que poderiam ser extraídos para utilização. Isto é desnecessário. A documentação Java incluída nos ficheiros .jar é diretamente acessível a partir do JBuilder. Para tal, configure o separador Documentação (6) acima. Aparece a seguinte janela nova:

Image

O botão Adicionar permite-nos especificar que o ficheiro SwingExtras.jar deve ser analisado para obter documentação. Depois de feito isto, podemos ver que temos, de facto, acesso à documentação do SwingExtras.jar. Isto proporciona várias vantagens:

  • se começar a digitar a instrução import
import com.lamatek.swingextras.*;

verá que o JBuilder fornece ajuda:

Image

O pacote com.lamatek foi encontrado com sucesso.

  • Agora, no programa seguinte:
import com.lamatek.swingextras.*;

public class test{
  JFontChooser jFontChooser1=null;
}  

Se premir F1 na palavra-chave JFontChooser, verá a ajuda para esta classe:

Image

Podemos ver na barra de estado 1 que está, de facto, a ser utilizado um ficheiro HTML do pacote swingextras.jar. O exemplo apresentado acima é suficientemente claro para nos permitir escrever o código para o botão «Font» na nossa aplicação:

  void btnPolice_actionPerformed(ActionEvent e) {
    // choice of text font using JFontChooser component
    jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
    if (jFontChooser1.showDialog(this, "Choix d'une police") == JFontChooser.ACCEPT_OPTION) {
      // change the font in the text box
      txtTexte.setFont(jFontChooser1.getSelectedFont());
    }//if
  }

A caixa de diálogo de seleção apresentada pelo método showDialog acima é a seguinte:

Image

5.5. A aplicação gráfica de cálculo de impostos

Voltamos à aplicação IMPOTS, que já abordámos duas vezes. Vamos agora adicionar-lhe uma interface gráfica de utilizador:

Image

Os controlos são os seguintes

N.º
tipo
nome
função
1
JRadioButton
rdYes
marcado se casado
2
JRadioButton
rdNo
Marcado se não for casado
3
JSpinner
spinChildren
número de filhos do contribuinte
Mínimo=0, Máximo=20, Incremento=1
4
JTextField
txtSalário
salário anual do contribuinte em F
5
JLabel
lblTaxes
montante do imposto devido
6
JTextField
txtStatus
campo de mensagem de estado - não editável

O menu é o seguinte:

opção principal
opção secundária
nome
função
Impostos
   
 
Inicializar
mnuInitialize
carrega os dados necessários para o cálculo a partir de um ficheiro de texto
 
Calcular
mnuCalculate
calcula o imposto devido quando todos os dados necessários estão presentes e corretos
 
Limpar
mnuLimpar
redefine o formulário para o seu estado inicial
 
Sair
mnuExit
fecha a aplicação

Regras de funcionamento

  • O menu «Calcular» permanece desativado enquanto o campo do salário estiver vazio
  • Se, quando o cálculo for executado, o salário estiver incorreto, é apresentada uma mensagem de erro:

Image

O programa é apresentado abaixo. Utiliza a classe *impots* criada no capítulo sobre classes. Parte do código gerado automaticamente pelo JBuilder não foi reproduzido aqui.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.util.*;
import javax.swing.event.*;

public class frmImpots extends JFrame {
  // window components
  JPanel contentPane;
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem mnuInitialiser = new JMenuItem();
  JMenuItem mnuCalculer = new JMenuItem();
  JMenuItem mnuEffacer = new JMenuItem();
  JMenuItem mnuQuitter = new JMenuItem();
  JLabel jLabel1 = new JLabel();
  JFileChooser jFileChooser1 = new JFileChooser();
  JTextField txtStatus = new JTextField();
  JRadioButton rdOui = new JRadioButton();
  JRadioButton rdNon = new JRadioButton();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSalaire = new JTextField();
  JLabel jLabel4 = new JLabel();
  JLabel jLabel5 = new JLabel();
  JLabel lblImpots = new JLabel();
  JLabel jLabel7 = new JLabel();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JSpinner spinEnfants=null;
  FileFilter filtreTxt=null;

   // class attributes
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;

   //Building the frame
  public frmImpots() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // other initializations
    moreInit();
  }

   // form initialization
  private void moreInit(){
     // calculate menu disabled
    mnuCalculer.setEnabled(false);
    // inhibited input zones
    txtSalaire.setEditable(false);
    txtSalaire.setBackground(Color.WHITE);
    // status field
    txtStatus.setBackground(Color.WHITE);
    // spinner Children - between 0 and 20 children
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);
     // filter *.txt for selection box
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // do we accept f?
        return f.getName().toLowerCase().endsWith(".txt");
      }//accept
      public String getDescription(){
        // filter description
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // add the *.txt filter
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // we also want to filter all files
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // set the box's start directory FileChooser
    jFileChooser1.setCurrentDirectory(new File("."));
  }//moreInit

   //Initialize component
  private void jbInit() throws Exception  {

................

  }

   //Replaced, so we can get out when the window is closed
  protected void processWindowEvent(WindowEvent e) {
.....................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // quit the application
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // load the data file
     // selected with the JFileChooser1 selection box
    jFileChooser1.setFileFilter(filtreTxt);
    if (jFileChooser1.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION)
      return;
     // process the selected file
    try{
       // dATA READING
      lireFichier(jFileChooser1.getSelectedFile());
       // create impots object
      objImpots=new impots(limites,coeffr,coeffn);
       // confirmation
      txtStatus.setText("Données chargées");
       // salary can be modified
      txtSalaire.setEditable(true);
       // no more chgt possible
      mnuInitialiser.setEnabled(false);
    }catch(Exception ex){
       // problem
      txtStatus.setText("Erreur : " + ex.getMessage());
      // end
      return;
    }//catch
  }

  private void lireFichier(File fichier) throws Exception {
     // data tables
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // open file in read mode
    BufferedReader IN=new BufferedReader(new FileReader(fichier));
    // read the file line by line
     // they are of the limit form coeffr coeffn
    String ligne=null;
    int numLigne=0;           // line number courannte
    while((ligne=IN.readLine())!=null){
      // one more line
      numLigne++;
       // break down the line into fields
      champs=ligne.split("\\s+");
       // 3 fields?
      if(champs.length!=3)
        throw new Exception("ligne " + numLigne + "erronée dans fichier des données");
       // we retrieve the three fields
       aLimites.add(champs[0]);
       aCoeffR.add(champs[1]);
       aCoeffN.add(champs[2]);
    }//while
     // close file
    IN.close();
     // data transfer to bounded arrays
    int n=aLimites.size();
    limites=new double[n];
    coeffr=new double[n];
    coeffn=new double[n];
    for(int i=0;i<n;i++){
      limites[i]=Double.parseDouble((String)aLimites.get(i));
      coeffr[i]=Double.parseDouble((String)aCoeffR.get(i));
      coeffn[i]=Double.parseDouble((String)aCoeffN.get(i));
    }//for
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    // tAX CALCULATION
     // salary verification
    int salaire=0;
    try{
      salaire=Integer.parseInt(txtSalaire.getText().trim());
      if(salaire<0) throw new Exception();
    }catch (Exception ex){
       // error msg
      txtStatus.setText("Salaire incorrect. Recommencez");
       // focus on wrong field
      txtSalaire.requestFocus();
       // back to interface
      return;
    }
     // no. of children
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     // tAX CALCULATION
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),InbEnfants.intValue(),salaire));
     // delete status msg
    txtStatus.setText("");
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
     // the salary has changed - update the calculate menu
    mnuCalculer.setEnabled(! txtSalaire.getText().trim().equals(""));
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
    // raz du formulaire
    rdNon.setSelected(true);
    spinEnfants.getModel().setValue(new Integer(0));
    txtSalaire.setText("");
    mnuCalculer.setEnabled(false);
    lblImpots.setText("");
  }
}

Aqui utilizámos um componente disponível apenas a partir do JDK 1.4, o JSpinner. Trata-se de um spinner, que, neste caso, permite ao utilizador definir o número de filhos. Este componente Swing não estava disponível na barra de componentes Swing do JBuilder 6 utilizado para testes. Isto não impede a sua utilização, mesmo que as coisas sejam um pouco mais complicadas do que para os componentes disponíveis na barra de componentes. Na verdade, não é possível arrastar o componente JSpinner para o formulário durante a fase de design. Deve fazê-lo em tempo de execução. Vejamos o código que faz isso:

     // spinner Children - between 0 and 20 children
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);

A primeira linha cria o componente JSpinner. Este componente pode ser utilizado para vários fins, não apenas como um spinner de inteiros, como aqui. O argumento do construtor JSpinner é um modelo de spinner numérico que aceita quatro parâmetros (valor, mínimo, máximo, incremento). O componente tem a seguinte forma:

Image

valor
valor inicial exibido no componente
min
valor mínimo que pode ser exibido no componente
máx
valor máximo que pode ser exibido no componente
incremento
valor de incremento do valor exibido ao utilizar as setas para cima/para baixo do componente

O valor do componente é obtido através do seu método getValue, que devolve um tipo Object. Por isso, é necessária alguma conversão de tipos para obter o inteiro de que precisamos:

    // nbre d'enfants
    Integer InbEnfants=(Integer)spinEnfants.getValue();
    // calcul de l'impôt
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),
      InbEnfants.intValue(),salaire));

Depois de definido o componente JSpinner, este é colocado na janela:

    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);

Em primeiro lugar, o utilizador deve utilizar a opção de menu Initialize, que cria um objeto tax utilizando o construtor

    public impots(double[] LIMITES, double[] COEFFR, double[] COEFFN) throws Exception

da classe impots. Recorde-se que isto foi definido como um exemplo no capítulo sobre classes. Consulte esse capítulo, se necessário. As três matrizes exigidas pelo construtor são preenchidas a partir do conteúdo de um ficheiro de texto com o seguinte formato:

12620.0
0
0
13190
0,05
631
15 640
0,1
1.290,5
24.740
0,15
2.072,5
31 810
0,2
3.309,5
39 970
0,25
4.900
48 360
0,3
6.898,5
55 790
0,35
9.316,5
92 970
0,4
12 106
127 860
0,45
16 754,5
151 250
0,50
23 147,5
172 040
0,55
30 710
195 000
0,60
39 312
0
0,65
49062

Cada linha contém três números separados por pelo menos um espaço. Este ficheiro de texto é selecionado pelo utilizador através de um componente JFileChooser. Depois de criado o objeto *impots*, basta deixar o utilizador introduzir as três informações necessárias: casado ou não, número de filhos, salário anual, e chamar o método calculate da classe impots. A operação pode ser repetida várias vezes. O próprio objeto *impots* é criado apenas uma vez, quando a opção *Initialize* é utilizada.

5.6. Escrever applets

5.6.1. Introdução

Depois de escrever uma aplicação com uma interface gráfica de utilizador, é bastante fácil convertê-la num applet. Armazenada na máquina A, pode ser descarregada através de um navegador web a partir da máquina B pela Internet. A aplicação original é, assim, partilhada entre muitos utilizadores, e esta é a principal vantagem de converter uma aplicação num applet. No entanto, nem todas as aplicações podem ser convertidas desta forma: para evitar causar problemas ao utilizador que executa um applet no seu navegador, o ambiente do applet é restrito:

  • um applet não pode ler nem escrever no disco do utilizador
  • só pode comunicar com a máquina a partir da qual foi descarregado pelo navegador.

Estas são restrições significativas. Implicam, por exemplo, que uma aplicação que necessite de ler informações de um ficheiro ou de uma base de dados deve solicitá-las através de uma aplicação de retransmissão localizada no servidor a partir do qual foi descarregada.

A estrutura geral de uma aplicação web simples é a seguinte:

Image

  • o cliente solicita um documento HTML ao servidor web, normalmente utilizando um navegador. Este documento pode conter um applet que funcionará como uma aplicação gráfica autónoma dentro do documento HTML apresentado pelo navegador do cliente.
  • Este applet pode ter acesso a dados, mas apenas aos dados localizados no servidor web. Não terá acesso aos recursos da máquina do cliente que o está a executar, nem aos de outras máquinas na rede que não aquela a partir da qual foi descarregado.

5.6.2. A classe JApplet

5.6.2.1. Definição

Uma aplicação pode ser carregada por um navegador da Web se for uma instância da classe java.applet.Applet ou da classe javax.swing.JApplet. Esta última deriva da primeira, que por sua vez deriva da classe Panel, a qual, por sua vez, deriva da classe Container. Uma vez que uma instância de Applet ou JApplet é do tipo Container, pode, portanto, conter componentes (Component) tais como botões, caixas de seleção, listas, etc. Aqui estão algumas notas sobre a função dos diferentes métodos:

Método
Função
public void destroy();
Destrói a instância do Applet
public AppletContext getAppletContext();
Recupera o contexto de execução do applet (o documento HTML no qual se encontra, outros applets no mesmo documento, etc.)
public String getAppletInfo();
retorna uma string contendo informações sobre o applet
public AudioClip getAudioClip(URL url);
carrega o ficheiro de áudio especificado pela URL
public AudioClip getAudioClip(URL url, String name);
carrega o ficheiro de áudio especificado pela URL/nome
public URL getCodeBase();
retorna a URL do applet
public URL getDocumentBase();
retorna a URL do documento HTML que contém o applet
public Image getImage(URL url);
recupera a imagem especificada pela URL
public Image getImage(URL url, String name);
recupera a imagem especificada pela URL/nome
public String getParameter(String name);
recupera o valor do parâmetro "name" contido na tag <applet> do documento HTML que contém o applet.
public void init();
Este método é chamado pelo navegador quando o applet é iniciado pela primeira vez
public boolean isActive();
estado do applet
public void play(URL url);
Reproduz o ficheiro de som especificado pela URL
public void play(URL url, String name);
Reproduz o ficheiro de som especificado pela URL/nome
public void resize(Dimension d);
define o tamanho do quadro do applet
public void resize(int width, int height);
o mesmo
public final void setStub(AppletStub stub);
 
public void showStatus(String msg);
exibe uma mensagem na barra de estado do applet
public void start();
este método é chamado pelo navegador sempre que o documento que contém o applet é exibido
public void stop();
este método é chamado pelo navegador sempre que o documento que contém o applet é abandonado em favor de outro (o utilizador altera o URL)

A classe JApplet introduziu várias melhorias na classe Applet, nomeadamente a capacidade de conter componentes JMenuBar (ou seja, menus), o que não era possível com a classe Applet.

5.6.2.2. Executar um applet: os métodos init, start e stop

Quando um navegador carrega um applet, chama três dos seus métodos:

init
Este método é chamado quando o applet é carregado inicialmente. Deve, portanto, conter as inicializações necessárias para a aplicação.
start
Este método é chamado sempre que o documento que contém o applet se torna o documento atual do navegador. Assim, quando um utilizador carrega um applet, os métodos init e start serão executados nessa ordem. Quando o utilizador sai do documento para visualizar outro, o método stop será executado. Quando o utilizador regressar a ele mais tarde, o método start será executado.
stop
Este método é chamado sempre que o utilizador sai do documento que contém o applet.

Para muitos applets, apenas o método init é necessário. Os métodos start e stop só são necessários se a aplicação iniciar tarefas (threads) que correm em paralelo e continuamente, muitas vezes sem o conhecimento do utilizador. Quando o utilizador sai do documento, a parte visível da aplicação desaparece, mas estas tarefas em segundo plano continuam a correr. Isto é muitas vezes desnecessário. Aproveitamos então a chamada do navegador ao método stop para as parar. Se o utilizador regressar ao documento, aproveitamos a chamada do navegador ao método start para as reiniciar.

Tomemos, por exemplo, um applet que tem um relógio na sua interface gráfica. Este relógio é mantido por uma tarefa em segundo plano (thread). Quando o utilizador sai da página do applet no navegador, não faz sentido manter o relógio a funcionar, uma vez que este se tornou invisível: no método stop do applet, iremos parar a thread que gere o relógio. No método start, reiniciamo-lo para que, quando o utilizador regressar à página do applet, encontre um relógio atualizado.

5.6.3. Converter uma aplicação gráfica num applet

Partimos do princípio de que esta conversão é possível, o que significa que cumpre as restrições de execução para applets. Uma aplicação é iniciada pelo método *main* de uma das suas classes:


public class application{
    
    public static main void(String arg[]){
        
    }
    
}// end of class

Uma aplicação deste tipo é convertida num applet da seguinte forma:

import java.applet.JApplet;

public class application extends JApplet{
    
    public void init(){
        
    }
    
}// end of class

Tenha em atenção os seguintes pontos:

  1. A classe Application agora deriva da classe JApplet
  2. o método main foi substituído pelo método init.

A título de exemplo, vamos revisitar uma aplicação que já estudámos: a gestão de listas.

Image

Os componentes desta janela são os seguintes:

N.º
Tipo
nome
função
1
JTextField
txtInput
campo de entrada
2
JList
jList1
lista contida num contentor jScrollPane1
3
JList
jList2
lista contida num contentor jScrollPane2
4
JButton
cmd1To2
transfere os itens selecionados da lista 1 para a lista 2
5
JButton
cmd2To1
faz o contrário
6
JButton
cmdRaz1
limpa a lista 1
7
JButton
cmdRaz2
limpar lista 2

A estrutura da aplicação era a seguinte:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Building the frame*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Initialize component*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // Jlist1 is placed in the jScrollPane1 container
    jScrollPane1.getViewport().add(jList1, null);
        // Jlist2 is placed in the jScrollPane2 container
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**Replaced, so we can get out when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//class
  void cmd1To2_actionPerformed(ActionEvent e) {
..........
  }//transfer
  void cmdRaz1_actionPerformed(ActionEvent e) {
    // empty list 1
    v1.removeAllElements();
  }//cmd Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // empty list 2
    v2.removeAllElements();
  }///cmd Raz2

Para converter a classe da aplicação num applet, proceda da seguinte forma:

  • modifique a classe interfaceAppli anterior para que esta deixe de herdar de JFrame e passe a herdar de JApplet:
public class interfaceAppli extends JApplet {
  • Remova a instrução que define o título da janela JFrame. Um JApplet não possui uma barra de título
    // this.setTitle("JList");
  • Altere o construtor para um método init e, dentro deste método, remova o tratamento de eventos da janela (WindowListener, ...). Um applet é um contentor que não pode ser redimensionado nem fechado.
   /**Building the frame*/
  public init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli
  • O método processWindowEvent deve ser removido ou comentado
   /**Replaced, so we can get out when the window is closed*/
  //protected void processWindowEvent(WindowEvent e) {
  //  super.processWindowEvent(e);
  //  if (e.getID() == WindowEvent.WINDOW_CLOSING) {
  //    System.exit(0);
  //  }
  // }

Aqui está o código completo do applet, excluindo a parte gerada automaticamente pelo JBuilder

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceAppli extends JApplet {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Building the frame*/
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Initialize component*/
  private void jbInit() throws Exception  {
    //setIconImage(Toolkit.getDefaultToolkit().createImage(interfaceAppli.class.getResource("[Votre icône]")));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(400, 308));
    // this.setTitle("JList");
    jScrollPane1.setBounds(new Rectangle(37, 133, 124, 101));
    jScrollPane2.setBounds(new Rectangle(232, 132, 124, 101));
.............
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     // the input text has been validated
     // we recover it free of its start and end spaces
    String texte=txtSaisie.getText().trim();
     // if it's empty, we don't want it
    if(texte.equals("")){
      // error msg
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // end
      return;
    }//if
    // if it is not empty, it is added to the values in list 1
    v1.addElement(texte);
     // and empty the input field
    txtSaisie.setText("");
  }

  void cmd1To2_actionPerformed(ActionEvent e) {
    // transfer items selected in list 1 to list 2
    transfert(jList1,jList2);
  }//cmd1To2

  private void transfert(JList L1, JList L2){
      // transfer items selected in list 1 to list 2
       // retrieve the array of indices of the elements selected in L1
      int[] indices=L1.getSelectedIndices();
      // anything to do?
      if (indices.length==0) return;
      // we retrieve the values of L1
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      // and L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // the values selected in L1 are added to L2
        v2.addElement(v1.elementAt(indices[i]));
        // l1 elements copied into L2 must be deleted from L1
        v1.removeElementAt(indices[i]);
      }//for
  }//transfer

  private void affiche(String message){
    // poster message
      JOptionPane.showMessageDialog(this,message,
        "Suivi",JOptionPane.INFORMATION_MESSAGE);
  }// poster

  void cmd2To1_actionPerformed(ActionEvent e) {
    // transfer selected items in jList2 to jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // empty list 1
    v1.removeAllElements();
  }//cmd Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // empty list 2
    v2.removeAllElements();
  }//cmd Raz2

}//class

Pode compilar o código-fonte deste applet. Aqui, fazemo-lo utilizando o JDK, sem o JBuilder.

E:\data\serge\Jbuilder\interfaces\JApplets\1>javac.bat interfaceAppli.java

E:\data\serge\Jbuilder\interfaces\JApplets\1>dir
12/06/2002  16:40                6 148 interfaceAppli.java
12/06/2002  16:41                  527 interfaceAppli$1.class
12/06/2002  16:41                  525 interfaceAppli$2.class
12/06/2002  16:41                  525 interfaceAppli$3.class
12/06/2002  16:41                  525 interfaceAppli$4.class
12/06/2002  16:41                  525 interfaceAppli$5.class
12/06/2002  16:41                4 759 interfaceAppli.class

A aplicação pode ser testada utilizando o programa AppletViewer do JDK, que permite executar applets, ou um navegador web. Para tal, deve criar o documento HTML appli.htm, que irá conter o applet:

<html>
    <head>
        <title>listes swing</title>
    </head>
    <body>
        <applet 
        code="interfaceAppli.class"
      width="400"
      height="300">
        </applet>
    </body>
</html>

Este é um documento HTML padrão, exceto pela presença da tag applet. Foi utilizado com três parâmetros:

code="interfaceAppli.class"
nome da classe Java compilada a carregar para executar o applet
width="400"
largura do quadro do applet no documento
height="300"
altura do quadro do applet no documento

Depois de criado o ficheiro appli.htm, este pode ser carregado utilizando o programa appletviewer do JDK ou um navegador da Web. Numa janela do DOS, digite o seguinte comando na pasta que contém o ficheiro appli.htm:

**appletviewer appli.htm**

Partimos do princípio de que o diretório que contém o executável appletviewer.exe está no PATH da janela do DOS; caso contrário, seria necessário especificar o caminho completo para o executável appletviewer.exe. Aparece a seguinte janela:

Image

Interrompa a execução do applet utilizando a opção Applet/Quit. Agora, vamos testar o applet utilizando um navegador. O navegador deve utilizar uma Máquina Virtual Java 2 para apresentar componentes Swing. Até recentemente (2001), este requisito representava um problema, porque a Sun lançava JDKs que os fornecedores de navegadores demoravam a adotar. Por fim, a Sun resolveu esta questão fornecendo aos utilizadores uma aplicação chamada «plug-in Java», que permite ao Internet Explorer e ao Netscape Navigator utilizar os JREs mais recentes produzidos pela Sun (JRE = Java Runtime Environment). Os testes seguintes foram realizados utilizando o IE 5.5 com o plug-in Java 1.4.

Uma forma de testar o applet interfaceAppli.class é carregar o ficheiro HTML appli.htm diretamente no navegador, clicando duas vezes nele. O navegador exibe então a página HTML e o seu applet sem a ajuda de um servidor web:

Image

Como se pode ver pela URL (1), o ficheiro foi carregado diretamente no navegador. No exemplo seguinte, o ficheiro appli.htm foi solicitado a um servidor web Apache a funcionar na porta 81 da máquina local:

Image

5.6.4. A tag <applet> num documento HTML

Vimos que, dentro de um documento HTML, o applet é referenciado pela tag <applet>. Esta tag pode ter vários atributos:

<applet
    code=
    width=
    height=
    codebase=
    align=
    hspace=
    vspace=
alt=
>
    <param name1=nom1 value=val1>
    <param name2=nom2 value=val2>
    texte
>
</applet>

O significado dos parâmetros é o seguinte:

Parâmetro
Significado
código
obrigatório - nome do ficheiro .class a executar
largura
obrigatório - largura do applet no documento
altura
obrigatório - altura …
codebase
opcional - URL do diretório que contém o applet a ser executado. Se codebase não for especificado, o applet será procurado no diretório do documento HTML que o referencia
align
opcional - posicionamento (LEFT, RIGHT, CENTER) do applet dentro do documento
hspace
opcional - margem horizontal em torno do applet, expressa em pixels
vspace
opcional - margem vertical em torno do applet, expressa em pixels
alt
opcional - texto exibido no lugar do applet se o navegador não conseguir carregá-lo
param
opcional - parâmetro passado para o applet, especificando o seu nome (name) e valor (value). O applet pode recuperar o valor do parâmetro name1 utilizando val1=getParameter("name1")
Pode utilizar quantos parâmetros desejar
texto
opcional - será exibido por qualquer navegador incapaz de executar um applet, por exemplo, porque não possui uma Máquina Virtual Java.

Vamos ver um exemplo para ilustrar a passagem de parâmetros para um applet:

<html>
    <head>
        <title>paramètres applet</title>
    </head>
    <body>
        <applet code="interfaceParams.class" width="400" height="300">
      <param name="param1" value="val1">
      <param name="param2" value="val2">      
        </applet>
    </body>
</html>

O código Java para o applet interfaceParams foi gerado conforme descrito anteriormente. Criámos uma aplicação JBuilder e, em seguida, efetuámos as poucas alterações mencionadas acima:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceParams extends JApplet {
  JPanel contentPane;
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel1 = new JLabel();
  DefaultListModel params=new DefaultListModel();
  JList lstParams = new JList(params);

  //Building the frame
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // other initializations
    moreInit();
  }

   // initializations
  public void moreInit(){
     // displays applet parameter values
    params.addElement("nom=param1 valeur="+getParameter("param1"));
    params.addElement("nom=param2 valeur="+getParameter("param2"));
  }//more Init

   //Initialize component
  private void jbInit() throws Exception  {
............
    this.setSize(new Dimension(205, 156));
    //this.setTitle("Applet parameters");
    jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
 }
}

Executando com o AppletViewer:

Image

5.6.5. Aceder a recursos remotos a partir de um applet

Muitas aplicações precisam de aceder a informações armazenadas em ficheiros ou bases de dados. Já referimos que um applet não tem acesso aos recursos da máquina na qual é executado. Trata-se de uma precaução de senso comum. Caso contrário, seria possível escrever um applet para «espiar» o disco rígido de quem o carregasse. O applet tem, no entanto, acesso aos recursos do servidor a partir do qual foi descarregado, tais como ficheiros. É isso que vamos ver agora.

5.6.5.1. A Classe URL

Qualquer aplicação Java pode ler um ficheiro localizado numa máquina na rede utilizando a classe java.net.URL (URL = Uniform Resource Locator). Um URL identifica um recurso de rede, a máquina na qual se encontra, bem como o protocolo e a porta de comunicação a utilizar para o recuperar, na forma:

protocolo:porta//máquina/ficheiro

Assim, o URL http://www.ibm.com/index.html refere-se ao ficheiro index.html na máquina www.ibm.com. É acessível através do protocolo HTTP. A porta não é especificada: o navegador utilizará a porta 80, que é a porta predefinida para o serviço HTTP.

Vamos analisar mais detalhadamente alguns dos elementos da classe URL:

public URL(String spec)
cria uma instância de URL a partir de uma cadeia de caracteres no formato "protocolo:porta//máquina/ficheiro" - lança uma exceção se a sintaxe da cadeia de caracteres não corresponder a uma URL
  
public String getFile()
recupera o campo do ficheiro da string "protocolo:porta//máquina/ficheiro" na URL
  
public String getHost()
recupera o campo "machine" da parte "protocol:port//machine/file" da URL
  
public String getPort()
recupera o campo «port» da cadeia de caracteres da URL «protocol:port//machine/file»
  
public String getProtocol()
recupera o campo do protocolo da cadeia de caracteres da URL "protocolo:porta//máquina/ficheiro"
  
public URLConnection openConnection()
abre uma ligação à máquina remota getHost() na sua porta getPort() utilizando o protocolo getProtocol() para ler o ficheiro getFile(). Lança uma exceção se a ligação não puder ser aberta
  
public final InputStream openStream()
Atalho para openConnection().getInputStream(). Recupera um fluxo de entrada a partir do qual o conteúdo do ficheiro getFile() pode ser lido. Lança uma exceção se o fluxo não puder ser obtido
  
public String toString()
Exibe a identidade da instância da URL

Existem aqui dois métodos que nos interessam:

  • public URL(String spec) para especificar o ficheiro a ser processado
  • public final InputStream openStream() para o processar

5.6.5.2. Um exemplo: um console-

Vamos escrever um programa Java, sem interface gráfica, concebido para exibir no ecrã o conteúdo de um URL que lhe seja passado como parâmetro. Um exemplo de chamada poderia ser o seguinte:

    DOS> java urlcontenu http://istia.univ-angers.fr/index.html

O programa é relativamente simples:


import java.net.*;             // for the URL class
import java.io.*;                // for streams
 
public class urlcontenu{
 
// displays contents of URL passed as argument
// this content must be text to be ˆtre lisible
 
  public static void main (String arg[]){
    // argument verification
    if(arg.length==0){
      System.err.println("Syntaxe pg url");
      System.exit(0);
    }
    
    try{
      // creation of URL      
      URL url=new URL(arg[0]);
      // content reading
      try{
        // input stream creation
        BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
        try{
          // read text lines in the input stream
          String ligne;
          while((ligne=is.readLine())!=null)
            System.out.println(ligne);
        } catch (Exception e){
            System.err.println("Erreur lecture : " +e);
        }
        finally{
          try { is.close(); } catch (Exception e) {}
        }
      } catch (Exception e){
          System.err.println("Erreur openStream : " +e);
      }
    } catch (Exception e){
      System.err.println("Erreur création URL : " +e);
    }
  }// fine hand
}// end of class

Depois de verificar que existe realmente um argumento, tentamos criar uma URL com ele:


// création de l'URL      
      URL url=new URL(arg[0]);

Esta criação pode falhar se o argumento não seguir a sintaxe do URL:protocolo:porta//máquina/ficheiro. Se tivermos um URL sintaticamente correto, tentamos criar um fluxo de entrada a partir do qual possamos ler linhas de texto. O fluxo de entrada fornecido por um URL URL.openStream() fornece um InputStream, que é um fluxo orientado por caracteres: a leitura ocorre caractere a caractere, e deve formar as linhas você mesmo. Para ler linhas de texto, deve utilizar o método readLine das classes BufferedReader ou DataInputStream. Aqui, optámos pelo BufferedReader. Resta apenas converter o InputStream da URL num fluxo BufferedReader. Isto é feito através da criação de um fluxo InputStreamReader intermédio:


BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));

A criação deste fluxo pode falhar. Tratamos a exceção correspondente. Assim que o fluxo for obtido, basta ler as linhas de texto a partir dele e exibi-las no ecrã.


            String ligne;
         while((ligne=is.readLine())!=null)
                System.out.println(ligne);

Mais uma vez, a leitura pode lançar uma exceção que deve ser tratada. Aqui está um exemplo da execução do programa que solicita um URL local:

E:\data\serge\Jbuilder\interfaces\JApplets\3>java urlcontenu http://localhost
<html>

<head>


<title>Bienvenue dans le Serveur Web personnel</title>
</head>

<body bgcolor="#FFFFFF" link="#0080FF" vlink="#0080FF"
topmargin="0" leftmargin="0">

<table border="0" cellpadding="0" cellspacing="0" width="100%"
bgcolor="#000000">
............
                </table>
                </center></div></td>
            </tr>
        </table>
        </td>
    </tr>
</table>
</body>
</html>

5.6.5.3. Um exemplo de um utilizador gráfico

A interface gráfica terá o seguinte aspeto:

Image

Número
Nome
Tipo
Função
1
txtURL
JTextField
URL a ler
2
btnLoad
JButton
botão para iniciar o carregamento da URL
3
JScrollPane1
JScrollPane
painel rolável
4
lstURL
JList
lista que exibe o conteúdo do URL solicitado

Quando executado, obtemos um resultado semelhante ao do programa de consola:

Image

O código relevante para a aplicação é o seguinte:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.net.*;
import java.io.*;

public class interfaceURL extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtURL = new JTextField();
  JButton btnCharger = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel lignes=new DefaultListModel();
  JList lstURL = new JList(lignes);

  //Building the frame
  public interfaceURL() {
..............
  }

   //Initialize component
  private void jbInit() throws Exception  {
..............
  }

   //Replaced, so we can get out when the window is closed
  protected void processWindowEvent(WindowEvent e) {
...................
  }

  void txtURL_caretUpdate(CaretEvent e) {
    // sets the state of the Load button
    btnCharger.setEnabled(! txtURL.getText().trim().equals(""));
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // displays contents of URL in list
    try{
      afficherURL(txtURL.getText().trim());
    }catch(Exception ex){
       // error display
      JOptionPane.showMessageDialog(this,"Erreur : " + ex.getMessage(),"Erreur",JOptionPane.ERROR_MESSAGE);
    }//try-catch
  }

  private void afficherURL(String strURL) throws Exception {
    // displays contents of URL strURL in list
     // no exceptions are handled specifically. They are simply reassembled

     // creation of URL
    URL url=new URL(strURL);
     // input stream creation
    BufferedReader IN=new BufferedReader(new InputStreamReader(url.openStream()));
    // read text lines in the input stream
    String ligne;
    while((ligne=IN.readLine())!=null)
      lignes.addElement(ligne);
     // close reading flow
    IN.close();
  }
}

5.6.5.4. Um applet

A aplicação gráfica anterior é convertida num applet, tal como já foi demonstrado várias vezes. O applet está incorporado num documento HTML denominado appliURL.htm:

<html>
  <head>
    <title>Applet lisant une URL</title>
  </head>
  <body>
    <h1>Applet lisant une URL</h1>
    <applet
      code="appletURL.class"
      width="400"
      height="300"
    >
    </applet>
  </body>
</html>

Image

No exemplo acima, o navegador solicitou a URL http://localhost:81/Japplets/2/appliURL.htm a partir de um servidor web Apache em execução na porta 81. O applet foi então exibido no navegador. Neste exemplo, solicitámos novamente a URL http://localhost:81/Japplets/2/appliURL.htm para verificar se estávamos realmente a obter o ficheiro appliURL.htm que tínhamos criado. Agora, vamos tentar carregar uma URL que não pertença à máquina que serviu o applet (neste caso, localhost):

Image

A URL foi recusada. Aqui deparamo-nos com a limitação associada aos applets: estes só podem aceder a recursos de rede na máquina a partir da qual foram descarregados. Existe uma forma de o applet contornar esta restrição, que consiste em delegar os pedidos de rede a um programa de servidor localizado na máquina a partir da qual foi descarregado. Este programa fará os pedidos de rede em nome do applet e enviar-lhe-á os resultados. Isto é designado por programa proxy.

5.7. O Applet de Cálculo de Impostos

Vamos agora converter a aplicação gráfica IMPOTS num applet. Isto reveste-se de particular interesse: a aplicação ficará disponível para qualquer utilizador da Internet que disponha de um navegador e de um plugin Java 1.4 (graças ao componente JSpinner). A nossa aplicação torna-se, assim, global... Esta modificação exigirá um pouco mais do que a simples conversão de aplicação gráfica para applet que se tornou agora padrão. A aplicação utiliza uma opção de menu Initialize concebida para ler o conteúdo de um ficheiro local. No entanto, se considerarmos uma aplicação web, verificamos que esta abordagem já não funciona:

Image

É claro que os dados que definem as faixas de imposto estarão no servidor web e não em cada máquina cliente. O ficheiro a ser lido do servidor web será colocado aqui na mesma pasta que o applet, e a opção «Initialize» terá de o recuperar a partir daí. Os exemplos anteriores mostraram como fazer isto. Além disso, para selecionar o ficheiro de dados localmente, tínhamos utilizado um componente JFileChooser, que já não é necessário aqui.

O documento HTML que contém o applet será o seguinte:

<html>
  <head>
    <title>Applet de calcul d'impôts</title>
  </head>
  <body>
    <h2>Calcul d'impôts</h2>
    <applet
      code="appletImpots.class"
      width="320"
      height="270"
    >

&lt;param name=&quot;data&quot; value=&quot;impots.txt&quot;&gt;

    </applet>
  </body>
</html>

Repare no parâmetro data, cujo valor é o nome do ficheiro que contém os dados das faixas de imposto. O documento HTML, a classe appletImpots, a classe impots e o ficheiro impots.txt encontram-se todos na mesma pasta no servidor web:

E:\data\serge\web\JApplets\impots>dir
12/06/2002  13:24                  247 impots.txt
13/06/2002  10:17                  654 appletImpots$2.class
13/06/2002  10:17                  653 appletImpots$3.class
13/06/2002  10:17                  653 appletImpots$4.class
13/06/2002  10:17                  651 appletImpots$5.class
13/06/2002  10:06                  651 appletImpots$6.class
13/06/2002  10:17                8 655 appletImpots.class
13/06/2002  10:17                  657 appletImpots$1.class
13/06/2002  10:24                  286 appletImpots.htm
13/06/2002  10:17                1 305 impots.class

O código do applet é o seguinte (destacámos apenas as alterações em relação à aplicação gráfica):

...........
import java.net.*;
import java.applet.Applet;

public class appletImpots extends JApplet {
  // window components
  JPanel contentPane;
............................

   // class attributes
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;
  String urlDATA=null;

  //Building the frame
  public void init() {
    //enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // other initializations
    moreInit();
  }

   // form initialization
  private void moreInit(){
     // calculate menu disabled
    mnuCalculer.setEnabled(false);
................
     // retrieve the name of the tax scale file
    String nomFichier=getParameter("data");
    // mistake?
    if(nomFichier==null){
       // error msg
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // we block the Initialize option
      mnuInitialiser.setEnabled(false);
      // end
      return;
    }//if
     // set the URL of the data
    urlDATA=getCodeBase()+"/"+nomFichier;
  }//moreInit

   //Initialize component
  private void jbInit() throws Exception  {
...................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // quit the application
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // load the data file
    try{
       // dATA READING
      lireDATA();
       // create impots object
      objImpots=new impots(limites,coeffr,coeffn);
................
  }

  private void lireDATA() throws Exception {
     // data tables
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // open file in read mode
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
    // read the file line by line
....................
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    // tAX CALCULATION
......................
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
..........
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
...............
  }
}

Aqui, comentamos apenas as alterações resultantes do facto de o ficheiro de dados a ser lido estar agora numa máquina remota, em vez de numa máquina local:

A URL do ficheiro de dados a ser lido é obtida utilizando o seguinte código:

     // retrieve the name of the tax scale file
    String nomFichier=getParameter("data");
    // mistake?
    if(nomFichier==null){
       // error msg
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // we block the Initialize option
      mnuInitialiser.setEnabled(false);
      // end
      return;
    }//if
     // set the URL of the data
    urlDATA=getCodeBase()+"/"+nomFichier;

Lembre-se de que o nome do ficheiro "impots.txt" é passado no parâmetro de dados do applet:

    <param name="data" value="impots.txt">

O código acima começa por recuperar o valor do parâmetro data, ao mesmo tempo que trata de quaisquer erros potenciais. Se o URL do documento HTML que contém o applet for http://localhost:81/JApplets/impots/appletImpots.htm, o URL do ficheiro impots.txt será http://localhost:81/JApplets/impots/impots.txt. Precisamos de construir este URL. O método getCodeBase() do applet devolve a URL do diretório onde o documento HTML que contém o applet foi recuperado, portanto, no nosso exemplo, http://localhost:81/JApplets/impots. A instrução seguinte constrói, portanto, a URL para o ficheiro de dados:

    urlDATA=getCodeBase()+"/"+nomFichier;

No método lireFichier(), que lê o conteúdo da URL urlData, encontramos a criação do fluxo de entrada que nos permitirá ler os dados:

     // open file in read mode
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));

A partir deste ponto, já não é possível distinguir se os dados provêm de um ficheiro remoto em vez de um local. Aqui está um exemplo do applet em ação:

Image

5.8. Conclusão

Este capítulo forneceu

  • uma introdução à criação de interfaces gráficas de utilizador com o JBuilder
  • os componentes Swing mais comuns
  • o desenvolvimento de applets

É importante referir que

  • o código gerado pelo JBuilder pode ser escrito manualmente. Uma vez obtido esse código, seja de que forma for, basta um JDK simples para o executar, deixando o JBuilder de ser essencial.
  • A utilização de uma ferramenta como o JBuilder pode conduzir a ganhos significativos de produtividade:
    • embora seja possível escrever manualmente o código gerado pelo JBuilder, isso pode ser muito demorado e oferece poucos benefícios, uma vez que a lógica da aplicação geralmente está noutro local.
    • O código gerado pode ser instrutivo. Lê-lo e estudá-lo é uma boa forma de descobrir certos métodos e propriedades dos componentes que está a utilizar pela primeira vez.
    • O JBuilder é multiplataforma. Por isso, mantém as suas competências ao alternar entre plataformas. Ser capaz de escrever programas que funcionam tanto no Windows como no Linux é, naturalmente, um fator de produtividade muito importante. Mas isto deve-se ao próprio Java, não ao JBuilder.

5.9. JBuilder no Linux

Todos os exemplos anteriores foram testados no Windows 98. Poder-se-á questionar se os programas escritos são portáveis tal como estão para o Linux. Desde que a máquina Linux em questão tenha as classes utilizadas pelos vários programas, sim, são. Se, por exemplo, tiver instalado o JBuilder no Linux, as classes necessárias já se encontram na sua máquina. Aqui está um exemplo do que acontece quando um dos nossos programas é executado no componente JList com o JBuilder 4 no Linux:

Abaixo, descrevemos a instalação do JBuilder 4 Foundation numa máquina Linux. A instalação numa máquina Win9x não apresenta problemas e é semelhante ao processo aqui descrito. A instalação de versões posteriores é provavelmente diferente, mas este documento pode ainda fornecer algumas informações úteis.

O JBuilder está disponível no site da Inprise em http://www.inprise.com/jbuilder

Image

Esta página contém links para Windows e Linux, entre outros. Vamos agora descrever a instalação do JBuilder numa máquina Linux que execute a interface gráfica KDE.

Ao clicar no link «JBuilder 4 para Linux», surge um formulário. Preencha-o e receberá dois ficheiros:

jb4docs_fr.tar.gz: documentação e exemplos do JBuilder 4

jb4fndlinux_fr.tar.gz: JBuilder 4 Foundation. Esta é uma versão limitada do JBuilder 4 comercial, mas é suficiente para fins educativos.

Será-lhe enviada uma chave de ativação do software por e-mail. Esta permitirá que utilize o JBuilder 4 e será solicitada na sua primeira utilização. Se perder esta chave, pode regressar ao URL acima e seguir o link «obter a sua chave de ativação». A partir daqui, assumiremos que está conectado como root e que se encontra no diretório que contém os dois ficheiros tar.gz mencionados acima. Descompacte os dois ficheiros:

[tar xvzf jb4fndlinux_fr.tar.gz]
[tar xvzf jb4docs_fr.tar.gz]
[ls -l]
drwxr-xr-x    3 nobody   nobody       4096 oct 10  2000 docs
drwxr-xr-x    3 nobody   nobody       4096 déc  5 13:00 foundation
[ls -l foundation]
-rw-r--r--    1 nobody   nobody       1128 déc  5 13:00 deploy.txt
-rwxr-xr-x    1 nobody   nobody   69035365 déc  5 13:00 fnd_linux_install.bin
drwxr-xr-x    2 nobody   nobody       4096 déc  5 13:00 images
-rw-r--r--    1 nobody   nobody      15114 déc  5 13:00 index.html
-rw-r--r--    1 nobody   nobody      23779 déc  5 13:00 license.txt
-rw-r--r--    1 nobody   nobody      75739 déc  5 13:00 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 déc  5 13:00 whatsnew.html
[ls -l docs]
-rw-r--r--    1 nobody   nobody       1128 oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 oct 10  2000 whatsnew.html

Em ambos os diretórios gerados, o ficheiro .bin é o ficheiro de instalação. Além disso, utilize um navegador da Web para visualizar o ficheiro index.html em cada diretório. Estes fornecem instruções para a instalação de ambos os produtos. Vamos começar por instalar o JBuilder Foundation:

[cd foundation]
[./fnd_linux_install.bin]

Aparece o primeiro ecrã de instalação. Seguir-se-ão muitos mais:

Image

Confirme. Segue-se um ecrã explicativo:

Image

Clique em [Seguinte].

Image

Aceite o contrato de licença e clique em [Seguinte].

Image

Aceite o local sugerido para o JBuilder (anote-o; vai precisar dele mais tarde) e clique em [Seguinte]. A instalação é concluída rapidamente.

Image

Estamos prontos para um primeiro teste. No KDE, inicie o gestor de ficheiros para aceder ao diretório do executável do JBuilder: /opt/jbuilder4/bin (se instalou o JBuilder em /opt/jbuilder4):

Image

Clique no ícone do JBuilder acima. Como esta é a primeira vez que utiliza o JBuilder, terá de introduzir a sua chave de ativação:

Image

Preencha os campos Nome e Empresa. Clique em [Adicionar] para introduzir a sua chave de ativação. Lembre-se de que esta chave deve ter-lhe sido enviada por e-mail e, caso a tenha perdido, pode recuperá-la a partir do URL onde descarregou o JBuilder 4 (consulte o início da instalação). Assim que a sua chave de ativação for aceite, os termos da licença serão apresentados:

Image

Ao clicar em OK, regressa à janela de introdução de informações que viu anteriormente:

Image

Clique em OK para concluir esta etapa, que só é executada durante a primeira execução. O ambiente de desenvolvimento JBuilder será então apresentado:

Image

Saia do JBuilder para instalar a documentação agora. Isto irá instalar vários ficheiros que serão utilizados na ajuda do JBuilder, que se encontra atualmente incompleta. Regresse ao diretório onde extraiu os ficheiros tar.gz do JBuilder. O programa de instalação encontra-se no diretório docs. Navegue até ele:

[cd docs]
[ls -l]
-rw-r--r--    1 nobody   nobody       1128 oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 oct 10  2000 whatsnew.html

O ficheiro de instalação é o doc_install.bin, mas não o pode executar imediatamente. Se o fizer, a instalação falhará sem que compreenda o motivo. Leia o ficheiro index.html num navegador para obter uma descrição detalhada do processo de instalação. O instalador requer uma Máquina Virtual Java (JVM); especificamente, um programa chamado java, que deve estar no PATH da sua máquina. Note que PATH é uma variável Unix cujo valor, na forma rep1:rep2:...:repn, especifica os diretórios repi que devem ser pesquisados ao procurar um executável. Aqui, o instalador solicita a execução de um programa Java. Pode ter várias versões deste programa, dependendo do número de máquinas virtuais Java que tenha instalado aqui e ali. Logicamente, utilizaremos a fornecida pelo JBuilder 4, que se encontra em /opt/jbuilder4/jdk1.3/bin. Para adicionar este diretório à variável PATH:

[echo $PATH]
/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
[export PATH=/opt/jbuilder4/jdk1.3/bin/:$PATH]
[echo $PATH]
/opt/jbuilder4/jdk1.3/bin/:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin

Agora podemos iniciar a instalação da documentação:

[./doc_install.bin]
Preparing to install...

Esta é uma instalação gráfica:

Image

É muito semelhante à do JBuilder Foundation. Por isso, não entraremos em detalhes aqui. Há um ecrã que não deve perder:

Image

Normalmente, o instalador deve localizar por si próprio o local onde instalou o JBuilder Foundation. Por isso, não altere as configurações predefinidas, a menos que, evidentemente, estejam incorretas.

Assim que a documentação estiver instalada, estamos prontos para outro teste do JBuilder. Inicie a aplicação como mostrado acima. Assim que o JBuilder estiver aberto, selecione Ajuda > Tópicos de Ajuda. No painel esquerdo, clique na ligação Tutoriais:

Image

O JBuilder inclui um conjunto de tutoriais que o ajudarão a dar os primeiros passos na programação Java. Abaixo, seguimos o tutorial «Criar uma aplicação» mencionado acima.

Image

No JBuilder, vá a Ficheiro > Novo Projeto. Um assistente irá guiá-lo através de três ecrãs:

Image

Vamos criar uma janela simples com o título «Olá a todos». Vamos chamar a este projeto «hello». O exemplo foi executado pelo utilizador root. O JBuilder sugere então agrupar todos os projetos num diretório «jbproject» dentro do diretório de login do utilizador root. O projeto «hello» será colocado no diretório «hello» (campo Nome do diretório do projeto) dentro de «jbproject». Clique em [Seguinte].

Image

Esta segunda tela é um resumo dos vários caminhos do seu projeto. Não há nada a alterar. Clique em [Seguinte].

Image

A terceira tela solicita que personalize o seu projeto. Preencha os detalhes e clique em [Concluir].

Agora vá a Ficheiro/Novo:

Image

Selecione Aplicação e clique em OK. Um novo assistente irá apresentar dois ecrãs:

Image

O campo Pacote utiliza o nome do projeto. O campo Classe solicita o nome a atribuir à classe principal do projeto. Utilize o nome acima e clique em [Seguinte]:

Image

A nossa aplicação inclui uma segunda classe Java para a janela da aplicação. Dê um nome a esta classe. O campo Título é o título que pretende atribuir a esta janela. O painel Opções oferece opções para a sua janela. Selecione todas elas e clique em [Concluir]. Em seguida, regressará ao ambiente do JBuilder, que foi atualizado com as informações que forneceu para o seu projeto:

Image

Na janela superior esquerda (1), vê a lista de ficheiros que compõem o seu projeto. Isto inclui as duas classes .java que acabámos de nomear. Na janela à direita (2), vê o código Java para a classe coucouCadre. A janela inferior esquerda mostra a estrutura (classes, métodos, atributos) do seu projeto. Está pronto a ser executado. Clique no botão 4 acima, ou selecione Run/Run Project, ou prima F9. Deverá ver a seguinte janela:

Image

Ao clicar na opção Ajuda, deverá ver as informações que forneceu aos assistentes de criação. Não iremos mais longe. Está na hora de mergulhar nos tutoriais.

Antes de terminarmos, vamos apenas mostrar que pode utilizar não o JBuilder e a sua interface gráfica, mas sim o JDK que ele trouxe consigo e colocou em /opt/jbuilder4/jdk1.3. Crie o seguinte ficheiro essai1.java:

import java.io.*;

public class essai1{
    public static void main(String args[]){
        System.out.println("coucou");
        System.exit(0);
    }
}

Vamos compilar e executar utilizando o JBuilder JDK:

[ls -l *.java]
-rw-r--r--    1 root     root          135 mai  9 21:57 essai1.java
[/opt/jbuilder4/jdk1.3/bin/javac essai1.java]
[/opt/jbuilder4/jdk1.3/bin/java essai1]
coucou