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:

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

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-á:
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:
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:
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:

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

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:

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

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:

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:
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.
- Inicie o JBuilder e selecione a opção Ficheiro/Novo projeto. É então apresentada a primeira página de um assistente:

- 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]
- Um ecrã confirma as escolhas da etapa anterior

Execute [suivant]
- Um novo ecrã solicita que defina as características do seu projeto:

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

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

No campo classe, introduza o nome da classe que vai ser criada. Aqui, utilizámos o mesmo nome do projeto.
Execute [suivant]
- Aparece o ecrã seguinte:

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]
- É 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

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

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:

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:

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:

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:
- a função main define o aspeto da janela (setLookAndFeel) e cria uma instância da classe début.
- 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.
- 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.
- 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:

Dê à nova classe o nome début2 e renomeie [Terminer]. Aparece um novo ficheiro no projeto:

O ficheiro début2.java é reduzido à sua forma mais simples:
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

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

Selecione début2 e altere para [OK].

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
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 é 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");
}
- O programador começa por indicar que irá gerir os eventos na janela (enableEvents) e, em seguida, chama o método jbInit.
- O contentor (JPanel) da janela (JFrame) é obtido (getContentPane)
- O gestor de formatação é definido (setLayout)
- O tamanho da janela é definido (setSize)
- 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:

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.

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

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:

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:

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:

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:

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

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:

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.

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:

e a seguinte estrutura:

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

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.

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:

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

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):


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:
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.

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:

Vamos analisar mais de perto as páginas Sommaire e Index.
5.2.4.1. Ajuda: Índice

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:

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:

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:
![]()
A ajuda irá apresentar as entradas do índice que começam com o texto digitado:

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

É-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:

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:

5.2.5.2. componente JComboBox


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.

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
- e, em seguida, no código de jbInit, a lista é associada ao contentor
Para adicionar valores à lista JList1 acima, basta adicioná-los ao seu vetor de valores valeurs:
e obtém-se então a seguinte janela:

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:

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:

É possível saber o modo de seleção atual com o método getSelectionMode:
![]()
O(s) elemento(s) selecionado(s) pode(m) ser obtido(s) através dos seguintes métodos:

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:

Já sabemos o suficiente para escrever a seguinte aplicação:

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:

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:

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:

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:

5.2.5.5. componente JScrollBar
Vamos criar a seguinte aplicação:

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:

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

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:

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

Eis o resultado, por exemplo, com RaisedBevel:
![]()
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.

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:

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:

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:

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:

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:

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:
- MousePressed ao premir o botão
- MouseReleased ao soltá-lo
- 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:

Vemos aqui os três eventos:
- MousePressed quando se clica inicialmente no botão
- MouseDragged ao mover o rato, com o botão pressionado
- 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?

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:


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.

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

Clique duas vezes no elemento jMenuBar1 acima para aceder ao menu no modo de conceção:

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.

Em seguida, ao lado:

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:

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:

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

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):

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:

Terá então acesso às suas propriedades e eventos:

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:

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:

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. Caixas de diálogo
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:

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

A visualização da consola:
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:

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:

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

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:

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

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:

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:

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

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:

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

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

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:

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
, verificamos que o JBuilder nos fornece uma ajuda:

O pacote com.lamatek foi encontrado.
- Se agora passarmos para o seguinte programa:
Ao pesquisar «F1» com a palavra-chave «JFontChooser», obtém-se ajuda sobre esta classe:

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:

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:

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:

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:
![]()
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:
Antes de mais nada, o utilizador deve utilizar a opção de menu Initialiser, que cria um objeto impots com o construtor
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:

- 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:
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:
- a classe application deriva agora da classe JApplet
- 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.

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 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:
- eliminar a instrução que define o título da janela JFrame. Um applet JApplet não tem barra de título
- 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:

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:

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:

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:

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

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:

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>

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):

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:

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

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

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:
[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:
Aparece o primeiro ecrã da instalação. Seguir-se-ão muitos outros:

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

Execute o comando [suivant].

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

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

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):

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

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:

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

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:

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:
Será realizada uma instalação gráfica:

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

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:

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.

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

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].

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

O terceiro ecrã pede-lhe para personalizar o seu projeto. Preencha e execute [Terminer].
Execute agora o Fichier/Nouveau:

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

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]:

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:

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:

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:






