Skip to content

5. Interfaces gráficas

Propomos aqui mostrar como construir interfaces gráficas com JAVA. Começamos por ver quais são as classes de base que nos permitem construir uma interface gráfica. Numa primeira fase, não utilizamos nenhuma ferramenta 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.

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

5.1.1. Uma janela simples

Consideremos o código seguinte:


// classes importadas
import javax.swing.*;
import java.awt.*;
    
    // a classe do formulário
  public class form1 extends JFrame {
    
      // o construtor
      public form1() {
            // título da janela
            this.setTitle("Mon premier formulaire");
            // dimensões da janela
            this.setSize(new Dimension(300,100));
      }//construtor
  
      // função de teste
      public static void main(String[] args) {
            // exibe-se o formulário
            new form1().setVisible(true);
      }
  }//classe

A execução do código anterior apresenta a seguinte janela:

Image

Uma interface gráfica deriva, geralmente, da classe base JFrame:


  public class form1 extends JFrame {

A classe base JFrame define uma janela básica com botões para fechar, ampliar/reduzir, tamanho ajustável, etc... e gere os eventos nestes objetos gráficos. Aqui, especializamos a classe base, definindo-lhe um título e as suas largura (300 píxeis) e altura (100 píxeis). Isto é feito no seu construtor:


      // o construtor
      public form1() {
            // título da janela
            this.setTitle("Mon premier formulaire");
            // dimensões da janela
            this.setSize(new Dimension(300,100));
      }//construtor

O título da janela é definido pelo método setTitle e as suas dimensões pelo método setSize. Este método aceita como parâmetro um objeto Dimension(largeur,hauteur), em que largeur e hauteur correspondem à largura e à altura da janela, expressas em píxeis.

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 dos eventos que ocorrem no formulário (cliques, movimentos do rato, ...) e executa aqueles que o formulário suporta. Neste caso, o nosso formulário não suporta outros eventos além dos geridos pela classe base JFrame (cliques nos botões de fecho, maximizar/minimizar, alteração do tamanho da janela, deslocamento da janela, ...).

Quando se testa este programa, executando-o a partir de uma janela do DOS com o comando:

java form1

para executar o ficheiro form1.class, verifica-se que, ao fechar a janela que foi exibida, não se «recupera o controlo» na janela do DOS, como se o programa não tivesse terminado. E é efetivamente esse o caso. A execução do programa ocorre da seguinte forma:

  • inicialmente, é iniciado um primeiro thread de execução para executar o método main
  • quando este cria o formulário e o apresenta, é criado um segundo thread para gerir especificamente os eventos relacionados com o formulário
  • após essa criação e, no nosso exemplo, o thread do método main termina, restando apenas o thread de execução da interface gráfica.
  • Quando se fecha a janela, esta desaparece, mas não interrompe o thread no qual estava a ser executada
  • Por enquanto, somos obrigados a parar esse thread premindo Ctrl-C na janela do DOS a partir da qual a execução do programa foi iniciada.

Vamos verificar a existência de duas threads separadas: uma na qual se executa o método main e outra na qual se executa a janela gráfica:


// classes importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;

// a classe do formulário
 public class form1 extends JFrame {
    
// o construtor
 public form1() {
   // título da janela
   this.setTitle("Mon premier formulaire");
   // dimensões da janela
   this.setSize(new Dimension(300,100));
}//construtor
  
// função de teste
 public static void main(String[] args) {
   // acompanhamento
   System.out.println("Début du thread main");
   // exibe o formulário
   new form1().setVisible(true);
   // acompanhamento
   System.out.println("Fin du thread main");  
}//principal
}//classe

A execução produz os seguintes resultados:

Image

Pode-se verificar que o thread main terminou, embora a janela ainda esteja visível. Fechar a janela não encerra o thread no qual esta estava a ser executada. Para parar este thread, volta-se a premir Ctrl-C na janela do DOS.

Para concluir este exemplo, destacam-se os pacotes importados:

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

5.1.2. Gerir um evento

No exemplo anterior, teríamos de gerir o fecho da janela nós próprios para que, quando isso acontecer, a aplicação seja encerrada, o que, por enquanto, não está a ser feito. Para tal, temos de criar um objeto que «escute» os eventos que ocorrem na janela e detete o evento «fecho da janela». A este objeto chama-se «listener» ou gestor de eventos. Existem diferentes tipos de gestores para os diversos eventos que podem ocorrer nos componentes de uma interface gráfica. Para o componente JFrame, o listener 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 o encerramento da janela
 
void
windowDeactivated(WindowEvent e)
          A janela já não é a janela ativa
 
void
windowDeiconified(WindowEvent e)
          A janela passa do estado minimizado para o estado normal
 
void
windowIconified(WindowEvent e)
          A janela passa 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 geridos. Todos os gestores recebem como parâmetro um objeto do tipo WindowEvent, que, por enquanto, ignoramos. O evento que nos interessa aqui é o fecho da janela, evento que deverá ser tratado pelo método windowClosing. Para gerir este evento, podemos criar um objeto Windowlistener utilizando uma classe anónima da seguinte forma:


   // criação de um gestor de eventos
   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){}
   };//definição do Windows

O nosso gestor de eventos que implementa a interface WindowListener deve definir os sete métodos desta interface. Como pretendemos gerir apenas o fecho da janela, apenas definimos código para o método windowClosing. Quando os outros eventos ocorrerem, seremos notificados, mas não faremos nada. O que faremos quando formos notificados de que a janela está a ser fechada (windowClosing)? Iremos encerrar a aplicação:


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

Temos aqui um objeto capaz de gerir os eventos de uma janela em geral. Como é que o associamos a uma janela específica? A classe JFrame possui um método addWindowListener(WindowListener win) que permite associar um gestor de eventos «janela» a uma janela específica. Assim, aqui, no construtor da janela, escreveremos:


   // criação de um gestor de eventos
   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){}
   };//definição do Windows
    // este gestor de eventos irá gerir os eventos da janela atual
   this.addWindowListener(win);

O programa completo é o seguinte:


// classes importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// a classe do formulário
 public class form2 extends JFrame {
    
// o construtor
 public form2() {
   // título da janela
   this.setTitle("Mon premier formulaire");
   // dimensões da janela
   this.setSize(new Dimension(300,100));
   // criação de um gestor de eventos
   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){}
   };//definição do Windows
   // este gestor de eventos irá gerir os eventos da janela atual
   this.addWindowListener(win);
}//construtor
  
// função de teste
 public static void main(String[] args) {
   // exibe-se o formulário
   new form2().setVisible(true);
}//main
}//classe

O pacote java.awt.event contém a interface WindowListener. Ao executar este programa e fechar a janela que apareceu, verifica-se na janela do DOS, onde o programa foi iniciado, que a execução do programa terminou, o que não acontecia anteriormente.

No nosso programa, a criação do objeto responsável pela gestão dos eventos da janela é um pouco complicada, na medida em que somos obrigados a definir métodos mesmo para eventos que não pretendemos gerir. Neste caso, em vez de utilizar a interface WindowListener, pode-se utilizar a classe WindowAdapter. Esta implementa a interface WindowListener, com sete métodos vazios. Ao derivar a classe WindowAdapter e redefinir apenas os métodos que nos interessam, chegamos ao mesmo resultado que com a interface WindowListener, mas sem precisarmos de definir os métodos que não nos interessam. A sequência

  • definição do gestor de eventos
  • associação do gestor à janela

pode ser realizada da seguinte forma no nosso exemplo:


   // criação de um gestor de eventos
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//definição do Windows
   // este gestor de eventos irá gerir os eventos da janela atual
   this.addWindowListener(win);

Aqui, utilizamos uma classe anónima que deriva da classe WindowAdapter e redefine o seu método windowClosing. O programa fica então assim:


// classes importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// a classe do formulário
 public class form2 extends JFrame {
    
// o construtor
 public form2() {
   // título da janela
   this.setTitle("Mon premier formulaire");
   // dimensões da janela
   this.setSize(new Dimension(300,100));
   // criação de um gestor de eventos
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//definição do Windows
   // este gestor de eventos irá gerir os eventos da janela atual
   this.addWindowListener(win); }//construtor
  
// função de teste
 public static void main(String[] args) {
   // exibe-se o formulário
   new form2().setVisible(true);
}//main
}//classe

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

5.1.3. Um formulário com um botão

Vamos agora adicionar um botão à nossa janela:


// classes importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// a classe do formulário
 public class form3 extends JFrame {
 
     // um botão
  JButton btnTest=null;
  Container conteneur=null;
  
  // o construtor
  public form3() {
     // título da janela
    this.setTitle("Formulaire avec bouton");
     // dimensões da janela
    this.setSize(new Dimension(300,100));
    // criação de um gestor de eventos
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//definição do Windows
     // este gestor de eventos irá gerir os eventos da janela atual
    this.addWindowListener(win);
     // recuperamos o contentor da janela
    conteneur=this.getContentPane();
     // seleciona-se um gestor de formatação dos componentes neste contentor
    conteneur.setLayout(new FlowLayout());
    // Cria-se um botão
    btnTest=new JButton();
    // define-se o seu texto
    btnTest.setText("Test");
    // adiciona-se o botão ao contentor
    conteneur.add(btnTest);
  }//construtor
  
  // função de teste
 public static void main(String[] args) {
    // exibe-se o formulário
   new form3().setVisible(true);
}//main
}//classe

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


  Container conteneur=null;
..........
     // recupera-se o contentor da janela
    conteneur=this.getContentPane();

Qualquer componente é colocado no contentor através do método add da classe Container. Assim, para colocar o componente C no objeto conteneur anterior, escrever-se-á:

conteneur.add(C)

Onde é que este componente é colocado no contentor? Existem vários gestores de disposição de componentes com o nome XXXLayout, sendo que XXX é igual, por exemplo, a Border, Flow, ... Cada gestor de disposição tem as suas particularidades. Por exemplo, o gestor FlowLayout dispõe os componentes em linha, começando pelo topo do formulário. Quando uma linha é preenchida, os componentes são colocados na linha seguinte. Para associar um gestor de formatação a uma janela JFrame, utiliza-se o método setLayout da classe JFrame da seguinte forma:

    setLayout(objet XXXLayout);

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


     // seleciona-se um gestor de formatação dos componentes neste contentor
    conteneur.setLayout(new FlowLayout());

É possível não utilizar um gestor de disposição e escrever:

    setLayout(null);

Neste caso, teremos de indicar as coordenadas precisas do componente no contentor na forma (x, y, largura, altura), em que (x, y) são as coordenadas do canto superior esquerdo do componente no contentor. É este método que utilizaremos com mais frequência daqui em diante.

Já sabemos como os componentes são colocados no contentor (add) e onde (setLayout). Resta-nos saber quais os

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



  JButton btnTest=null;
..........
     // cria-se um botão
    btnTest=new JButton();
    // define-se o seu texto
    btnTest.setText("Test");
    // adiciona-se o botão ao contentor
    conteneur.add(btnTest);

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

Image

Se redimensionarmos o formulário acima, o gestor de disposição do contentor é automaticamente chamado para reposicionar os componentes:

Image

Este é o principal interesse dos gestores de disposição: manter uma disposição coerente dos componentes à medida que o tamanho do contentor é alterado. Vamos utilizar o gestor de disposição null para ver a diferença. O botão é agora posicionado no contentor através das seguintes instruções:


// seleciona-se um gestor de formatação dos componentes neste contentor
conteneur.setLayout(null);
    // cria-se um botão
btnTest=new JButton();
    // define-se o texto do botão
btnTest.setText("Test");
    // define-se a sua localização e as suas dimensões
btnTest.setBounds(10,20,100,20);
     // adiciona-se o botão ao contentor
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 local.

Image

Se clicarmos no botão Test, nada acontece. Com efeito, ainda não associamos nenhum gestor de eventos ao botão. Para saber quais os tipos de gestores de eventos disponíveis para um determinado componente, pode-se procurar na definição da sua classe os métodos addXXXListener que permitem associar um gestor de eventos ao componente. A classe javax.swing.JButton deriva da classe javax.swing.AbstractButton, na qual se encontram 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 saber qual o gestor de eventos que trata o clique no botão. Trata-se da interface ActionListener. Esta define apenas um método:

Resumo do método
 
void
actionPerformed(ActionEvent e)
 

O método recebe um parâmetro ActionEvent que, por enquanto, iremos ignorar. Para gerir o clique no botão btntest do nosso programa, associamos-lhe primeiro um gestor de eventos:


        btnTest.addActionListener(new ActionListener()
         {
                public void actionPerformed(ActionEvent evt){
                  btnTest_clic(evt);
              }
            }//classe anónima
    );//gestor de eventos

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


public void btnTest_clic(ActionEvent evt){
  // monitorização da consola
System.out.println("clic sur bouton");
}//btnTest_click

Sempre que o utilizador clica no botão Test, é gravada uma mensagem na consola. É o que se pode ver na execução seguinte:

Image

O programa completo é o seguinte:


// classes importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// a classe do formulário
 public class form4 extends JFrame {
 
     // um botão
  JButton btnTest=null;
  Container conteneur=null;
  
  // o construtor
  public form4() {
     // título da janela
    this.setTitle("Formulaire avec bouton");
     // dimensões da janela
    this.setSize(new Dimension(300,100));
    // criação de um gestor de eventos
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//definição do Windows
     // este gestor de eventos irá gerir os eventos da janela atual
    this.addWindowListener(win);
     // recuperamos o contentor da janela
    conteneur=this.getContentPane();
     // seleciona-se um gestor de formatação dos componentes neste contentor
    conteneur.setLayout(null);
    // cria-se um botão
    btnTest=new JButton();
    // define-se o seu texto
    btnTest.setText("Test");
    // define-se a sua localização e as suas dimensões
    btnTest.setBounds(10,20,100,20);
     // associa-se-lhe um gestor de eventos
    btnTest.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt){
              btnTest_clic(evt);
          }
        }//classe anónima
    );//gestor de eventos
     // adiciona-se o botão ao contentor
    conteneur.add(btnTest);
  }//construtor

    public void btnTest_clic(ActionEvent evt){
       // acompanhamento da consola
    System.out.println("clic sur bouton");
  }//btnTest_click
    
  // função de teste
 public static void main(String[] args) {
    // o formulário é apresentado
   new form4().setVisible(true);
}//principal
}//classe

5.1.4. Os gestores de eventos

Os principais componentes do Swing que iremos apresentar são as janelas (JFrame), os botões (JButton), as caixas de seleção (JCheckBox), os botões de opção (JButtonRadio), as listas suspensas (JComboBox), as listas (JList), os controlos deslizantes (JScrollBar), as etiquetas (JLabel), os campos de entrada de uma linha (JTextField) ou de várias linhas (JTextArea), os menus (JMenuBar), os elementos de menu (JMenuItem).

As tabelas seguintes apresentam uma lista de alguns gestores de eventos e os eventos aos quais estão associados.

Gestor
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 elemento do menu
 
JTextField
ItemListener
JComboBox, JList
public void addItemListener(ItemListener)
O elemento selecionado foi alterado
InputMethodListener
JTextField, JTextArea
public void addMethodInputListener(InputMethodListener)
O texto do campo de introdução foi alterado ou o cursor de introdução mudou de posição
CaretListener
JTextField, JTextArea
public void addcaretListener(CaretListener)
O cursor de introdução mudou de posição
AdjustmentListener
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
O valor do variador alterou-se
MouseMotionListener
 
public void addMouseMotionListener(MouseMotionListener)
o rato moveu-se
WindowListener
JFrame
public void addWindowlistener(WindowListener)
evento de janela
MouseListener
 
public void addMouselistener(MouseListener)
eventos do rato (clique, entrada/saída da área de um componente, botão pressionado, soltar)
FocusListener
 
public void addFocuslistener(FocusListener)
evento focus (obtido, perdido)
KeyListener
 
public void addKeylistener(KeyListener)
evento de teclado (tecla digitada, pressionada, solta)
Componente
Método de registo dos gestores de eventos
JButton
public void addActionListener(ActionListener)
JCheckbox
public void addItemListener(ItemListener)
JCheckboxMenuItem
public void addItemListener(ItemListener)
JComboBox
public void addItemListener(ItemListener)
public void addActionListener(ActionListener)
Container
public void addContainerListener(ContainerListener)
JComponent
public void addComponentListener(ComponentListener)
public void addFocusListener(FocusListener)
public void addKeyListener(KeyListener)
public void addMouseListener(MouseListener)
public void addMouseMotionListener(MouseMotionListener)
JFrame
public void addWindowlistener(WindowListener)
JList
public void addItemListener(ItemListener)
JMenuItem
public void addActionListener(ActionListener)
JPanel
como Container
JScrollPane
como Container
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
JTextComponent
public void addInputMethodListener(InputMethodListener)
public void addCaretListener(CaretListener)
JTextArea
como JTextComponent
JTextField
como JTextComponent
public void addActionListener(ActionListener)

Todos os componentes, exceto os do tipo TextXXX, sendo derivados da classe JComponent, possuem também os métodos associados a essa classe.

5.1.5. Os métodos dos gestores de eventos

A tabela seguinte enumera os métodos que os diferentes gestores de eventos devem implementar.

Interface
Métodos
ActionListener
public void actionPerformed(ActionEvent)
AdjustmentListener
public void adjustmentValueChanged(AdjustmentEvent)
ComponentListener
public void componentHidden(ComponentEvent)
public void componentMoved(ComponentEvent)
public void componentResized(ComponentEvent)
public void componentShown(ComponentEvent)
ContainerListener
public void componentAdded(ContainerEvent)
public void componentRemoved(ContainerEvent)
FocusListener
public void focusGained(FocusEvent)
public void focusLost(FocusEvent)
ItemListener
public void itemStateChanged(ItemEvent)
KeyListener
public void keyPressed(KeyEvent)
public void keyReleased(KeyEvent)
public void keyTyped(KeyEvent)
MouseListener
public void mouseClicked(MouseEvent)
public void mouseEntered(MouseEvent)
public void mouseExited(MouseEvent)
public void mousePressed(MouseEvent)
public void mouseReleased(MouseEvent)
MouseMotionListener
public void mouseDragged(MouseEvent)
public void mouseMoved(MouseEvent)
TextListener
public void textValueChanged(TextEvent)
InputmethodListener
public void InputMethodTextChanged(InputMethodEvent)
public void caretPositionChanged(InputMethodEvent)
CaretLisetner
public void caretUpdate(CaretEvent)
WindowListener
public void windowActivated(WindowEvent)
public void windowClosed(WindowEvent)
public void windowClosing(WindowEvent)
public void windowDeactivated(WindowEvent)
public void windowDeiconified(WindowEvent)
public void windowIconified(WindowEvent)
public void windowOpened(WindowEvent)

5.1.6. As classes adaptadoras

Tal como vimos para a interface WindowListener, existem classes denominadas XXXAdapter que implementam as interfaces XXXListener com métodos vazios. Um gestor de eventos derivado de uma classe XXXAdapter pode, assim, implementar apenas uma parte dos métodos da interface XXXListener, nomeadamente aqueles de que a aplicação necessita.

Suponhamos que se pretenda gerir os cliques do rato num componente Frame f1. Poder-se-ia associar-lhe um gestor de eventos da seguinte forma:

    f1.addMouseListener(new gestionnaireSouris());

e escrever:


    public class gestionnaireSouris implements MouseListener{
         // escrevem-se os 5 métodos da interface MouseListener
        // mouseClicked, ..., mouseReleased)
    }// fim da classe

Como se pretende gerir apenas os cliques do rato, é, no entanto, preferível escrever:


public class gestionnaireSouris extends MouseAdapter{
        // escreve-se apenas um método, aquele que gere os cliques do rato
        public void mouseClicked(MouseEvent evt){

        }
}// fim da classe

A tabela seguinte apresenta as classes adaptadoras dos diferentes gestores de eventos:

Gestor de eventos
Adaptador
ComponentListener
ComponentAdapter
ContainerListener
ContainerAdapter
FocusListener
FocusAdapter
KeyListener
KeyAdapter
MouseListener
MouseAdapter
MouseMotionListener
MouseMotionAdapter
WindowListener
WindowAdapter

5.1.7. Conclusão

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

  • criação de uma janela
  • criação de componentes
  • associação dos componentes à janela através de um gestor de disposição
  • associação de gestores de eventos aos componentes

Agora, em vez de construir interfaces gráficas «manualmente», como acabámos de fazer, vamos utilizar o JBuilder, uma ferramenta de desenvolvimento Java da Borland/Inprise na sua versão 4, e supérieure.Nous utilizaremos os componentes da biblioteca java.swing, atualmente recomendada pela Sun, criadora do Java.

5.2. Criar uma interface gráfica 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 a opção Ficheiro/Novo projeto. É então apresentada a primeira página de um assistente:

Image

  1. Preencha os seguintes campos:
Nome do projeto
Início
Isto irá criar um ficheiro de projeto début.jpr na pasta indicada no campo «Nome da pasta do projeto»
Caminho raiz
Indique a pasta na qual será criada a pasta do projeto que vai criar.
Nome da pasta do projeto
Indique o nome da pasta onde serão colocados todos os ficheiros do projeto. Esta pasta será criada na pasta indicada 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 esses campos em branco, serão colocados no mesmo diretório que o projeto.

Crie [suivant]

  1. Um ecrã confirma as escolhas da etapa anterior

Image

Execute [suivant]

  1. Um novo ecrã solicita que defina as características do seu projeto:

Image

Selecione [terminer]

  1. Verifique se a opção Voir/projet está marcada. Deverá ver a estrutura do seu projeto na janela da esquerda.

Image

  1. Agora vamos criar uma interface gráfica neste projeto. Selecione a opção Fichier/Nouveau/Application:

Image

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

Execute [suivant]

  1. Aparece o ecrã seguinte:

Image

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

Note que, acima, solicitámos que a janela fosse centrada no ecrã ao iniciar a aplicação.

Crie [Terminer]

  1. É agora que o JBuilder se revela útil.
  • Ele gera os ficheiros-fonte .java das duas classes cujos nomes indicámos: a classe da aplicação e a da interface gráfica. Estes dois ficheiros aparecem na estrutura do projeto, na janela da esquerda

Image

  • Para aceder ao código gerado para as duas classes, basta clicar duas vezes no ficheiro .java correspondente. Voltaremos mais tarde ao código gerado.
  • Verifique se a opção Voir/Structure está marcada. Esta opção permite visualizar a estrutura da classe atualmente selecionada (clique duplo no ficheiro .java). Aqui está, por exemplo, a estrutura da classe début:

Image

Aqui ficamos a saber:

  • as bibliotecas importadas (imports)

  • que existe um construtor début()

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

  • que existe um atributo packFrame

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

  • tem 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 de 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 ser utilizado. Selecione Executar/Executar o projeto ou F9 e obterá a janela pretendida:

Image

Além disso, ela fecha corretamente quando se clica no botão de fecho da janela. Acabámos de construir a nossa primeira interface gráfica. Podemos guardar o nosso projeto através da opção Ficheiro/Fechar projetos:

Image

Ao premir Tous, todos os projetos presentes na janela acima serão selecionados. OK irá fechá-los. Se tivermos curiosidade em aceder, através do Explorador do Windows, à pasta do nosso projeto (aquela que foi indicada ao assistente no início da configuração do projeto), encontraremos os seguintes ficheiros:

Image

No nosso exemplo, solicitámos que todos os ficheiros (fonte .java, destino .class, cópia de segurança .jpr~) ficassem na mesma pasta que o projeto .jpr.

5.2.2. Os ficheiros gerados pelo JBuilder para uma interface gráfica

Vamos agora dar uma vista de olhos aos ficheiros-fonte .java que o JBuilder gerou. É importante saber interpretar o que é gerado, uma vez que, na maioria das vezes, temos de adicionar código ao que foi gerado. Comecemos por recuperar o nosso projeto: Ficheiro/Abrir um projeto e selecionemos o projeto début.jpr. Encontramos o projeto criado anteriormente.

5.2.2.1. A classe principal

Vamos examinar a classe début.java clicando duas vezes no seu nome na janela que apresenta 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;

   /**Construir a aplicação*/
  public début() {
    interfaceDébut frame = new interfaceDébut();

     //Validar os quadros com tamanhos predefinidos
     //Compactar os quadros com informações de tamanho preferencial — por exemplo, a partir do seu layout
    if (packFrame) {
      frame.pack();
    }
    else {
      frame.validate();
    }
    //Centrar a janela
    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);
  }
   /**Método principal*/
  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 main define o aspeto da janela (setLookAndFeel) e cria uma instância da classe début.
  2. O construtor début() é então executado. Este cria uma instância frame da classe da janela (new interfaceDébut()). Esta é construída, mas não é apresentada.
  3. A janela é então dimensionada de acordo com as informações disponíveis para cada um dos seus componentes (frame.validate). Inicia então a sua existência independente, sendo exibida e respondendo às solicitações do utilizador.
  4. A janela é centrada no ecrã, uma vez que tal foi solicitado durante a configuração da janela com o assistente.

Vejamos o que se obteria se reduzíssemos o código début.java ao seu mínimo indispensável, tal como fizemos no início do capítulo. Criemos uma nova classe. Selecione a opção Ficheiro/Nova classe:

Image

Dê à nova classe o nome début2 e renomeie [Terminer]. Aparece um novo ficheiro 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 {
   // função principal
  public static void main(String args[]){
    // cria a janela
    new interfaceDébut().show();    // ou new interfaceDébut.setVisible(true);
  }//main
}//classe início2

A função main cria uma instância da janela interfaceDébut e apresenta-a (show). Antes de executar o nosso projeto, é necessário referir 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 propriétés e, em seguida, o separador Exécution:

21

Image

Aqui, é indicado que a classe principal é début (1). Clique no botão (2) para selecionar outra classe principal:

Image

Selecione début2 e altere para [OK].

Image

Selecione [OK] para confirmar esta escolha e, em seguida, inicie a execução do projeto através de Executar/Executar projeto ou F9. Obtém-se a mesma janela que com a classe début, com a diferença de que esta não está centrada, uma vez que tal não foi solicitado neste caso. Daqui em diante, não iremos apresentar a classe principal gerada pelo JBuilder, pois esta faz sempre o mesmo: criar uma janela. É na classe desta última que, a partir de agora, nos iremos concentrar.

5.2.2.2. A classe da janela

Vejamos agora 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();

  /**Construir o quadro*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  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");
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
}

5.2.2.2.1. As bibliotecas importadas
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

Trata-se das bibliotecas java.awt, java.awt.event e javax.swing. As duas primeiras eram as únicas disponíveis para criar interfaces gráficas com as primeiras versões do Java. A biblioteca javax.swing é mais recente. Neste caso, é necessária para a janela do tipo JFrame que está a ser utilizada aqui.

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

JPanel é um tipo de contentor no qual é possível colocar componentes. BorderLayout é um dos tipos de gestores de formatação disponíveis para colocar os componentes no contentor. Em todos os nossos exemplos, não utilizaremos nenhum gestor de formatação e colocaremos nós próprios os componentes num local específico do contentor. Para tal, utilizaremos o gestor de formatação null.

5.2.2.2.3. O construtor da janela
   /**Construir o quadro*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  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 programador começa por indicar que irá gerir 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 formatação é definido (setLayout)
  4. O tamanho da janela é definido (setSize)
  5. O título da janela é definido (setTitle)

5.2.2.2.4. O gestor de eventos
   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }

O criador tinha indicado que a classe trataria os eventos da janela. É o método processWindowEvent que realiza essa tarefa. Começa por transmitir à sua classe pai (JFrame) o evento WindowEvent recebido e, se este for o evento WINDOW_CLOSING provocado pelo clique no botão de fecho da janela, a aplicação é encerrada.

5.2.2.2.5. Conclusão

O código da classe da janela é diferente do apresentado no exemplo no início do capítulo. Se utilizássemos outra ferramenta de geração de código Java que não o JBuilder, teríamos, sem dúvida, um código ainda diferente. Na prática, aceitaremos o código produzido pelo JBuilder para construir a janela, de modo a concentrarmo-nos exclusivamente na escrita dos gestores de eventos da interface gráfica.

5.2.3. Desenhar uma interface gráfica

5.2.3.1. Um exemplo

No exemplo anterior, não colocámos componentes na janela. Vamos agora construir 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
lblSaisie
JLabel
uma designação
2
txtSaisie
JTextField
um campo de introdução de dados
3
cmdAfficher
JButton
para apresentar numa caixa de diálogo o conteúdo do campo de entrada txtSaisie

Seguindo o mesmo procedimento do projeto anterior, crie o projeto interface2.jpr sem, por enquanto, colocar quaisquer componentes na janela.

Image

Na janela acima, selecione a classe interface2.java da janela. À direita desta janela, encontra-se um organizador com separadores:

Image

O separador Source dá acesso ao código-fonte da classe interface2.java. A aba Conception permite construir visualmente a janela. Selecione esta aba. Tem diante de si o contentor da janela, que irá receber os componentes que irá colocar nele. De momento, está vazio. Na janela à esquerda é apresentada a estrutura da classe:

Image

this
representa a janela
contentPane
o seu contentor, no qual serão colocados os componentes, bem como a forma como esses componentes serão dispostos no contentor (BorderLayout por predefinição)
borderLayout1
uma instância do gestor de formatação

Selecione o objeto this. A janela de propriedades deste aparece então à direita:

Image

Algumas destas propriedades merecem destaque:

background
para definir a cor de fundo da janela
foreground
para definir a cor dos elementos 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 o objeto this ainda selecionado, é possível redimensionar o contentor exibido no ecrã, arrastando os pontos de ancoragem situados à volta do contentor:

Image

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

Image

Em seguida, na janela de propriedades desse objeto, selecione a propriedade layout e escolha, entre os valores possíveis, o valor null:

Image

A ausência de um gestor de formatação permitirá-nos posicionar livremente os componentes no contentor. Chegou a altura de os selecionar.

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

Image

Para construir a interface gráfica, dispomos dos componentes swing (1) e dos componentes awt (2). Vamos utilizar aqui 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 de design.

Image

Agora, vamos personalizar cada um destes três componentes:

  • a etiqueta (JLabel) jLabel1

Selecione o componente para aceder à sua janela de propriedades. Nesta janela, altere as seguintes propriedades: nome: lblSaisie, texto: Introdução

  • o campo de introdução (JTextField) jTextfield1

Selecione o componente para aceder à sua janela de propriedades. Nesta janela, altere as seguintes propriedades: name: txtSaisie, text: não preencher

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

Temos agora a seguinte janela:

Image

e a seguinte estrutura:

Image

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

Image

Feche a janela. Resta-nos escrever o procedimento associado a um clique no botão Afficher. Selecione o botão para aceder à sua janela de propriedades. Esta janela tem dois separadores: propriétés e événements. Selecione événements.

Image

A coluna da esquerda da janela lista os eventos possíveis associados ao 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 por predefinição para cada gestor de eventos com o formato nomComposant_nomEvénement, neste caso cmdAfficher_actionPerformed. É possível apagar o nome proposto por predefinição e introduzir outro. Para aceder ao código do gestor cmdAfficher_actionPerformed, basta clicar duas vezes no seu nome acima. Passa-se então automaticamente para o painel de código-fonte da classe, posicionado no esboço do código do gestor de eventos:

  void cmdAfficher_actionPerformed(ActionEvent e) {
 }

Resta-nos apenas completar este código. Neste caso, pretendemos 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 apresentar mensagens acompanhadas de um ícone ou solicitar informações ao utilizador. Aqui, utilizamos um método estático da classe:

Image

parentComponent
o objeto «pai» da caixa de diálogo: neste caso, this.
mensagem
um objeto a apresentar. Aqui, o conteúdo do campo de introdução
title
o título da caixa de diálogo
messageType
o tipo da mensagem a apresentar. Determina o ícone que será apresentado na caixa ao lado da mensagem. Os 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();

  /**Construir o quadro*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  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);
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  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();

Encontram-se o contentor dos componentes do tipo JPanel e os três componentes.

5.2.3.2.2. O fabricante
   /**Construir o quadro*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  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 analisada. É no método jbInit que se encontram as diferenças: o código de construção da janela depende dos componentes que nela foram colocados. Podemos reutilizar o código de jbInit, acrescentando-lhe os nossos próprios comentários:

  private void jbInit() throws Exception  {
       // a própria janela (tamanho, título)
this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
         // o contentor dos componentes
    contentPane = (JPanel) this.getContentPane();
         // sem gestor de formatação para este contentor
    contentPane.setLayout(null);
         // a etiqueta lblSaisie (texto, posição, tamanho)
         lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
        // o campo de introdução de dados (posição, tamanho)
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
         // o botão «Mostrar» (texto, posição, tamanho)
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
         // o gestor de eventos do botão
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
         // adição dos 3 componentes ao contentor
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }//jbInit

É importante destacar dois aspetos:

  • este código poderia ter sido escrito manualmente. Isto significa que é possível prescindir do JBuilder para criar uma interface gráfica.
  • a forma como o gestor de eventos do botão cmdAfficher está definido. O gestor de eventos do componente cmdAfficher poderia ter sido declarado por cmdAfficher.addActionListener(new gestora()) em que gestionnaire seria uma classe com um método público actionPerformed encarregado de gerir o clique no botão Afficher. Aqui, o JBuilder utiliza como gestora uma instância de uma classe anónima:
 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 em seguida. Este método limita-se a chamar um método da classe interface2. Tudo isto não passa de um artifício para definir, na mesma classe que a janela, os procedimentos de tratamento dos eventos dos componentes dessa janela. Seria possível proceder de outra forma:

cmdAfficher.addActionListener(this)

o que faz com que o método actionPerformed seja procurado em this, ou seja, na classe da janela. Este segundo método parece mais simples, mas o primeiro tem uma vantagem: permite ter gestores diferentes para botões diferentes, ao passo que o segundo método não o permite. Neste último caso, com efeito, o único método actionPeformed tem de processar os cliques de diferentes botões e, por isso, começar por identificar qual deles está na origem do evento antes de iniciar o seu funcionamento.

5.2.3.2.3. Os gestores de eventos

Encontramos aqui os que já foram estudados:

   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }

     // clique no botão «Mostrar»
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }

5.2.3.3. Conclusion

A partir dos dois projetos analisados, podemos concluir que, uma vez criada a interface gráfica com o JBuilder, o trabalho do programador consiste em escrever os gestores de eventos que pretende gerir para essa interface gráfica.

5.2.4. Procurar ajuda

Com o Java, é frequente precisarmos de ajuda, sobretudo devido ao grande número de classes disponíveis. Apresentamos aqui algumas indicações 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 se especifica o que se procura. Tem três separadores: Sommaire, Index e Chercher.
  • a da direita, que apresenta o resultado da pesquisa

Existe uma ajuda sobre como utilizar a ajuda do JBuilder. Selecione, na ajuda do JBuilder, a opção Ajuda/Utilização da ajuda. Ser-lhe-á então explicado como utilizar a ajuda. Ser-lhe-ão indicados, por exemplo, os diferentes componentes do visualizador de ajuda:

Image

Vamos analisar mais de perto as páginas Sommaire e Index.

5.2.4.1. Ajuda: Índice

Image

5.2.4.1.1. Índice: Introdução ao Java

Aqui encontrar-se-ão os conceitos básicos de Java, mas não só, como mostra a lista de temas abordados nesta opção:

Image

5.2.4.1.2. Índice: Tutoriais

Se selecionarmos a opção «Tutoriais» no índice acima, a janela à direita apresenta-nos uma lista dos tutoriais disponíveis:

Image

Os tutoriais básicos são particularmente interessantes para começar a familiarizar-se com o JBuilder. Existem muitos outros além dos apresentados acima e, quando se pretende desenvolver uma aplicação, pode ser útil verificar previamente se não existe algum tutorial que nos possa ajudar.

5.2.4.1.3. Índice: o JDK

Ao selecionar a opção Java 2 JDK 1.3, tem-se acesso a todas as bibliotecas do JDK. Normalmente, não é aqui que se deve procurar se precisarmos de informações sobre uma classe específica e não soubermos em que biblioteca ela se encontra. Por outro lado, esta opção é útil se estivermos interessados em ter uma visão global das bibliotecas do Java.

5.2.4.2. Ajuda: Índice

Selecione o separador Índice na janela à esquerda da ajuda. Esta opção permite-lhe, por exemplo, encontrar ajuda sobre uma classe. Suponhamos, por exemplo, que queira conhecer os métodos dos campos de entrada swing e JTextField. Digite JTextField no campo de entrada do texto a pesquisar:

Image

A ajuda irá apresentar as entradas do índice que começam com o texto digitado:

Image

Basta clicar duas vezes na entrada que lhe interessa, neste caso JTextField class. A ajuda sobre esta classe é então apresentada na janela à direita:

Image

É-lhe então apresentada uma descrição completa da classe.

5.2.5. Alguns componentes Swing

Apresentamos agora várias aplicações que utilizam os componentes swing mais comuns, com o objetivo de explorar os seus principais métodos e propriedades. Para cada aplicação, apresentamos a interface gráfica e o código relevante, nomeadamente o dos gestores 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 introdução de dados. Os seus dois métodos principais são

String getText()
para obter o conteúdo do campo de introdução ou o texto da legenda
void setText(String unTexte)
para inserir unTexte no campo ou no rótulo

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

actionPerformed
indica que o utilizador confirmou (tecla Enter) o texto introduzido
caretUpdate
indica que o utilizador moveu o cursor de introdução
inputMethodChanged
indica que o utilizador alterou o campo de introdução

Eis um exemplo que utiliza o evento caretUpdate para acompanhar as alterações num campo de introdução de dados:

Image

n.º
tipo
nome
função
1
JTextField
txtSaisie
campo de introdução
2
JTextField
txtControle
exibe o texto de 1 em tempo real
3
JButton
cmdEffacer
para apagar os campos 1 e 2
4
JButton
cmdQuitter
para sair da aplicação

O código relevante desta 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();

  /**Construir o quadro*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  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);
      }
    });
....
}

   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_caretUpdate(CaretEvent e) {
         // o cursor de introdução de dados moveu-se
    txtControle.setText(txtSaisie.getText());
  }

  void CmdQuitter_actionPerformed(ActionEvent e) {
        // sai-se da aplicação
    System.exit(0);
  }

  void CmdEffacer_actionPerformed(ActionEvent e) {
        // limpa-se o conteúdo do campo de introdução
    txtSaisie.setText("");
  }
}

Eis um exemplo de execução:

Image

5.2.5.2. componente JComboBox

Image

Image

Um componente JComboBox é uma lista suspensa acompanhada de um campo de introdução de texto: o utilizador pode escolher um elemento em (2) ou introduzir texto em (1). Por predefinição, os JComboBox não são editáveis. É necessário chamar explicitamente o método setEditable(true) para que se tornem editáveis. Para conhecer a classe JComboBox, digite JComboBox no índice da ajuda.

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

new JComboBox()
cria um combo vazio
new JComboBox (Object[] items)
cria um combo que contém um vetor de objetos
new JComboBox(Vector items)
o mesmo, mas com um vetor de objetos

Pode parecer surpreendente que um combo possa conter objetos, quando normalmente contém cadeias de caracteres. Visualmente, será esse o caso. Se um JComboBox contiver um objeto obj, exibirá a cadeia obj.toString(). Recorde-se que todo o objeto possui um método toString herdado da classe Object, que devolve uma cadeia de caracteres «representativa» do objeto.

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

void addItem(Object unObjet)
adiciona um objeto à lista suspensa
int getItemCount()
retorna o número de elementos da lista suspensa
Object getItemAt(int i)
retorna o objeto n.º i da lista suspensa
void insertItemAt(Object unObjet, int i)
insere unObjet na posição i da lista suspensa
int getSelectedIndex()
retorna o número do elemento selecionado na lista suspensa
Object getSelectedItem()
retorna o objeto selecionado na lista suspensa
void setSelectedIndex(int i)
seleciona o elemento i da lista suspensa
void setSelectedItem(Object unObjet)
seleciona o objeto especificado na lista suspensa
void removeAllItems()
esvazia a lista suspensa
void removeItemAt(int i)
remove o elemento n.º i da lista suspensa
void removeItem(Object unObjet)
remove o objeto especificado da lista suspensa
void setEditable(boolean val)
torna a lista suspensa editável (val=true) ou não (val=false)

Ao selecionar um elemento na lista suspensa, ocorre o evento actionPerformed, que pode então ser utilizado para ser notificado da alteração da seleção na lista suspensa. Na aplicação seguinte, utilizamos este evento para apresentar o elemento que foi selecionado na lista.

Image

Apresentamos apenas o código relevante da janela.

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

   /**Construir o quadro*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // processamento - preencher a lista suspensa
    String[] infos={"un","deux","trois","quatre"};
    for(int i=0;i<infos.length;i++)
      jComboBox1.addItem(infos[i]);
  }
   /**Inicializar o componente*/
  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) {
        // foi selecionado um novo elemento - exibe-se o mesmo
    JOptionPane.showMessageDialog(this,jComboBox1.getSelectedItem(),
"actionPerformed",JOptionPane.INFORMATION_MESSAGE);
  }

}

5.2.5.3. componente JList

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

  • o conteúdo da lista é gerido por um objeto diferente da própria lista. Aqui, utilizaremos um objeto DefaultListModel, que funciona como um Vector, mas que, além disso, notifica o objeto JList assim que o seu conteúdo muda, para que a apresentação visual da lista também seja atualizada.
  • Por predefinição, a lista não é rolante. É necessário colocar a lista num contentor ScrollPane, que permite essa funcionalidade de rolagem.

No código-fonte, a definição de uma lista pode ser feita da seguinte forma:

      // o vetor dos valores da lista 
DefaultlistModel valeurs=new DefaultListModel();
// a própria lista à qual se associa o vetor dos seus valores
  JList jList1 = new JList(valeurs);
     // o contentor de rolagem no qual se coloca a lista para obter uma lista com rolagem
  JScrollPane jScrollPane1 = new JScrollPane(jList1);

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

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

Para adicionar valores à lista JList1 acima, basta adicioná-los ao seu vetor de valores valeurs:

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

e obtém-se então a seguinte janela:

Image

Como é que esta interface é construída?

  • seleciona-se um componente JScrollPane na página «Contentores Swing» dos componentes e arrasta-se para a janela, ajustando-o ao tamanho desejado
  • seleciona-se um componente JList na página «Swing» dos componentes e coloca-se no contentor JScrollPane, ocupando assim todo o espaço disponível.

O código gerado pelo JBuilder deve ser ligeiramente alterado para obter 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();


   /**Construir o quadro*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // processamento
     // inclui-se a lista no scrollPane
    // inicializar lista
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);
  }

   /**Inicializar o componente*/
  private void jbInit() throws Exception  {
        ....
         // a lista jList1 está associada ao contentor jcrollPane1
    jScrollPane1.getViewport().add(jList1, null);
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
        ....
  }
}

Vamos agora descobrir os principais métodos da classe JList, pesquisando por JList no índice da ajuda. O objeto JList pode ser criado de várias formas:

Image

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

Image

É possível saber o modo de seleção atual com o método getSelectionMode:

Image

O(s) elemento(s) selecionado(s) pode(m) ser obtido(s) através dos seguintes métodos:

Image

Sabemos associar um vetor de valores a uma lista com o construtor JList(DefaultListModel). Inversamente, podemos obter o objeto DefaultListModel a partir de uma lista JList através de:

Image

Já 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
txtSaisie
campo de introdução
2
JList
jList1
lista contida num contentor jScrollPane1
3
JList
jList2
lista contida num contentor jScrollPane2
4
JButton
cmd1To2
transfere os elementos selecionados da lista 1 para a lista 2
5
JButton
cmd2To1
faz o inverso
6
JButton
cmdRaz1
esvazia a lista 1
7
JButton
cmdRaz2
esvazia a lista 2

O utilizador introduz texto no campo (1) e confirma. Em seguida, ocorre o evento actionPerformed no campo de introdução, que é utilizado para adicionar o texto introduzido à lista 1. Aqui está o código necessário 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();

   /**Construir o quadro*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Inicializar o componente*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // O Jlist1 é colocado no contentor jScrollPane1
    jScrollPane1.getViewport().add(jList1, null);
        // O Jlist2 é colocado no contentor jScrollPane2
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     // o texto introduzido foi validado
     // recuperamo-lo sem os espaços no início e no fim
    String texte=txtSaisie.getText().trim();
     // se estiver vazio, não o queremos
    if(texte.equals("")){
      // mensagem de erro
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // fim
      return;
    }//se
    // se não estiver vazio, adiciona-se aos valores da lista 1
    v1.addElement(texte);
     // e esvazia-se o campo de introdução
    txtSaisie.setText("");
  }/// txtSaisie_actionperformed
}//classe

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

  void cmd1To2_actionPerformed(ActionEvent e) {
    // transferência dos elementos selecionados da lista 1 para a lista 2
    transfert(jList1,jList2);
  }//cmd1To2

  void cmd2To1_actionPerformed(ActionEvent e) {
    // transferência dos elementos selecionados em jList2 para jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  private void transfert(JList L1, JList L2){
      // transferência dos elementos selecionados da lista 1 para a lista 2
       // recuperamos a tabela de índices dos elementos selecionados em L1
      int[] indices=L1.getSelectedIndices();
      // há algo a fazer?
      if (indices.length==0) return;
      // recuperam-se os valores de L1
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      // e os de L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // adiciona-se a L2 os valores selecionados em L1
        v2.addElement(v1.elementAt(indices[i]));
        // os elementos de L1 copiados para L2 devem ser eliminados de L1
        v1.removeElementAt(indices[i]);
      }//para
  }//transferência

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

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // esvaziar a lista 1
    v1.removeAllElements();
  }//comando Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // esvaziar lista 2
    v2.removeAllElements();
  }///comando 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 — serve para agrupar os 3 botões de opção, de modo a que, quando um deles ficar aceso, os outros se apaguem.

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

  • coloca-se cada um dos botões de opção sem se preocupar em agrupá-los
  • coloca-se no contentor um componente Swing ButtonGroup. Este componente não é visual. Por isso, não aparece no editor da janela. No entanto, aparece na sua estrutura:

Image

Vê-se acima, no ramo Autre, os atributos não visuais da janela. Depois de criado um grupo de botões de opção, é possível associar-lhe cada um dos botões de opção. Para tal, seleciona-se as propriedades do botão de opção:

Image

e, na propriedade buttonGroup do botão de opção, introduz-se o nome do grupo no qual se pretende colocar o botão de opção, neste caso buttonGroup1. Repete-se esta operação para os 3 botões de opção.

O método principal dos botões de opção e das caixas de seleção é o método isSelected(), que indica se a caixa ou o botão está marcado. O texto associado ao componente pode ser obtido com getText() e definido com setText(String unTexte). A caixa de seleção/botão de opção pode ser marcada com o método setSelected(boolean value).

Ao clicar num botão de opção ou numa caixa de seleção, é desencadeado o evento actionPerformed. No código que se segue, utilizamos 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);

   /**Construir o quadro*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  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");

// os botões de opção estão agrupados
    buttonGroup1.add(jRadioButton1);
    buttonGroup1.add(jRadioButton2);
    buttonGroup1.add(jRadioButton3);

// caixas de seleção
    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);
      }
    });

    ....
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
        ...
  }

  private void afficheRadioButtons(ActionEvent e){
     // exibe os valores dos 3 botões de opção
    valeurs.addElement("boutons radio=("+jRadioButton1.isSelected()+","+
      jRadioButton2.isSelected()+","+jRadioButton3.isSelected()+")");
  }//afficheRadioButtons

  void afficheCases(ActionEvent e) {
     // exibe os valores das caixas de seleção
    valeurs.addElement("cases à cocher=["+jCheckBox1.isSelected()+","+
      jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
  }//afficheCases

}//classifica

Eis 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
um variador horizontal
2
JScrollBar
jScrollBar2
um variador vertical
3
JTextField
txtvaleurHS
exibe o valor do variador horizontal 1 — permite também fixar esse valor
4
JTextField
txtvaleurVS
exibe o valor do regulador vertical 2 - permite também fixar esse valor
  • Um regulador JScrollBar permite ao utilizador selecionar um valor dentro de um intervalo de valores inteiros, simbolizado pela «faixa» do regulador, na qual se desloca um cursor.
  • Num regulador horizontal, a extremidade esquerda representa o valor mínimo do intervalo, a extremidade direita o valor máximo e o cursor o valor atual selecionado. Num regulador vertical, o mínimo é representado pela extremidade superior e o máximo pela extremidade inferior. O par (mín., máx.) tem, por predefinição, o valor (0,100).
  • Um clique nas extremidades do regulador altera o valor num incremento (positivo ou negativo), dependendo da extremidade clicada, designada por unitIncrement, cujo valor predefinido é 1.
  • Um clique em cada lado do cursor altera o valor num incremento (positivo ou negativo), dependendo da extremidade clicada, designada por blockIncrement, cujo valor predefinido é 10.
  • Estes cinco valores (mín., máx., valor, unitIncrement, blockIncrement) podem ser obtidos através dos métodos getMinimum(), getMaximum(), getValue(), getUnitIncrement() e getBlockIncrement(), que devolvem todas um número inteiro e podem ser definidas através dos métodos setMinimum(int min), setMaximum(int max), setValue(int val), setUnitIncrement(int uInc), setBlockIncrement(int bInc)

Há alguns aspetos a ter em conta na utilização dos componentes JScrollBar. Em primeiro lugar, encontram-se na barra de componentes do Swing:

Image

Quando o arrastamos para o contentor, a orientação predefinida é vertical. Podemos torná-lo horizontal com a propriedade orientation abaixo:

Image

Na folha de propriedades acima, vemos que temos acesso às propriedades minimum, maximum, value, unitIncrement, blockIncrement do JScrollbar. Assim, é possível defini-las na fase de conceção. Quando se coloca uma barra de deslocamento no contentor, a sua «faixa de variação» não aparece:

Image

É possível resolver este problema atribuindo uma borda ao componente. Isto é feito através da sua propriedade border, que pode assumir diferentes valores:

Image

Eis o resultado, por exemplo, com RaisedBevel:

Image

Quando se clica na extremidade superior de um controlador vertical, o seu valor diminui. Isto pode surpreender o utilizador comum, que normalmente espera ver o valor «subir». Resolvemos este problema atribuindo um valor negativo a unitIncrement e a blockIncrement.

Como acompanhar as alterações de um controlador? Quando o valor deste se altera, ocorre o evento adjustmentValueChanged. Basta associar um procedimento a este evento para ser informado de cada variação do valor da barra de deslocamento.

Image

O código útil da 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;

   /**Construir o quadro*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  private void jbInit() throws Exception  {
...

// uma moldura para as barras de deslocamento
    border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.white,Color.white,new Color(134, 134, 134),new Color(93, 93, 93));
        // sem título na moldura
    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);
      }
    });

    ......
  }

   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
    // o valor da barra de deslocamento 1 alterou-se
    txtValeurHS.setText(""+jScrollBar1.getValue());
  }

  void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
    // o valor da barra de deslocamento 2 mudou
    txtValeurVS.setText(""+jScrollBar2.getValue());
  }

  void txtValeurHS_actionPerformed(ActionEvent e) {
    // fixamos o valor da barra de deslocamento horizontal
    setValeur(jScrollBar1,txtValeurHS);
  }

  void txtValeurVS_actionPerformed(ActionEvent e) {
    // fixa-se o valor da barra de deslocamento vertical
    setValeur(jScrollBar2,txtValeurVS);
  }

  private void setValeur(JScrollBar jS, JTextField jT){
     // fixa o valor da barra de deslocamento jS com o texto do campo jT
    int valeur=0;
    try{
      valeur=Integer.parseInt(jT.getText());
      jS.setValue(valeur);
    }
    catch (Exception e){
      // exibe o erro
      afficher(""+e);
    }//try-catch
  }//setValeur

  void afficher(String message){
    // exibe uma mensagem numa caixa
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//exibir

}

Eis 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 linha. Se este componente for colocado num contentor com barra de deslocamento (JScrollPane), obtém-se um campo de introdução de texto com barra de deslocamento. Este tipo de componente pode ser encontrado, por exemplo, numa aplicação de correio eletrónico, em que o texto da mensagem a enviar seria digitado num componente JTextArea. Os métodos habituais são String getText() para obter o conteúdo da área de texto, setText(String unTexte) para inserir unTexte na caixa de texto, e append(String unTexte) para adicionar unTexte ao texto já presente na caixa de texto. Consideremos a seguinte aplicação:

Image

n.º
tipo
nome
função
1
JTextArea
txtTexte
um campo de texto multilinha
2
JButton
cmdAfficher
exibe o conteúdo de 1 numa caixa de diálogo
3
JButton
cmdEffacer
apaga o conteúdo de 1
4
JTextField
txtAjout
texto adicionado ao texto de 1 quando validado com a tecla Enter.
5
JScrollPane
jScrollPane1
recipiente com rolagem no qual foi colocada a área de texto 1, de modo a obter uma área de texto com rolagem.

O código a utilizar é 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();

  /**Construir o quadro*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  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);
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
        ........
  }

  void cmdAfficher_actionPerformed(ActionEvent e) {
    // exibe o conteúdo de TextArea
    afficher(txtTexte.getText());
  }

    void afficher(String message){
     // exibe uma mensagem numa caixa
    JOptionPane.showMessageDialog(this,message,"Suivi",JOptionPane.INFORMATION_MESSAGE);
  }// exibir

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

  void txtAjout_actionPerformed(ActionEvent e) {
    // adicionar texto
    txtTexte.append(txtAjout.getText());
     // limpar adição
    txtAjout.setText("");
  }//
}

5.2.6. Eventos do rato

Quando se desenha num contentor, é importante saber a posição do rato para, por exemplo, exibir um ponto ao clicar. Os movimentos do rato provocam eventos no contentor em que se desloca. Aqui estão, por exemplo, os eventos propostos pelo JBuilder para um contentor JPanel:

Image

mouseClicked
clique do rato
mouseDragged
o rato desloca-se, botão esquerdo premido
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
Pressão no botão esquerdo do rato
mouseReleased
Soltar o botão esquerdo do rato

Eis um programa que permite compreender melhor em que momentos ocorrem os diferentes eventos do rato:

Image

n.º
tipo
nome
função
1
JTextField
txtPosition
para apresentar a posição do rato no contentor (eventualmente MouseMoved)
2
JList
lstAffichage
para apresentar os eventos do rato que não sejam MouseMoved
3
JButton
cmdEffacer
para apagar o conteúdo de 2

Ao executar este programa, eis o que se obtém com um clique:

Image

Os eventos são empilhados a partir do topo da lista. Assim, a captura de ecrã acima indica que um clique provoca três eventos, pela seguinte ordem:

  1. MousePressed ao premir o botão
  2. MouseReleased ao soltá-lo
  3. MouseClicked, o que indica que a sucessão dos dois eventos anteriores é considerada um clique. Poderia ser um duplo clique. Mas, acima, a informação clickCount=1 indica que se trata de um clique simples.

Agora, se premirmos o botão, deslocarmos o rato e soltarmos o botão:

Image

Vemos aqui os três eventos:

  1. MousePressed quando se clica inicialmente no botão
  2. MouseDragged ao mover o rato, com o botão pressionado
  3. MouseReleased ao soltar o botão

Nos dois exemplos acima, verifica-se que um evento do rato traz consigo várias informações, incluindo as coordenadas (x, y) do rato, por exemplo (408,65) na primeira linha acima.

Se continuarmos assim, 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 inverso ocorrerá quando o rato sair do componente para regressar ao contentor.

O que acontece quando se clica duas vezes?

Image

Temos exatamente os mesmos eventos que num clique simples. Apenas o evento traz consigo a informação clickCount=2 (ver acima), indicando que, na verdade, houve um duplo clique.

O código útil desta 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();

  /**Construir o quadro*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  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);

...............
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  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){
     // exibe o evento e na lista lstAffichage
    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) {
     // limpa a lista
    valeurs.removeAllElements();
  }
}

5.2.7. Criar uma janela com menu

Vamos agora ver como criar uma janela com menu utilizando o JBuilder. Vamos criar a seguinte janela:

Image

Image

Crie um novo projeto com uma janela vazia inicial. Na lista de componentes «Contenedores Swing», selecione o componente JMenuBar (ver Fig. 1 abaixo) e arraste-o para a janela que está a ser concebida.

Image

Não aparece nada na janela de conceção, 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 conceção:

Image

1
Inserir um elemento de menu
2
inserir um separador
3
inserir um menu aninhado
4
eliminar um elemento do menu
5
desativar um elemento do menu
6
elemento do menu para marcar
7
inverter o botão de opção

Para criar o seu primeiro elemento de menu, digite «Opções A» na caixa A acima e, em seguida, abaixo, por 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 o menu vai sendo concebido, a estrutura lógica da nossa janela evolui:

Image

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

Image

Terá então acesso às propriedades de this:

Image

Uma dessas propriedades é a JMenuBar, que serve para definir o menu que será associado à janela. Clique na célula à direita de JMenuBar. Ser-lhe-ão então apresentados todos os menus criados. Neste caso, teremos apenas o jMenuBar1. Selecione-o.

Inicie a execução da aplicação (F9):

Image

Agora, temos um menu, mas as opções, por enquanto, 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

Terá então 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 se clica num elemento do menu. É-lhe proposto, por predefinição, um procedimento de processamento. 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){
     // exibe uma mensagem numa caixa
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//exibir

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

Image

O código útil desta 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();

  /**Criar o quadro*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar o componente*/
  private void jbInit() throws Exception  {
        // a janela está associada a um 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);
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
....
  }

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

  void afficher(String message){
     // exibe uma mensagem numa caixa
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//exibir

}

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);
  }
}

gera a exibição da seguinte caixa:

Image

Quando se fecha esta janela, ela desaparece, mas o thread de execução no qual estava a ser executada não é interrompido. Este fenómeno não ocorre normalmente. As caixas de diálogo são utilizadas no âmbito de uma aplicação que, em determinado momento, utiliza uma instrução System.exit(n) para interromper todos os threads. Iremos recordar isto nos exemplos que se seguem, todos construídos segundo o mesmo modelo. No DOS, a aplicação pode ser interrompida com Ctrl-C. Com JBuilder, utilizar-se-á a opção Executar/Reiniciar o programa (Ctrl-F2). Além disso, o primeiro argumento de showMessageDialog é, neste caso, null. Em geral, não é esse o caso. É mais provável que seja this, em que this designa a janela principal da aplicação.

5.3.2. Aspecto e comportamento

A aparência da caixa acima pode ser diferente. É possível definir essa aparência através da classe javax.swing.UIManager. Quando comentámos o código gerado por JBuilder para a nossa primeira janela, deparámo-nos com uma instrução à qual não prestámos muita atenção:

      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 dispõe de um método que permite conhecer as «aparências» possíveis para as interfaces:

static UIManager.LookAndFeelInfo[]
getInstalledLookAndFeels()

O método devolve um array de elementos do tipo LookAndFeelInfo. Esta classe possui um método:

String
getClassName()

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

import javax.swing.*;

public class LookAndFeels {
  // exibe os «look and feels» disponíveis
  public static void main(String[] args) {
    // lista os «look and feels» instalados
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    // exibição
    for(int i=0;i<lf.length;i++){
      System.out.println(lf[i].getClassName());
    }//para
  }//principal
}//classificar

O código 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. Retomemos o nosso programa de exibição de mensagens, experimentando os diferentes aspectos possíveis:

import javax.swing.*;

public class LookAndFeel2 {
  // exibe os «look and feels» disponíveis
  public static void main(String[] args) {
    // lista dos «look and feels» instalados
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    // visualização
    for(int i=0;i<lf.length;i++){
      // gestor de aparência
      try{
        UIManager.setLookAndFeel(lf[i].getClassName());
      }catch(Exception ex){
        System.err.println(ex.getMessage());
      }//captura
      // mensagem
      JOptionPane.showMessageDialog(null,"Un message",lf[i].getClassName(),JOptionPane.INFORMATION_MESSAGE);
    }//for
  }//main
}//classe

A execução apresenta os seguintes resultados:

que correspondem, da direita para a esquerda, aos «looks» Metal, Motivo e Windows.

5.3.3. Caixas de confirmação

A classe JOptionPane possui um método showConfirmDialog para apresentar caixas de confirmação com os botões Oui, Non e Annuler. Existem vários métodos showConfirmDialog sobrecarregados. Vamos analisar um deles:

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
title
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

Eis um exemplo:

import javax.swing.*;

public class confirm1 {
  public static void main(String[] args) {
    // exibe caixas de confirmação
    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));
  }//principal

  private static void affiche(int réponse){
     // indica que tipo de resposta foi recebida
    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;
    }//
  }//ecrã
}//classificar

Na consola, são exibidas as mensagens Non e Annuler.

5.3.4. Campo de introdução

A classe JOptionPane também oferece a possibilidade de efetuar uma entrada com 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á foram apresentados várias vezes. O método devolve a cadeia de caracteres introduzida pelo utilizador. Eis um exemplo:

import javax.swing.*;

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

Apresentação da caixa de introdução de dados:

Image

A visualização da consola:

Chaîne saisie [dupont]

5.4. Caixas de seleção

Vamos agora analisar algumas caixas de seleção predefinidas no Java 2:

JFileChooser
caixa de seleção que permite selecionar um ficheiro na árvore de ficheiros
JColorChooser
caixa de seleção que permite escolher uma cor

5.4.1. Caixa 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
Conténcer deslizante para a caixa de texto 1
1
O próprio JTextArea no JScrollPane
txtTexte
texto digitado pelo utilizador ou carregado a partir de um ficheiro
2
JButton
btnSauvegarder
permite guardar o texto de 1 num ficheiro de texto
3
JButton
btnCharger
permite carregar o conteúdo de um ficheiro de texto em 1
4
JButton
btnEffacer
apaga o conteúdo de 1

É utilizada uma verificação não visual: jFileChooser1. Esta é selecionada na paleta de contentores Swing de JBuilder:

Image

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

Image

Apresentamos agora o código relevante do programa para se ter 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 {
   // os componentes do quadro
  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();

  // os filtros de ficheiros
  javax.swing.filechooser.FileFilter filtreTxt = null;

   //Construir o quadro
  public dialogues() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
       // outras inicializações
      moreInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

   // moreInit
  private void moreInit(){
     // inicializações aquando da construção da janela
     // filtro *.txt
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // aceita-se «f»?
        return f.getName().toLowerCase().endsWith(".txt");
      }//aceitar
      public String getDescription(){
        // descrição do filtro
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // adiciona-se o filtro
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // também queremos o filtro para todos os ficheiros
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // definimos o diretório inicial da caixa FileChooser como o diretório atual
    jFileChooser1.setCurrentDirectory(new File("."));
  }

   //Inicializar o componente
  private void jbInit() throws Exception  {
.......................
  }
   //Substituído, para que possamos sair quando a janela for fechada
  protected void processWindowEvent(WindowEvent e) {
......................
    }
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // escolha de um ficheiro utilizando um objeto JFileChooser

     // definimos o filtro inicial
    jFileChooser1.setFileFilter(filtreTxt);
     // exibe-se a caixa de seleção
    int returnVal = jFileChooser1.showOpenDialog(this);
    // O utilizador selecionou alguma coisa?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // coloca-se o ficheiro no campo de texto
       lireFichier(jFileChooser1.getSelectedFile());
    }//if
  }//btnCharger_actionPerformed

  // lireFichier
  private void lireFichier(File fichier){
     // exibe o conteúdo do ficheiro de texto «ficheiro» no campo de texto

     // limpa o campo de texto
    txtTexte.setText("");

     // algumas dados
    BufferedReader IN=null;
    String ligne=null;
    try{
      // abre o ficheiro em modo de leitura
      IN=new BufferedReader(new FileReader(fichier));
      // lê-se o ficheiro linha a linha
      while((ligne=IN.readLine())!=null){
        txtTexte.append(ligne+"\n");
      }//while
       // fecho do ficheiro
      IN.close();
    }catch(Exception ex){
       // ocorreu um erro
      txtTexte.setText(""+ex);
    }//catch
  }

  // limpar
  void btnEffacer_actionPerformed(ActionEvent e) {
    // a caixa de texto está a ser apagada
    txtTexte.setText("");
  }

   // guardar
  void btnSauvegarder_actionPerformed(ActionEvent e) {
     // guarda o conteúdo da caixa de texto num ficheiro

     // define o filtro inicial
    jFileChooser1.setFileFilter(filtreTxt);
     // exibe a caixa de seleção de gravação
    int returnVal = jFileChooser1.showSaveDialog(this);
    // O utilizador selecionou alguma opção?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // escreve-se o conteúdo da caixa de texto num ficheiro
       écrireFichier(jFileChooser1.getSelectedFile());
    }//if
  }

   // lireFichier
  private void écrireFichier(File fichier){
     // escreve o conteúdo da caixa de texto num ficheiro

     // algumas dados
    PrintWriter PRN=null;
    try{
       // abertura do ficheiro para escrita
      PRN=new PrintWriter(new FileWriter(fichier));
      // escreve o conteúdo da caixa de texto
      PRN.print(txtTexte.getText());
       // fecha o ficheiro
      PRN.close();
    }catch(Exception ex){
       // ocorreu um erro
      txtTexte.setText(""+ex);
    }//catch
  }

Não iremos comentar o código dos métodos btnEffacer_Click, lireFichier e écrireFichier, uma vez que não trazem nada que já não tenha sido visto. Vamos debruçar-nos sobre a classe JFileChooser e a sua utilização. Esta classe é complexa, do tipo «muito complicada». Aqui, utilizamos apenas os seguintes métodos:

addChoosableFilter(FileFilter)
define os tipos de ficheiros propostos para seleção
setAcceptAllFileFilterUsed(boolean)
indica se o tipo «Todos os ficheiros» deve ou não ser apresentado para seleção
File getSelectedFile()
o ficheiro (File) selecionado pelo utilizador
int showSaveDialog()
método que apresenta a caixa de seleção para guardar. Devolve um resultado do tipo int. O valor jFileChooser.APPROVE_OPTION indica que o utilizador efetuou uma escolha válida. Caso contrário, ou o utilizador cancelou a escolha, 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 apresenta uma caixa de seleção semelhante à seguinte:

Image

1
lista suspensa criada com o método addChoosableFilter. Esta contém os chamados filtros de seleção, representados pela classe FileFilter. Cabe ao programador definir esses filtros e adicioná-los à lista 1.
2
pasta atual, definida pelo método setCurrentDirectory, caso este método tenha sido utilizado; caso contrário, a pasta 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 com o método getSelectedFile()
4
Botões «Guardar»/«Anular». Se for utilizado o botão Enregistrer, o método showSaveDialog devolve o resultado jFileChooser.APPROVE_OPTION

Como são criados os filtros de ficheiros da lista suspensa 1? Os filtros são adicionados à lista 1 através do método:

addChoosableFilter(FileFilter)
define os tipos de ficheiros propostos para seleção

da classe JFileChooser. Resta-nos conhecer a classe FileFilter. Na verdade, trata-se da classe javax.swing.filechooser.FileFilter, que é uma classe abstrata, c.a.d — 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 pertence 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 os ficheiros *.txt com a descrição «Ficheiros de texto (*.txt)».

  • Temos de criar uma classe derivada da classe FileFilter
  • utilizar o método boolean accept(File f) para devolver o valor true se o nome do ficheiro f terminar em .txt
  • utilizar o método String getDescription() para apresentar a descrição «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){
      // aceita-se f?
      return f.getName().toLowerCase().endsWith(".txt");
    }//aceitar
    public String getDescription(){
      // descrição do filtro
      return "Fichiers Texte (*.txt)";
    }//getDescription
  };

Este filtro seria adicionado à lista de filtros do objeto jFileChooser1 através da instrução:

     // adiciona-se o filtro *.txt
    jFileChooser1.addChoosableFileFilter(filtretxt);

Tudo isto e algumas outras inicializações são efetuadas no método moreInit, executado aquando da criação da janela (ver programa completo acima). O código do botão Sauvegarder é o seguinte:

  void btnSauvegarder_actionPerformed(ActionEvent e) {
    // guarda o conteúdo da caixa de texto num ficheiro

     // define-se o filtro inicial
    jFileChooser1.setFileFilter(filtreTxt);
     // exibe a caixa de seleção para guardar
    int returnVal = jFileChooser1.showSaveDialog(this);
    // O utilizador selecionou alguma opção?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // escreve-se o conteúdo da caixa de texto num ficheiro
       écrireFichier(jFileChooser1.getSelectedFile());
    }//if
  }

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

  • define-se o filtro ativo como *.txt, para permitir que o utilizador procure preferencialmente este tipo de ficheiros. O filtro «Todos os ficheiros» também está presente. Foi adicionado no procedimento moreInit. Temos, portanto, dois filtros.
  • É apresentada a caixa de seleção para gravação. Aqui, perdemos o controlo, uma vez que o utilizador utiliza a caixa de seleção para indicar um ficheiro do sistema de ficheiros.
  • Quando o utilizador sai da caixa de seleção, verifica-se o valor de retorno para determinar se a caixa de texto deve ou não ser guardada. Se sim, 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) {
    // escolha de um ficheiro utilizando um objeto JFileChooser

     // define-se o filtro inicial
    jFileChooser1.setFileFilter(filtreTxt);
     // exibe-se a caixa de seleção
    int returnVal = jFileChooser1.showOpenDialog(this);
    // O utilizador selecionou alguma coisa?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // coloca-se o ficheiro no campo de texto
       lireFichier(jFileChooser1.getSelectedFile());
    }//if
  }//btnCharger_actionPerformed

Existem duas diferenças:

  • para apresentar a caixa de seleção de ficheiros, utiliza-se o método showOpenDialog em vez do método showSaveDialog. A caixa de seleção apresentada é semelhante à apresentada pelo método showSaveDialog.
  • Se o utilizador tiver selecionado corretamente um ficheiro, é chamado o método lireFichier em vez do método écrireFichier.

5.4.1.1. Caixas de seleção JColorChooser e JFontChooser

Continuamos o exemplo anterior, adicionando dois novos botões:

Image

N.º
tipo
nome
função
6
JButton
btnCouleur
para definir a cor dos caracteres do TextBox
7
JButton
btnPolice
para definir o tipo de letra do TextBox

O componente JColorChooser, que permite apresentar uma caixa de seleção de cor, pode ser encontrado na lista de componentes Swing do 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. A caixa de seleção de cores é exibida com o método int showDialog:

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

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

  void btnCouleur_actionPerformed(ActionEvent e) {
     // escolha de uma cor de texto utilizando o componente JColorChooser
    Color couleur;
    if((couleur=jColorChooser1.showDialog(this,"Choix d'une couleur",Color.BLACK))!=null){
       // definir a cor dos caracteres da caixa de texto
      txtTexte.setForeground(couleur);
    }//if
  }

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

Image

Curiosamente, a biblioteca Swing não oferece nenhuma classe para selecionar um tipo de letra. Felizmente, existem recursos Java disponíveis na Internet. Ao pesquisar a palavra-chave «JFontChooser», que parece ser um nome possível para uma classe desse tipo, encontram-se várias opções. O exemplo que se segue dar-nos-á a oportunidade de configurar o JBuilder para que utilize pacotes não previstos na sua configuração inicial.

O pacote recuperado chama-se swingextras.jar e foi colocado na pasta <jdk>\jre\lib\perso, em que <jdk> designa o 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

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

Image

Deste arquivo, é importante notar que a classe JFontChooser se chama, na realidade, com.lamatek.swingextras.JFontChooser. Se não quisermos escrever o nome completo, teremos de escrever no início do programa:

import com.lamatek.swingextras.*;

Como é que o compilador e a máquina virtual Java irão localizar este novo pacote? No caso da utilização direta do JDK, isto já foi explicado e o leitor poderá consultar as explicações no parágrafo sobre os pacotes Java. Apresentamos aqui em pormenor o método a utilizar com o JBuilder. Os pacotes são configurados no menu Opções/Configurar o JDK:

Image

1
O botão Modifier (1) permite indicar ao JBuilder qual o JDK a utilizar. Neste exemplo, o JBuilder trouxe consigo o JDK 1.3.1. Quando o JDK 1.4 foi lançado, foi instalado separadamente do JBuilder e utilizou-se o botão Modifier para indicar ao JBuilder queutilizar doravante o JDK 1.4, indicando o diretório de instalação deste último
2
diretório raiz do JDK, atualmente utilizado pelo JBuilder
3
lista dos arquivos Java (.jar) utilizados pelo JBuilder. É possível adicionar outros através do botão Ajouter (4)
4
O botão Ajouter (4) permite adicionar novos pacotes que o JBuilder utilizará tanto para a compilação como para a execução dos programas. Utilizámo-lo aqui para adicionar o pacote SwingExtras.jar (5)

Agora, o JBuilder está corretamente configurado para poder utilizar a classe JFontChooser. No entanto, precisaríamos de ter acesso à definição dessa classe para a utilizar corretamente. O arquivo swingextras.jar contém ficheiros HTML que poderíamos extrair para os utilizar. Isso é desnecessário. A documentação Java incluída nos ficheiros .jar está diretamente acessível a partir de JBuilder. Para tal, é necessário configurar o separador Documentation (6) acima. Obtém-se a seguinte nova janela:

Image

O botão Ajouter permite-nos indicar que o ficheiro SwingExtras.jar deve ser analisado para obter a documentação. Após a validação deste procedimento, verifica-se que temos efetivamente acesso à documentação do SwingExtras.jar. Isto traduz-se em várias facilidades:

  • se começarmos a escrever a instrução de importação
import com.lamatek.swingextras.*;

, verificamos que o JBuilder nos fornece uma ajuda:

Image

O pacote com.lamatek foi encontrado.

  • Se agora passarmos para o seguinte programa:
import com.lamatek.swingextras.*;

public class test{
  JFontChooser jFontChooser1=null;
}  

Ao pesquisar «F1» com a palavra-chave «JFontChooser», obtém-se ajuda sobre esta classe:

Image

Vemos na barra de estado 1 que é, de facto, um ficheiro HTML do pacote swingextras.jar que está a ser utilizado. O exemplo apresentado acima é suficientemente explícito para que possamos escrever o código do botão Police da nossa aplicação:

  void btnPolice_actionPerformed(ActionEvent e) {
    // escolha de um tipo de letra para o texto utilizando o componente JFontChooser
    jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
    if (jFontChooser1.showDialog(this, "Choix d'une police") == JFontChooser.ACCEPT_OPTION) {
      // alterar o tipo de letra da caixa de texto
      txtTexte.setFont(jFontChooser1.getSelectedFont());
    }//if
  }

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

Image

5.5. A aplicação gráfica IMPOTS

Retomamos a aplicação IMPOTS, que já foi abordada duas vezes. Acrescentamos agora uma interface gráfica:

Image

Os controlos são os seguintes

n.º
tipo
nome
função
1
JRadioButton
rdOui
assinalar se for casado
2
JRadioButton
rdNon
marcar se não for casado
3
JSpinner
spinEnfants
número de filhos do contribuinte
Mínimo=0, Máximo=20, Incremento=1
4
JTextField
txtSalaire
salário anual do contribuinte em F
5
JLabel
lblImpots
montante do imposto a pagar
6
JTextField
txtStatus
campo de mensagens de estado - não editável

O menu é o seguinte:

opção principal
opção secundária
nome
função
Impostos
   
 
Inicializar
mnuInitialiser
carrega os dados necessários para o cálculo a partir de um ficheiro de texto
 
Calcular
mnuCalculer
calcula o imposto a pagar quando todos os dados necessários estão presentes e corretos
 
Apagar
mnuEffacer
repor o formulário ao seu estado inicial
 
Sair
mnuQuitter
encerra a aplicação

Regras de funcionamento

  • o menu Calculer permanece desativado enquanto não houver nada no campo do salário
  • se, quando o cálculo for iniciado, se verificar que o salário está incorreto, o erro é sinalizado:

Image

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

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 {
  // os componentes da janela
  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;

   // os atributos da classe
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;

   //Construir o quadro
  public frmImpots() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // outras inicializações
    moreInit();
  }

   // inicialização do formulário
  private void moreInit(){
     // menu «Calcular» desativado
    mnuCalculer.setEnabled(false);
    // campos de introdução de dados desativados
    txtSalaire.setEditable(false);
    txtSalaire.setBackground(Color.WHITE);
    // campo de estado
    txtStatus.setBackground(Color.WHITE);
    // spinner «Filhos» — entre 0 e 20 filhos
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);
     // filtro *.txt para a caixa de seleção
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // aceita-se «f»?
        return f.getName().toLowerCase().endsWith(".txt");
      }//aceitar
      public String getDescription(){
        // descrição do filtro
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // adiciona-se o filtro *.txt
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // também queremos o filtro para todos os ficheiros
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // definimos o diretório inicial da caixa FileChooser
    jFileChooser1.setCurrentDirectory(new File("."));
  }//moreInit

   //Inicializar o componente
  private void jbInit() throws Exception  {

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

  }

   //Substituído, para que possamos sair quando a janela for fechada
  protected void processWindowEvent(WindowEvent e) {
.....................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // sai-se da aplicação
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // carregamos o ficheiro de dados
     // que selecionamos com a caixa de seleção JFileChooser1
    jFileChooser1.setFileFilter(filtreTxt);
    if (jFileChooser1.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION)
      return;
     // o ficheiro selecionado é processado
    try{
       // leitura de dados
      lireFichier(jFileChooser1.getSelectedFile());
       // criação do objeto «impostos»
      objImpots=new impots(limites,coeffr,coeffn);
       // confirmação
      txtStatus.setText("Données chargées");
       // o salário pode ser alterado
      txtSalaire.setEditable(true);
       // não é possível efetuar mais alterações
      mnuInitialiser.setEnabled(false);
    }catch(Exception ex){
       // problema
      txtStatus.setText("Erreur : " + ex.getMessage());
      // fim
      return;
    }//captura
  }

  private void lireFichier(File fichier) throws Exception {
     // as tabelas de dados
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // abertura do ficheiro em modo de leitura
    BufferedReader IN=new BufferedReader(new FileReader(fichier));
    // o ficheiro é lido linha a linha
     // têm o formato limite coeffr coeffn
    String ligne=null;
    int numLigne=0;           // n.º da linha atual
    while((ligne=IN.readLine())!=null){
      // mais uma linha
      numLigne++;
       // a linha é dividida em campos
      champs=ligne.split("\\s+");
       // 3 campos?
      if(champs.length!=3)
        throw new Exception("ligne " + numLigne + "erronée dans fichier des données");
       // recuperam-se os três campos
       aLimites.add(champs[0]);
       aCoeffR.add(champs[1]);
       aCoeffN.add(champs[2]);
    }//while
     // fechar ficheiro
    IN.close();
     // transferência dos dados para tabelas delimitadas
    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) {
    // cálculo do imposto
     // verificação do salário
    int salaire=0;
    try{
      salaire=Integer.parseInt(txtSalaire.getText().trim());
      if(salaire<0) throw new Exception();
    }catch (Exception ex){
       // mensagem de erro
      txtStatus.setText("Salaire incorrect. Recommencez");
       // foco no campo com erro
      txtSalaire.requestFocus();
       // regresso à interface
      return;
    }
     // número de filhos
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     // cálculo do imposto
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),InbEnfants.intValue(),salaire));
     // apagar mensagem de estado
    txtStatus.setText("");
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
     // o salário alterou-se — atualiza-se o menu «Calcular»
    mnuCalculer.setEnabled(! txtSalaire.getText().trim().equals(""));
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
    // limpar o formulário
    rdNon.setSelected(true);
    spinEnfants.getModel().setValue(new Integer(0));
    txtSalaire.setText("");
    mnuCalculer.setEnabled(false);
    lblImpots.setText("");
  }
}

Utilizámos aqui um componente disponível apenas a partir da versão 1.4 do JDK, o JSpinner. Trata-se de um incrementador, que 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 o teste. Isso não impede a sua utilização, embora o processo seja um pouco mais complicado do que no caso dos componentes disponíveis na barra de componentes. Com efeito, não é possível colocar o componente JSpinner no formulário durante a fase de conceção. É necessário fazê-lo durante a execução. Vejamos o código que o faz:

     // spinner «Filhos» — entre 0 e 20 filhos
    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 diversos fins e não apenas como um incrementador de números inteiros, como neste caso. O argumento do construtor JSpinner é, neste caso, um modelo de incrementador de números que aceita quatro parâmetros (valor, mínimo, máximo, incremento). O componente tem a seguinte forma:

Image

valeur
valor inicial apresentado no componente
min
valor mínimo exibível no componente
max
valor máximo exibível no componente
incrément
valor de incremento do valor exibido quando se utilizam 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. Daí a necessidade de algumas conversões de tipo para obter o inteiro de que precisamos:

     // número de filhos
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     // cálculo do imposto
    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);

Antes de mais nada, o utilizador deve utilizar a opção de menu Initialiser, que cria um objeto impots com o construtor

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

da classe impots. Recorde-se que esta foi definida como exemplo no capítulo sobre classes. Consulte-o, se necessário. As três tabelas necessárias ao 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
15640
0,1
1290,5
24 740
0,15
2072,5
31 810
0,2
3309,5
39 970
0,25
4900
48 360
0,3
6898,5
55 790
0,35
9316,5
92 970
0,4
12106
127 860
0,45
16 754,5
151 250
0,50
23 147,5
172 040
0,55
30710
195 000
0,60
39312
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 do tipo impots, basta deixar que o utilizador forneça as três informações necessárias: casado ou solteiro, número de filhos, salário anual, e chamar o método calculer da classe impots. A operação pode ser repetida várias vezes. O objeto do tipo impots, por sua vez, é criado apenas uma vez, ao utilizar a opção Initialiser.

5.6. Criação de applets

5.6.1. Introdução

Quando se cria uma aplicação com interface gráfica, é bastante fácil transformá-la em applet. Armazenada num computador A, esta pode ser descarregada através de um navegador da Web a partir de um computador B ligado à Internet. A aplicação inicial é assim partilhada entre vários utilizadores e é aí que reside o principal interesse de transformar uma aplicação num applet. No entanto, nem todas as aplicações podem ser transformadas desta forma: para não prejudicar o utilizador que utiliza um applet no seu navegador, o ambiente do applet é regulamentado:

  • um applet não pode ler nem escrever no disco do utilizador
  • só pode comunicar com o computador a partir do qual foi descarregada pelo navegador.

Trata-se de restrições rigorosas. Implicam, por exemplo, que uma aplicação que necessite de ler informações num ficheiro ou numa base de dados terá de as solicitar através de uma aplicação intermediária 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, geralmente através de um navegador. Este documento pode conter um applet que funcionará como uma aplicação gráfica autónoma no seio do documento HTML exibido pelo navegador do cliente.
  • Este applet poderá ter acesso a dados, mas apenas aos que se encontram no servidor Web. Não terá acesso nem aos recursos do computador do cliente que o executa, nem aos de outros computadores da rede, para além daquele a partir do qual foi descarregado.

5.6.2. A classe JApplet

5.6.2.1. Définition

Uma aplicação pode ser descarregada 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 deriva da classe Container. Uma instância Applet ou JApplet, sendo do tipo container, poderá, portanto, conter componentes (Component) tais como botões, caixas de seleção, listas, etc. Apresentamos algumas indicações 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 (documento HTML no qual se encontra, outros applets do mesmo documento, …)
public String getAppletInfo();
retorna uma cadeia de caracteres com informações sobre o applet
public AudioClip getAudioClip(URL url);
carrega o ficheiro de áudio especificado por URL
public AudioClip getAudioClip(URL url, String name);
carrega o ficheiro de áudio especificado por URL/name
public URL getCodeBase();
retorna o URL do applet
public URL getDocumentBase();
retorna o URL do documento HTML que contém o applet
public Image getImage(URL url);
recupera a imagem especificada por URL
public Image getImage(URL url, String name);
recupera a imagem especificada por URL/name
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 é executado pelo navegador aquando do arranque inicial do applet
public boolean isActive();
estado do applet
public void play(URL url);
reproduz o ficheiro de som especificado por URL
public void play(URL url, String name);
reproduz o ficheiro de som especificado por UR/name
public void resize(Dimension d);
define as dimensões do quadro do applet
public void resize(int width, int height);
idem
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 é executado pelo navegador sempre que o documento que contém o applet é apresentado
public void stop();
este método é executado pelo navegador sempre que o documento que contém o applet é abandonado em favor de outro (mudança de URL pelo utilizador)

A classe JApplet introduziu algumas melhorias na classe Applet, nomeadamente a capacidade de conter componentes JMenuBar e c.a.d. dos menus, o que não era possível com a classe Applet.

5.6.2.2. Execução de um applet: os métodos init, start e stop

Quando um navegador carrega um applet, chama três métodos do mesmo:

init
Este método é chamado durante o carregamento inicial do applet. Nele, devem ser colocadas 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 ativo do navegador. Assim, quando um utilizador carrega um applet, os métodos init e start serão executados por esta ordem. Quando o utilizador sair do documento para visualizar outro, o método stop será executado. Quando regressar a esse documento 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 sejam executadas em paralelo e de forma contínua, muitas vezes sem o conhecimento do utilizador. Quando este sai do documento, a parte visível da aplicação desaparece, mas essas tarefas em segundo plano continuam a funcionar. Muitas vezes, isso é desnecessário. Aproveita-se, então, a chamada do navegador ao método stop para as parar. Se o utilizador regressar ao documento, aproveita-se 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 é mantido por uma tarefa em segundo plano (thread). Quando, no navegador, o utilizador sai da página do applet, é desnecessário manter o relógio, que se tornou invisível: no método «stop» do applet, interromper-se-á o thread que gere o relógio. No método «start», reiniciá-la-emos para que, quando o utilizador regressar à página do applet, encontre um relógio com a hora certa.

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

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


public class application{
    
    public static main void(String arg[]){
        
    }
    
}// fim da classe

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

import java.applet.JApplet;

public class application extends JApplet{
    
    public void init(){
        
    }
    
}// fim da turma

É de salientar o seguinte:

  1. a classe application deriva agora da classe JApplet
  2. o método main é substituído pelo método init.

A título de exemplo, voltamos a uma aplicação já analisada: a gestão de listas.

Image

Os componentes desta janela são os seguintes:

n.º
tipo
nome
função
1
JTextField
txtSaisie
campo de introdução
2
JList
jList1
lista contida num contentor jScrollPane1
3
JList
jList2
lista contida num contentor jScrollPane2
4
JButton
cmd1To2
transfere os elementos selecionados da lista 1 para a lista 2
5
JButton
cmd2To1
faz o inverso
6
JButton
cmdRaz1
esvazia a lista 1
7
JButton
cmdRaz2
esvazia a 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();

   /**Criar o quadro*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Inicializar o componente*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // O Jlist1 é colocado no contentor jScrollPane1
    jScrollPane1.getViewport().add(jList1, null);
        // Jlist2 é colocado no contentor jScrollPane2
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**Substituído, para que possamos sair quando a janela for fechada*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//classe
  void cmd1To2_actionPerformed(ActionEvent e) {
..........
  }//transferência
  void cmdRaz1_actionPerformed(ActionEvent e) {
    // esvaziar a lista 1
    v1.removeAllElements();
  }//comando Raz1

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

Para transformar a classe appli em applet, deve-se proceder da seguinte forma:

  • alterar a classe anterior interfaceAppli para que deixe de derivar de JFrame e passe a derivar de JApplet:
public class interfaceAppli extends JApplet {
  • eliminar a instrução que define o título da janela JFrame. Um applet JApplet não tem barra de título
    // this.setTitle("JList");
  • Alterar o construtor para um método init e, nesse método, eliminar o tratamento dos eventos da janela (WindowListener, ...). Um applet é um contentor que não pode ser redimensionado nem fechado.
   /**Construir o quadro*/
  public init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli
  • O método processWindowEvent deve ser eliminado ou colocado em comentários
   /**Substituído, para que possamos sair quando a janela estiver fechada*/
  //protected void processWindowEvent(WindowEvent e) {
  //  super.processWindowEvent(e);
  //  if (e.getID() == WindowEvent.WINDOW_CLOSING) {
  //    System.exit(0);
  //  }
  // }

Apresentamos, a título de exemplo, o código completo do applet, exceto 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();

   /**Construir o quadro*/
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Inicializar o componente*/
  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) {
     // o texto introduzido foi validado
     // recuperamo-lo sem os espaços no início e no fim
    String texte=txtSaisie.getText().trim();
     // se estiver vazio, não o aceitamos
    if(texte.equals("")){
      // mensagem de erro
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // fim
      return;
    }//se
    // se não estiver vazio, adiciona-se aos valores da lista 1
    v1.addElement(texte);
     // e esvazia-se o campo de introdução
    txtSaisie.setText("");
  }

  void cmd1To2_actionPerformed(ActionEvent e) {
    // transferência dos elementos selecionados da lista 1 para a lista 2
    transfert(jList1,jList2);
  }//cmd1To2

  private void transfert(JList L1, JList L2){
      // transferência dos elementos selecionados da lista 1 para a lista 2
       // recupera-se a tabela de índices dos elementos selecionados em L1
      int[] indices=L1.getSelectedIndices();
      // há algo a fazer?
      if (indices.length==0) return;
      // recuperam-se os valores de L1
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      // e os de L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // adiciona-se a L2 os valores selecionados em L1
        v2.addElement(v1.elementAt(indices[i]));
        // os elementos de L1 copiados para L2 devem ser eliminados de L1
        v1.removeElementAt(indices[i]);
      }//para
  }//transferência

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

  void cmd2To1_actionPerformed(ActionEvent e) {
    // transferência dos elementos selecionados em jList2 para jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // esvaziar a lista 1
    v1.removeAllElements();
  }//comando Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // vazio lista 2
    v2.removeAllElements();
  }//comando Raz2

}//classe

É possível compilar o código-fonte deste applet. Fazemo-lo aqui com 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 com o programa AppletViewer do JDK, que permite executar applets ou um navegador. Para tal, é necessário criar o documento HTML appli.htm, que conterá o applet:

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

Temos aqui um documento HTML clássico, exceto pela presença da tag applet. Esta foi utilizada 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 o ficheiro appli.htm ter sido gravado, pode ser carregado com o programa appletviewer do JDK ou com um navegador. Digite na janela do DOS o seguinte comando na pasta do ficheiro appli.htm:

appletviewer appli.htm

Partimos do princípio de que o diretório do executável appletviewer.exe se encontra no PATH da janela do DOS; caso contrário, seria necessário indicar o caminho completo do executável appletviewer.exe. Obtém-se a seguinte janela:

Image

Interrompemos a execução do applet com a opção Applet/Quitter. Vamos agora testar o applet com um navegador. Este deve utilizar uma máquina virtual Java 2 para poder apresentar os componentes Swing. Até recentemente (2001), esta restrição representava um problema, uma vez que a Sun produzia JDK que os editores de navegadores só acompanhavam com grande atraso. Por fim, a Sun eliminou este obstáculo ao disponibilizar aos utilizadores uma aplicação chamada «Java plugin», que permite aos navegadores Internet Explorer e Netscape Navigator utilizarem as versões mais recentes do JRE produzidas pela Sun (JRE = Java Runtime Environment). Os testes que se seguem foram realizados com o IE 5.5 equipado com o plugin Java 1.4.

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

Image

Pelo URL (1), verifica-se que 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 opção de formatação <applet> num documento HTML

Vimos que, num documento HTML, o applet era referenciado pela tag de formatação <applet>. Esta tag pode ter vários parâmetros:

<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
code
obrigatório - nome do ficheiro .class a executar
width
obrigatório - largura do applet no documento
height
obrigatório - altura …
codebase
opcional - URL do diretório que contém o applet a ser executado. Se o «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 no documento
hspace
opcional - margem horizontal em torno do applet, expressa em píxeis
vspace
opcional - margem vertical em torno do applet, expressa em píxeis
alt
opcional - texto exibido no lugar do applet caso o navegador não consiga carregá-lo
param
opcional - parâmetro passado ao applet que especifica o seu nome (name) e o seu valor (value). O applet poderá recuperar o valor do parâmetro nome1 através de val1=getParameter("nome1")
É possível utilizar quantos parâmetros se quiser
texte
opcional — será exibido por qualquer navegador incapaz de executar um applet, por exemplo, por não dispor de uma máquina virtual Java.

Vejamos 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 do applet interfaceParams foi gerado conforme indicado anteriormente. Foi criada uma aplicação JBuilder e, em seguida, foram efetuadas as 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);

  //Construir o quadro
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // outras inicializações
    moreInit();
  }

   // inicializações
  public void moreInit(){
     // exibe os valores dos parâmetros do applet
    params.addElement("nom=param1 valeur="+getParameter("param1"));
    params.addElement("nom=param2 valeur="+getParameter("param2"));
  }//mais inicializações

   //Inicializar o componente
  private void jbInit() throws Exception  {
............
    this.setSize(new Dimension(205, 156));
    //this.setTitle("Parâmetros de um applet");
    jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
 }
}

A execução com AppletViewer:

Image

5.6.5. Aceder a recursos remotos a partir de um applet

Muitas aplicações têm de utilizar informações presentes em ficheiros ou bases de dados. Já referimos que um applet não tem acesso aos recursos do computador em que é executado. Trata-se de uma medida de bom senso. Caso contrário, bastaria escrever um applet para «espiar» o disco dos utilizadores que o carregam. No entanto, o applet tem acesso aos recursos do servidor a partir do qual foi descarregado, por exemplo, ficheiros. É isso que vamos ver agora.

5.6.5.1. A classe URL

Qualquer aplicação Java pode ler um ficheiro presente numa máquina da rede graças à classe java.net.URL (URL = Uniform Resource Locator). Um URL identifica um recurso da rede, o computador em que 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 designa o ficheiro index.html da 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 do serviço http.

Vamos detalhar alguns dos elementos da classe URL:

public URL(String spec)
cria uma instância de URL a partir de uma cadeia de caracteres do tipo «protocolo:porta//máquina/ficheiro» — lança uma exceção se a sintaxe da cadeia de caracteres não corresponder a um URL
  
public String getFile()
permite obter o campo «ficheiro» da cadeia «protocolo:porta//máquina/ficheiro» do URL
  
public String getHost()
permite obter o campo «máquina» da cadeia «protocolo:porta//máquina/ficheiro» do URL
  
public String getPort()
permite obter o campo «porta» da cadeia «protocolo:porta//máquina/ficheiro» do URL
  
public String getProtocol()
permite obter o campo «protocolo» da cadeia «protocolo:porta//máquina/ficheiro» do URL
  
public URLConnection openConnection()
abre a ligação com a máquina remota getHost() na sua porta getPort(), de acordo com o protocolo getProtocol(), com o objetivo de ler o ficheiro getFile(). Lança uma exceção se não for possível estabelecer a ligação
  
public final InputStream openStream()
abreviatura de openConnection().getInputStream(). Permite obter um fluxo de entrada a partir do qual o conteúdo do ficheiro getFile() poderá ser lido. Lança uma exceção se não for possível obter o fluxo
  
public String toString()
exibe a identidade da instância de URL

Existem aqui dois métodos que nos interessam:

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

5.6.5.2. Um exemplo de consola

Vamos escrever um programa Java, sem interface gráfica, encarregado de apresentar no ecrã o conteúdo de um URL que lhe é 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.*;             // para a classe URL
import java.io.*;                // para os fluxos (stream)

public class urlcontenu{

// exibe o conteúdo do URL passado como argumento
// este conteúdo deve ser texto para poder ser lido

  public static void main (String arg[]){
    // verificação dos argumentos
    if(arg.length==0){
      System.err.println("Syntaxe pg url");
      System.exit(0);
    }
    
    try{
      // criação do URL      
      URL url=new URL(arg[0]);
      // leitura do conteúdo
      try{
        // criação do fluxo de entrada
        BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
        try{
          // leitura das linhas de texto no fluxo de entrada
          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);
    }
  }// fim da função main
}// fim da classe

Depois de verificar se existe efetivamente um argumento, tenta-se criar um URL com esse argumento:


// criação do URL      
      URL url=new URL(arg[0]);

Esta criação pode falhar se o argumento não respeitar a sintaxe dos URL protocole:port//machine/fichier. 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 fluxo do tipo InputStream, que é um fluxo orientado por caracteres: a leitura é feita caractere a caractere e é necessário formar as linhas manualmente. Para poder ler linhas de texto, é necessário utilizar o método readLine das classes BufferedReader ou DataInputStream.On; neste caso, foi escolhido o BufferedReader. Resta-nos apenas transformar o fluxo InputStream do URL num fluxo BufferedReader. Isto é feito criando um fluxo intermédio InputStreamReader:


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

A criação deste fluxo pode falhar. Trata-se da exceção correspondente. Assim que o fluxo estiver disponível, basta ler as linhas de texto e exibi-las no ecrã.


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

Mais uma vez, a leitura pode gerar uma exceção que deve ser tratada. Aqui está um exemplo de execução do programa que requer uma 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 gráfico

A interface gráfica será a seguinte:

Image

Número
Nome
Tipo
Função
1
txtURL
JTextField
URL a ler
2
btnCharger
JButton
botão para iniciar a reprodução do URL
3
JScrollPane1
JScrollPane
painel deslizante
4
lstURL
JList
lista que apresenta o conteúdo do URL solicitado

Ao executar, obtemos um resultado semelhante ao do programa de consola:

Image

O código relevante da 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);

  //Construir o quadro
  public interfaceURL() {
..............
  }

   //Inicializar o componente
  private void jbInit() throws Exception  {
..............
  }

   //Substituído, para que possamos sair quando a janela for fechada
  protected void processWindowEvent(WindowEvent e) {
...................
  }

  void txtURL_caretUpdate(CaretEvent e) {
    // define o estado do botão «Carregar»
    btnCharger.setEnabled(! txtURL.getText().trim().equals(""));
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // exibe o conteúdo do URL na lista
    try{
      afficherURL(txtURL.getText().trim());
    }catch(Exception ex){
       // exibe um erro
      JOptionPane.showMessageDialog(this,"Erreur : " + ex.getMessage(),"Erreur",JOptionPane.ERROR_MESSAGE);
    }//try-catch
  }

  private void afficherURL(String strURL) throws Exception {
    // exibe o conteúdo de URL strURL na lista
     // nenhuma exceção é tratada especificamente. Limitamo-nos a reenviá-las

     // criação do URL
    URL url=new URL(strURL);
     // criação do fluxo de entrada
    BufferedReader IN=new BufferedReader(new InputStreamReader(url.openStream()));
    // leitura das linhas de texto no fluxo de entrada
    String ligne;
    while((ligne=IN.readLine())!=null)
      lignes.addElement(ligne);
     // encerramento do fluxo de leitura
    IN.close();
  }
}

5.6.5.4. Um applet

A aplicação gráfica anterior é transformada num applet, tal como já foi apresentado várias vezes. O applet é inserido num documento HTML 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 o http://localhost:81/Japplets/2/appliURL.htm URL a um servidor web apache a funcionar na porta 81. O applet foi então apresentado no navegador. Nesta, solicitou-se novamente o URL http://localhost:81/Japplets/2/appliURL.htm para verificar se se obtinha efetivamente o ficheiro appliURL.htm que se tinha criado. Agora, vamos tentar carregar um ficheiro URL que não pertença à máquina que emitiu o applet (neste caso, o localhost):

Image

O carregamento do ficheiro URL foi recusado. Aqui voltamos a encontrar a restrição associada aos applets: estes só podem aceder aos recursos de rede da 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 servidor localizado no computador a partir do qual foi descarregado. Este programa efetuará os pedidos de rede em vez do applet e enviar-lhe-á os resultados. A isto chama-se um programa de retransmissão.

5.7. O applet IMPOTS

Vamos agora transformar a aplicação gráfica IMPOTS num applet. Isto apresenta um certo interesse: a aplicação ficará disponível para qualquer utilizador da Internet que disponha de um navegador e de um plugin Java 1.4 (devido ao componente JSpinner). A nossa aplicação torna-se assim global... Esta alteração vai exigir um pouco mais do que a simples transformação de aplicação gráfica em applet, que já se tornou clássica. A aplicação utiliza uma opção de menu Initialiser cujo objetivo é ler o conteúdo de um ficheiro local. No entanto, se imaginarmos uma aplicação Web, percebemos que este esquema já não se aplica:

Image

É evidente que os dados que definem as tabelas de impostos estarão no servidor Web e não em cada uma das máquinas clientes. O ficheiro a ler no servidor Web será aqui colocado na mesma pasta que o applet e a opção Initialiser terá de o ir buscar aí. Os exemplos anteriores mostraram como fazer isso. Além disso, para selecionar o ficheiro de dados localmente, utilizámos um componente JFileChooser que já não é necessário neste caso.

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"
    >

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


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

De salientar o parâmetro data, cujo valor corresponde ao nome do ficheiro que contém os dados da tabela de impostos. O documento HTML, a classe appletImpots, a classe impots e o ficheiro impots.txt encontram-se todos na mesma pasta do 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 {
  // os componentes da janela
  JPanel contentPane;
............................

   // os atributos da classe
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;
  String urlDATA=null;

  //Construir o quadro
  public void init() {
    //enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // outras inicializações
    moreInit();
  }

   // inicialização do formulário
  private void moreInit(){
     // menu «Calcular» desativado
    mnuCalculer.setEnabled(false);
................
     // recuperar o nome do ficheiro da tabela de impostos
    String nomFichier=getParameter("data");
    // erro?
    if(nomFichier==null){
       // mensagem de erro
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // bloqueia-se a opção «Inicializar»
      mnuInitialiser.setEnabled(false);
      // fim
      return;
    }//if
     // define-se o URL dos dados
    urlDATA=getCodeBase()+"/"+nomFichier;
  }//moreInit

   //Inicializar o componente
  private void jbInit() throws Exception  {
...................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // sair da aplicação
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // carregar o ficheiro de dados
    try{
       // leitura de dados
      lireDATA();
       // Criação do objeto «impostos»
      objImpots=new impots(limites,coeffr,coeffn);
................
  }

  private void lireDATA() throws Exception {
     // as tabelas de dados
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // abertura do ficheiro em modo de leitura
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
    // leitura do ficheiro linha a linha
....................
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    // cálculo do imposto
......................
  }

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

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

Aqui, limitamo-nos a comentar as alterações decorrentes do facto de o ficheiro de dados a ler se encontrar agora numa máquina remota, em vez de numa máquina local:

O nome do ficheiro de dados a ler, URL, é obtido através do código seguinte:

     // recuperação do nome do ficheiro da tabela de impostos
    String nomFichier=getParameter("data");
    // erro?
    if(nomFichier==null){
       // mensagem de erro
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // bloqueia-se a opção «Inicializar»
      mnuInitialiser.setEnabled(false);
      // fim
      return;
    }//if
     // define-se o URL dos dados
    urlDATA=getCodeBase()+"/"+nomFichier;

Recorde-se que o nome do ficheiro «impots.txt» foi passado para o parâmetro data do applet:

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

O código acima começa, portanto, por recuperar o valor do parâmetro data, gerindo um eventual erro. 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. Temos de construir o nome deste URL. O método getCodeBase() do applet fornece o URL da pasta onde foi recuperado o documento HTML que contém o applet, ou seja, no nosso exemplo, http://localhost:81/JApplets/impots. A instrução seguinte permite, assim, construir o URL do ficheiro de dados:

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

No método lireFichier(), que lê o conteúdo do URL e do urlData, encontra-se a criação do fluxo de entrada que permitirá a leitura dos dados:

     // abertura do ficheiro em modo de leitura
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));

A partir daí, já não é possível distinguir se os dados provêm de um ficheiro remoto ou local. Eis um exemplo de execução do applet:

Image

5.8. Conclusão

Este capítulo apresentou

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

Concluímos que

  • o código gerado pelo JBuilder pode ser escrito manualmente. Uma vez obtido esse código, seja de que forma for, basta um simples JDK para o executar, deixando o JBuilder desnecessário.
  • a utilização de uma ferramenta como o JBuilder pode trazer ganhos de produtividade significativos:
    • embora seja possível escrever manualmente o código gerado pelo JBuilder, isso pode demorar muito tempo e tem pouco interesse, uma vez que a lógica da aplicação reside, geralmente, noutro local.
    • O código gerado pode ser instrutivo. Lê-lo e estudá-lo é uma boa forma de descobrir certos métodos e propriedades de componentes que se utilizam pela primeira vez.
    • O JBuilder é multiplataforma. Assim, mantém-se o conhecimento adquirido ao mudar de uma plataforma para outra. Poder escrever programas que funcionam tanto no Windows como no Linux é, naturalmente, um fator de produtividade muito importante. Mas isso deve-se ao próprio Java e não ao JBuilder.

5.9. JBuilder no Linux

Todos os exemplos anteriores foram testados no Windows 98. Podemos questionar-nos se os programas escritos são portáveis tal como estão para o Linux. Desde que a máquina Linux em questão disponha das classes utilizadas pelos diferentes programas, sim, são portáveis. Se, por exemplo, tiver instalado o JBuilder no Linux, as classes necessárias já se encontram na sua máquina. Eis, por exemplo, o resultado da execução de um dos nossos programas no componente JList com o JBuilder 4 no Linux:

Apresentamos abaixo a instalação do JBuilder 4 Foundation num computador Linux. A sua instalação num computador Win9x não apresenta qualquer problema e é semelhante ao processo que iremos agora descrever. A instalação de versões posteriores é, sem dúvida, diferente, mas este documento pode, ainda assim, fornecer algumas informações úteis.

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

Image

Nesta página encontram-se os links para, nomeadamente, Windows e Linux. Passamos agora a descrever a instalação do JBuilder num computador Linux com a interface gráfica KDE.

Ao clicar no link «Jbuilder 4 for Linux», é apresentado um formulário. Preenche-se o formulário e, no final, obtêm-se dois ficheiros:

jb4docs_fr.tar.gz: a documentação e os exemplos do Jbuilder4

jb4fndlinux_fr.tar.gz: JBuilder 4 Foundation. Trata-se de uma versão limitada do JBuilder 4 comercial, mas suficiente num contexto educativo.

Receberá por e-mail uma chave de ativação do software. Esta chave permitirá utilizar o JBuilder 4 e ser-lhe-á solicitada logo na primeira utilização. Caso perca esta chave, pode voltar ao URL acima indicado e clicar na ligação «get your activation key». Partimos do princípio de que, a partir daqui, é o utilizador root e que se encontra no diretório dos dois ficheiros tar.gz acima referidos. 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

Nos dois diretórios gerados, o ficheiro .bin é o ficheiro de instalação. Além disso, utilize um navegador para visualizar o ficheiro index.html em cada um dos diretórios. Estes ficheiros fornecem as instruções a seguir para instalar os dois produtos. Comecemos por instalar o JBuilder Foundation:

[cd foundation]
[./fnd_linux_install.bin]

Aparece o primeiro ecrã da instalação. Seguir-se-ão muitos outros:

Image

Confirme. Segue-se um ecrã com explicações:

Image

Execute o comando [suivant].

Image

Aceite o contrato de licença e execute o comando [suivant].

Image

Aceite o local proposto para o JBuilder (anote-o, pois irá precisar dele mais tarde) e execute [suivant]. A instalação é rápida.

Image

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

Image

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

Image

Preencha os campos Nom e Société. Selecione [Ajouter] para introduzir a sua chave de ativação. Recorde-se que esta lhe deve ter sido enviada por e-mail e que, caso a tenha perdido, pode obtê-la no endereço URL onde descarregou o JBuilder 4 (ver início da instalação). Assim que a sua chave de ativação for aceite, ser-lhe-ão relembradas as condições da licença:

Image

Ao introduzir OK, regressa à janela de introdução de informações já vista anteriormente:

Image

Execute OK para concluir esta fase, que só é executada na primeira vez que o programa é iniciado. Em seguida, surge o ambiente de desenvolvimento do JBuilder:

Image

Saia do JBuilder para instalar agora a documentação. Esta irá instalar alguns ficheiros que serão utilizados na ajuda do JBuilder, ajuda essa que, por enquanto, está incompleta. Volte ao diretório onde descompactou os ficheiros tar.gz do Jbuilder. O programa de instalação encontra-se no diretório docs. Navegue até lá:

[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 se perceba o motivo. Leia o ficheiro index.html num navegador para obter uma descrição detalhada do processo de instalação. O instalador necessita de uma máquina virtual Java, mais concretamente de um programa chamado java, que deve estar localizado no diretório PATH do seu computador. Recorde-se que PATH é uma variável Unix cujo valor, na forma rep1:rep2:...:repn, indica os diretórios repi que devem ser pesquisados na procura de um executável. Neste caso, 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 ou ali. Logicamente, utilizaremos a versão fornecida pelo Jbuilder4, que se encontra em /opt/jbuilder4/jdk1.3/bin. Para definir este diretório na 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...

Será realizada uma instalação gráfica:

Image

É muito semelhante à do JBuilder Foundation. Por isso, não a iremos descrever em pormenor. Há um ecrã que não se deve perder:

Image

Normalmente, o programa de instalação deve identificar automaticamente a localização onde instalou o JBuilder Foundation. Por isso, não altere as opções sugeridas, a menos, claro, que estejam erradas.

Assim que a documentação estiver instalada, estamos prontos para um novo teste do JBuilder. Inicie a aplicação tal como foi mostrado acima. Assim que o JBuilder estiver ativo, selecione a opção Ajuda/Tópico de ajuda. No painel da esquerda, clique na ligação Tutoriels:

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 «Construção de uma aplicação» mencionado anteriormente.

Image

No JBuilder, selecione Ficheiro/Novo projeto. Um assistente irá apresentar-lhe 3 ecrãs:

Image

Vamos criar uma janela simples com o título «Olá a todos». Chamamos a este projeto coucou. O exemplo foi executado pelo root. O JBuilder sugere então agrupar todos os projetos num diretório jbproject, dentro do diretório de ligação do root. O projeto coucou será colocado no diretório coucou (campo «Nome do diretório do projeto») de jbproject. Execute o [suivant].

Image

Este segundo ecrã apresenta um resumo dos diferentes caminhos do seu projeto. Não há nada a alterar. Execute o [suivant].

Image

O terceiro ecrã pede-lhe para personalizar o seu projeto. Preencha e execute [Terminer].

Execute agora o Fichier/Nouveau:

Image

Selecione Application e execute OK. Um novo assistente irá apresentar-lhe duas telas:

Image

O campo paquet retoma o nome do projeto. O campo «classe» solicita o nom, que será atribuído à classe principal do projeto. Utilize o nome acima e introduza [suivant]:

Image

A nossa aplicação inclui uma segunda classe Java para a janela da aplicação. Atribua um nome a esta classe. O campo Titre corresponde ao título que pretende atribuir a esta janela. O quadro options apresenta-lhe opções para a sua janela. Selecione todas elas e defina como [Terminer]. Em seguida, regressa ao ambiente JBuilder, que foi atualizado com as informações que forneceu para o seu projeto:

Image

Na janela à esquerda/em cima (1), encontra a lista dos ficheiros que compõem o seu projeto. Encontram-se, nomeadamente, as duas classes .java às quais acabámos de atribuir um nome. Na janela à direita (2), encontra o código Java da classe coucouCadre. Na janela à esquerda/em baixo, encontra-se a estrutura (classes, métodos, atributos) do seu projeto. Está pronto para ser executado. Clique no botão 4 acima, selecione Executar/Executar o projeto ou selecione F9. Deverá aparecer a seguinte janela:

Image

Ao clicar na opção Aide, deverá encontrar as informações que forneceu aos assistentes de criação. Não iremos mais além. Está na hora de mergulhar nos tutoriais.

Antes de terminar, 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 que colocou em /opt/jbuilder4/jdk1.3. Compile 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 com o JDK do JBuilder:

[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