Prévia do material em texto
Aplicações de Linguagem de Programação Orientada a
Objetos
2
Módulo 1 – AWT (Abstract Window Toolkit) e Swing
Componentes
Os componentes, também chamados de widgets (windows gadgets, ou dispositivos de janelas)
são os elementos construtivos das interfaces gráficas de usuário ou GUIs, isto é, são botões,
caixas de entrada de texto, caixas de seleção, menus, barras de rolagem, etc., que compõem
qualquer aplicativo visual. Também existem componentes não visuais destinados a oferecer
suporte aos demais componentes, como prover acesso a dados ou outras tarefas com as quais o
usuário do aplicativo não interaja diretamente. A figura abaixo apresenta um exemplo de GUI:
Java oferece uma ampla biblioteca de componentes GUI e de capacidades gráficas na forma de
classes, pertencentes aos pacotes java.awt e javax.swing, que representam os frameworks
(ou conjuntos de classes) responsáveis pela composição dos elementos visuais em um aplicativo.
AWT
A AWT constitui a primeira biblioteca de componentes visuais do Java que permitem a construção
de aplicações GUI, capaz de ser utilizada em grande parte dos sistemas operacionais. A AWT
funciona como uma casca entre o componente do sistema nativo e seu equivalente representado
pela classe correspondente da biblioteca.
Assim, uma aplicação Java AWT que contenha um botão usará o componente nativo para botões
onde a aplicação é executada. Mesmo que a aparência do componente apresente ligeira diferença
entre um sistema operacional e outro para o mesmo aplicativo, o comportamento e funcionamento
durante a operação serão os mesmos.
No entanto, isso exige um mecanismo razoavelmente complexo e pesado de troca de mensagens
entre o sistema operacional e a JVM (máquina virtual Java), o que reduz o desempenho dos
componentes AWT (daí serem chamados de componentes pesados ou heavy-weight
components). Além disso, a quantidade de componentes disponíveis é relativamente pequena e a
construção de novos componentes torna-se complexa ou dependente da plataforma.
A classe abstrata Component é a base para a construção de todos os componentes GUI
oferecidos pelo Java no pacote java.awt. Essa classe oferece a infra-estrutura necessária para
a criação de objetos que possuam uma representação gráfica, as quais poderão ser exibidas num
ambiente gráfico e com as quais o usuário poderá interagir. Sendo uma classe abstrata,
3
Component não pode ser instanciada diretamente, mas sendo a classe-base comum de todos os
componentes da biblioteca AWT, possibilita por meio do polimorfismo o tratamento generalizado
dos componentes derivados.
Com a API (Application Programming Interface ou Interface de Programação de Aplicativos) da
classe Component é possível determinar tamanho, cores, fonte e cursor utilizados pelo
componente, além do seu estado de funcionamento, posição e visibilidade.
Em particular, a classe Component é a base para a construção de outra classe abstrata especial
denominada Container, a qual representa um compartimento onde outros componentes podem
ser adicionados e posicionados, cuja API oferece facilidades para inclusão e remoção de
componentes. Classes derivadas de Container também são containers, isto é, também podem
conter outros componentes, tais como janelas e painéis.
Atualmente a AWT está integrada à JFC (Java Foundation Classes), um conjunto de bibliotecas
que engloba a própria AWT, o Swing e o Java 2D. A JFC foi desenvolvida para a construção de
aplicativos GUI e também gráficas voltadas para diferentes plataformas operacionais, cujo
destaque é o Swing, uma outra família de componentes.
Swing
Como comentado, o uso do AWT é dependente da plataforma; portanto, usá-la não é fácil e essa
biblioteca não está livre de bugs. Os componentes da biblioteca Swing são mais fáceis de utilizar
e estão muito mais bem implementados, mas alguns de seus componentes ainda necessitam de
classes da biblioteca AWT. A família de componentes Swing é uma parte importante da JFC que
engloba:
• Componentes Swing – uma nova família de componentes com funcionalidade ampliada e
grande capacidade de configuração;
• Suporte para múltiplos Pluggable Look and Feel – dá aos programas Java a
capacidade de utilizarem diferentes aparências visuais, tais como peles (skins) adaptadas
ou não ao ambiente operacional utilizado;
• Acessibilidade – permite o uso integrado de tecnologias para auxílio de portadores de
necessidades especiais, tais como monitores e teclados diferenciados;
• Java 2D – um pacote de classes para desenho 2D de gráficos, texto e imagens de alta
qualidade;
• Suporte para Drag and Drop – oferece capacidade de arrastar e soltar entre aplicações
Java e aplicações nativas.
Além de oferecer um conjunto muito mais amplo e versátil, os componentes Swing são 100% Java
e assim não utilizam código nativo tal como a família AWT, constituindo deste modo componentes
leves (ou light-weight components).
A classe JComponent do pacote javax.swing oferece a infra-estrutura para a maior parte dos
componentes Swing. Por sua vez, a classe JComponent é uma subclasse da classe Container,
4
do pacote java.awt, uma classe abstrata que oferece a estrutura para construção de
componentes que podem conter outros componentes. Em virtude disso, a estratégia de
representação (ou renderização) utilizada no Swing é diferenciada, sendo dividida em três partes:
a representação do componente em si, a representação da borda do componente e a
representação dos componentes nele contidos. A figura abaixo apresenta o diagrama da
hierarquia de classes da biblioteca Swing e respectivas dependências com a biblioteca AWT.
Como uma interface gráfica trabalha
Programas com interface gráfica de usuário (GUI) são controlados por eventos. Isto significa que o
programa reage às ações do usuário; estas ações são chamadas de eventos. Exemplos de
eventos podem ser: o pressionar de uma tecla do teclado, mover o mouse, pressionar um botão
ou selecionar um item de menu.
Um programa com uma GUI possui uma pequena fase de iniciação na qual a GUI é construída,
mas ainda não exibida. Algumas outras ações (não relacionadas aos componentes visuais)
também são executadas. Esta fase não é controlada por eventos e não é possível a interação com
java.awt.Container JComponent
JTextComponent AbstractButton
JComboBox
Texto
JTextArea
JEditorPane
JTextPane
JTextField
Menus Widgets
JLabel
JList
JTree
JToolBar
JTable
JMenuBar
JPopupMenu
JCheckBoxMenuItem
JMenuItem
JMenu
JRadioButtonMenuItem
JSeparator
JToggleButton
JButton
JCheckBox
JRadioButton
JPasswordField
JSlider
JToolTip
JScrollBar
JProgressBar
Sub-janelas
java.awt.Panel
java.awt.Applet
JApplet
JPanel
JViewPort
Janelas de nível mais alto
JScrollPane
JRootPane
JTabbedPane
JOptionPane
JInternalFrame
JPane
JSliptPane
JLayeredPane
java.awt.Applet
JWindow
JFrame
JDialog
java.awt.Frame
java.awt.Dialog
5
o usuário. Depois desta fase a GUI é apresentada na tela e o programa passa a ser controlado
por eventos.
Obviamente, queremos que o programa reaja somente a alguns tipos de eventos, não todos. O
programador precisa especificar quem serão os eventos aos quais o programa deverá reagir e, é
claro, quais as reações que deverá ter para cada evento. Em Java isto é feito acrescentando-se
os chamados listeners, ou observadores de eventos, que são interfaces que ficam aguardando a
ocorrência de determinados tipos de eventos. O observador, então, executa a ação desejada por
meio deseus métodos. Os eventos são processados na seqüência em que ocorrem, sob o
controle de um despachante de eventos que os organizam em fila.
Existem muitos tipos de eventos em Java associados a diferentes fontes de eventos, tais como
botões, menus ou o mouse. Os eventos contêm informações sobre o que aconteceu, isto é, quem
disparou o evento (se um botão ou um item de menu) e onde ele ocorreu (em quais coordenadas
do mouse, por exemplo). Estas são as informações exploradas pelo observador. O diagrama da
figura abaixo indica como se dá este processo.
Cada componente da interface é um objeto de uma classe distinta. O mesmo acontece com cada
tipo de evento, que é um objeto de uma classe particular, da mesma forma que cada observador
(listener) é uma interface que especifica um tipo particular de receptor de eventos. As classes e
interfaces disponíveis no modelo de eventos da AWT estão no pacote java.awt.event. Todos
os eventos da AWT possuem uma raiz comum que é a classe abstrata AWTEvent, existindo tipos
diferentes de eventos responsáveis pelo encapsulamento de informações relativas às diferentes
ações possíveis.
Todos os componentes Swing são capazes de produzir eventos dos seguintes tipos:
ComponentEvent, FocusEvent, KeyEvent e MouseEvent. Tais eventos, respectivamente,
sinalizam a alteração do tamanho, posição e visibilidade do componente, as mudanças de foco, o
acionamento de teclas via teclado e a utilização do mouse sobre o componente, necessitando de
tratamento pelos seus respectivos observadores: ComponentListener, FocusListener,
Programa GUI
Gera eventos
Despachante de eventos
Enfileira os
eventos e notifica
Observadores de eventos
Acionam
Métodos de notificação
6
KeyListener e MouseListener. A tabela a seguir apresenta os eventos adicionais gerados
pelos principais componentes Swing.
Classes
Ac
tio
n
Ev
en
t
Ca
re
tE
v
en
t
Ch
an
ge
Ev
en
t
Do
cu
m
en
tE
v
en
t
Un
do
ab
le
Ed
itE
v
en
t
Ite
m
Ev
en
t
Li
st
Se
le
ct
io
n
Ev
en
t
W
in
do
w
Ev
en
t
Outros eventos
JButton * * *
JCheckBox * * *
JColorChooser *
JComboBox * *
JDialog *
JEditorPane * * * HyperlinkEvent
JFileChooser *
JFrame *
JInternalFrame InternalFrameEvent
JList *
JMenu MenuEvent
JMenuItem * * * MenuDragMouseEvent, MenuKeyEvent
JOptionPane
JPasswordField * * * *
JPopupMenu PopupMenuEvent
JProgress *
JRadioButton * * *
JSlider *
JSpinner *
JTabbedPane *
JTable *
TableModelEvent,
TableColumnModelEvent,
CellEditorEvent
JTextArea * * *
JTextField * * * *
JTextPane * * * HyperlinkEvent
JToggleButton * * *
JTree
TreeExpansionEvent,
TreeWillExpandEvent,
TreeModelEvent,
TreeSelectionEvent
JViewPort *
Os eventos típicos do Swing são aqueles produzidos pelos componentes mais usados pela
grande maioria das aplicações, cujo tratamento é usualmente requisitado:
• ActionEvent – evento semântico que indica a ocorrência de alguma ação predefinida em
um componente. Corresponde ao acionamento de botões (JButton) e itens de menu
(JMenuItem), mas pode ser disparado por outros componentes tal como no acionamento
da tecla ENTER em uma caixa de texto (JTextField). Seu tratamento é realizado por
implementação da interface ActionListener;
• CaretEvent – notifica as classes interessadas que a posição do cursor de edição de um
componente de texto sofreu modificação. É produzido por componentes deste tipo, tais
como JTextField e JTextArea. Seu tratamento é realizado por implementações da
interface CaretListener;
• ChangeEvent – permite avisar às classes interessadas que ocorreu alguma mudança no
componente associado, tal como o posicionamento de um controle deslizante JSlider ou
7
troca de aba em um JTabbedPane. Seu tratamento é realizado por implementações da
interface ChangeListener;
• DocumentEvent – constitui uma interface para notificação de modificações em
documentos (conteúdo de componentes de texto). São produzidos de modo especializado
por JTextField, JTextArea e outros. Seu tratamento exige a implementação da
interface DocumentListener;
• UndoableEditEvent – indica a ocorrência de uma operação que pode ser desfeita e cujo
tratamento se dá por meio da interface UndoableEditListener;
• ItemEvent – evento semântico que indica a seleção ou remoção da seleção de um
componente. Corresponde a seleção de caixas de opção (JCheckBox), botões de opção
(JRadioButton) ou itens de combos e listas (respectivamente JComboBox e JList).
Seu tratamento é realizado por implementações da interface ItemListener;
• ListSelectionEvent – caracteriza a mudança de seleção em uma caixa de lista (JList)
ou tabela (JTable). Seu tratamento é realizado por implementação da interface
ListSelectionListener;
• WindowEvent – evento de baixo nível que indica a alteração do estado de uma janela. O
tratamento deste evento se dá por meio de implementações da interface
WindowListener.
Os eventos semânticos são aqueles que têm significados bem definidos e cujos tratamentos são
independentes de plataforma. Também são considerados como eventos de alto nível. Já os
demais eventos, chamados de baixo nível, possuem tratamentos que, às vezes, precisam
considerar detalhes específicos da plataforma, sendo portanto de implementação mais complexa.
O tratamento de eventos no Java é relativamente simples. Para um evento qualquer, aqui
denominado XEvent, seu tratamento sempre acontece por meio de uma interface XListener, a
qual será incluída e removida respectivamente pelos métodos addXListener(XListener) e
removeXListener(XListener). Na interface XListener é comum que os métodos a serem
implementados tenham como prefixo o nome do evento (embora existam várias exceções).
A tabela abaixo relaciona os principais eventos, suas interfaces ou classes adaptadoras e
respectivos métodos do Swing:
Evento Interface ou Adaptador Métodos
ActionEvent ActionListener actionPerformed(ActionEvent)
CaretEvent CaretListener caretUpdate(CaretEvent)
ChangeEvent ChangeListener stateChanged(ChangeEvent)
componentHidden(ComponentEvent)
componentMoved(ComponentEvent)
componentResized(ComponentEvent) ComponentEvent
ComponentListener
ComponentAdapter
componentShow(ComponentEvent)
changedUpdate(DocumentEvent)
insertUpdate(DocumentEvent) DocumentEvent DocumentListener
removeUpdate(DocumentEvent)
focusGained(FocusEvent) FocusEvent FocusListener FocusAdapter focusLost(FocusEvent)
ItemEvent ItemListener itemStateChanged(ItemEvent)
keyPressed(KeyEvent) KeyEvent KeyListener
KeyAdapter keyReleased(KeyEvent)
8
keyTyped(KeyEvent)
ListSelectionEvent ListSelectionListener valueChanged(ListSelectionEvent)
mouseClicked(MouseEvent)
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mousePressed(MouseEvent)
MouseListener
MouseAdapter
mouseReleased(MouseEvent)
mouseDragged(MouseEvent)
MouseEvent
MouseMotionListener
MouseMotionAdapter mouseMoved(MouseEvent)
MouseWheelEvent MouseWheelListener mouseWheelMoved(MouseWheelEvent)
UndoableEditEvent UndoableEditListener undoableEditHappened(UndoableEditEvent)
windowActivated(WindowEvent)
windowClosed(WindowEvent)
windowClosing(WindowEvent)
windowDeactivated(WindowEvent)
windowDeiconified(WindowEvent)
windowIconified(WindowEvent)
WindowEvent
WindowListener
WindowAdapter
windowOpened(WindowEvent)
Módulo 2 – Swing parte 1: Criação de objetos via código
Construindo uma aplicação gráfica
Quando se decide pela construçãode uma aplicação gráfica, é necessário um projeto da interface
para a aplicação, ou seja, é preciso determinar quais tarefas devem ser realizadas pela interface,
quais componentes serão utilizados, qual o objetivo de seu uso e qual a disposição desejada para
tais componentes. Dessa maneira, é possível dizer que a representação de uma aplicação gráfica
envolve seis passos simples, os quais devem ser repetidos para cada janela pretendida para a
aplicação:
1. Esboço da janela: desenho da janela pretendido que inclui disposição dos componentes
(leiaute), identificação e tipo dos componentes, especificação das ações do usuário e
reações correspondentes;
2. Implementação de uma subclasse JFrame: construção de uma subclasse de JFrame para
cada janela;
3. Declaração dos componentes: declaração dos componentes ativos como campos privados
da classe criada e, opcionalmente, dos componentes não ativos;
4. Representação do construtor: definição de construtor capaz de organizar os componentes
na interface e registrar os eventos necessários;
5. Programação dos processadores de eventos (event listeners): representação dos métodos
que processarão os eventos selecionados;
6. Início da aplicação GUI: caso a janela seja a principal da aplicação (a primeira janela a ser
utilizada), é adequado incluir o método main(String[] args).
Frames
Os elementos básicos de qualquer sistema operacional gráfico são as janelas, que são áreas
retangulares nas quais texto, imagens ou outras informações podem ser exibidas. As janelas
também podem conter elementos de interação com usuários, como menus, botões ou áreas para
9
entrada de textos. Muitos outros componentes gráficos não podem ser exibidos isoladamente,
sendo necessário que sejam colocados dentro de uma janela. A aparência final de uma janela
dependerá do sistema operacional utilizado, especialmente a largura e o tipo de borda ao redor de
uma janela. A posição e a cor dos botões podem variar.
Em Java, o termo frame (moldura) é usado para aquilo que genericamente é denominado janela.
No Swing, os frames são representados pela classe JFrame. Um frame é uma área retangular
com uma barra de título no topo. A barra de título também contém botões para fechar, maximizar
e minimizar a janela. Como comentado, o tipo e a posição desses botões dependem da
plataforma (Windows, MacOS, Linux, Solaris, etc.). Abaixo da barra de título existe uma área na
qual outros componentes gráficos podem ser embutidos. Esta área é dividida em duas partes: um
espaço para uma barra de menu na parte superior e o painel de conteúdo, logo abaixo. O painel
de conteúdo pode conter diversos componentes gráficos embutidos. Se não for incluída uma barra
de menu, então o painel de conteúdo é expandido para o espaço vazio deixado pela ausência da
barra de menu. As funções básicas como redimensionamento ou movimentação do frame com o
mouse são automaticamente fornecidas e não precisam ser programadas pelo programador.
Existe um outro componente chamado window na biblioteca Swing, mas este componente não
possui moldura, isto é, não possui uma barra de título, uma borda nem botões de fechar,
maximizar ou minimizar. A figura abaixo mostra a estrutura de um frame:
O construtor padrão do frame é o JFrame(), que gera um frame sem título. Gerar aqui significa
que a informação para desenhar-se o frame é fornecida; entretanto, o frame não é exibido na tela.
Isto é obtido chamando-se o método setVisible.
O método setVisible(boolean b) torna o frame visível se b for true. Se b for false, o
frame é ocultado da tela, mas a informação utilizada para desenhá-lo não é destruída. Assim, se b
for true novamente, o frame tornar-se-á visível na tela mais uma vez, ou seja, não será
necessário chamar o construtor uma segunda vez.
Painel de conteúdo
Título X □ _
Espaço para a barra de menu
10
O método setTitle(String title) ajusta o título na barra de título do frame com o valor
passado como argumento em title.
O método setSize(int width, int height) ajusta a largura do frame de acordo com o
valor passado como argumento em width e a altura com o valor passado em height.
O método setLocation(int horizontal, int vertical) posiciona o canto superior
esquerdo do frame na tela de acordo com os valores passados em horizontal e vertical.
O método pack() redimensiona o frame de modo que se ajuste firmemente ao redor dos
componentes embutidos em seu painel de conteúdo.
Finalmente, o método setDefaultCloseOperation(int operation) determina o que
acontece se o botão de fechar do frame for pressionado. Neste caso, pode-se utilizar a opção
JFrame.EXIT_ON_CLOSE como parâmetro passado ao argumento operation.
Panels e layouts
Embutiremos agora outro componente gráfico em um frame. Os componentes usados chamam-se
panels (painéis). Panels são componentes retangulares, que servem a dois propósitos: podem ser
usados como se fossem uma tela onde se pode desenhar ou podem ser usados como
compartimentos (containers) para embutir mais componentes gráficos.
No Swing a classe JPanel representa um panel. Abaixo temos seu construtor e alguns métodos:
JPanel() é o construtor. O tamanho do panel é ajustado para valores padronizados, 10 por 10
pixels na maioria dos sistemas.
setBackground(Color c) ajusta a cor de fundo do panel. A classe Color vem da biblioteca
da AWT. Assim, algumas cores são pré-definidas, isto é, vermelho será Color.red. Por padrão a
cor de fundo é cinza (grey).
setPreferredSize(Dimension d) ajusta o tamanho do panel. A classe Dimension vem da
biblioteca da AWT. O construtor possui a sintaxe Dimension(int width, int height).
Tanto width quanto height estão em pixels. É importante lembrar que estes valores são apenas
recomendações para o tamanho de um componente. Dependendo do tamanho de outros
componentes, o sistema – em tempo de execução – poderá escolher valores diferentes para eles!
Os valores realmente usados são determinados por um LayoutManager (gerenciador de leiaute)
em tempo de execução. Esta flexibilidade é importante ao Java para que seja independente de
plataforma.
Componentes gráficos são embutidos da seguinte maneira: chamemos o componente que
queremos embutir de componente filho (child component). Aqueles componentes do Swing
capazes de embutir outros possuem um método add (adicionar). Então, para embutir um
componente filho (childComp) em um componente pai (parentComp), a sintaxe utilizada é:
parentComp.add(childComp)
11
Vamos agora especificar como os componentes são acomodados no painel de conteúdo. A fim de
ser uma plataforma independente, os projetistas do Java deram alguma flexibilidade ao sistema
gráfico. O programador apenas especifica a estrutura de arranjo dos componentes, não suas
posições absolutas. Por exemplo, especifica-se que “o componente A está à direita do
componente B” ao invés de definir que “o componente A está na posição (x, y)”. Em tempo de
execução, as posições dos componentes é que são determinadas. Isto é feito pelo chamado
layout manager (gerenciador de leiaute) que está associado ao componente pai. Existem
diferentes gerenciadores de leiaute pré-definidos e o programador pode definir os seus próprios.
Um JFrame possui por padrão um BorderLayout; mais precisamente o painel de conteúdo
possui um gerenciador de leiaute do tipo BorderLayout. Ele permite que o usuário posicione um
(grande) componente central e até quatro componentes nas bordas. As posições são
determinadas pelas constantes CENTER, NORTH, SOUTH, EAST e WEST. Estas constantes estão
definidas na classe BorderLayout. Se um componente de borda não estiver presente, então o
componente central expande-se naquela direção. O componente central geralmente contém a
informação principal. Os componentes de borda contêminformações extras. Para inserir um
componente filho (childComp) dentro do painel de conteúdo na posição pos, usamos o método:
this.getContentPane().add(childComp, pos)
Onde pos é uma das seguintes constantes: BorderLayout.CENTER, BorderLayout.NORTH,
BorderLayout.SOUTH, BorderLayout.EAST ou BorderLayout.WEST. A figura abaixo
apresenta a distribuição dos componentes ao redor do frame.
Vejamos agora mais dois gerenciadores de leiaute: o gerenciador de leiaute por fluxo
(FlowLayout) e o gerenciador de leiaute por grade (GridLayout). Os leiautes não estão
restritos a frames. Todo componente Swing no qual outros componentes possam ser embutidos
(os chamados compartimentos ou containers) possui um leiaute. O leiaute padrão é uma borda.
Para que se possa alterar o leiaute de um componente pai parentComp para outro leiaute
newLayout usa-se o comando:
parentComp.setLayout(newLayout)
Se um componente tem um leiaute de fluxo então os componentes embutidos são dispostos em
fila única da esquerda para a direita. Se uma linha estiver completa, a próxima é iniciada. Leiaute
em linha (normalmente) respeita as dimensões dos componentes embutidos. A ordem de
chamada do parentComp.add(child) determina a ordem dos componentes embutidos no
componente pai. A altura de uma linha é determinada em tempo de execução, verificando-se
CNorth
CSouth
CW
e
s
t
C
E
a
s
t
CCenter
12
todos os componentes daquela linha, conforme indicado na figura abaixo, onde os componentes
C3 e C5 é que estão determinando a altura de cada uma das duas linhas presentes no frame.
A seguir, alguns construtores do FlowLayout:
FlowLayout()
FlowLayout(int align)
FlowLayout(int align, int hdist, int vdist)
O primeiro construtor gera um leiaute que, por padrão, deixa cinco pixels de distância entre os
componentes de uma linha e cinco pixels de distância entre linhas. Complementarmente, o
segundo construtor especifica o tipo de alinhamento dos componentes, onde align é um destes:
FlowLayout.RIGHT, FlowLayout.LEFT ou FlowLayout.CENTER
Isto determina quais componentes em cada linha estarão “empacotados” à direita, à esquerda ou
quais estarão centralizados. O terceiro construtor, além disso, também especifica a distância
hdist horizontal entre os componentes de uma linha e a distância vdist vertical entre linhas.
O terceiro gerenciador de leiaute a ser descrito é o GridLayout, que ordena os componentes em
uma grade. O componente pai (em nosso exemplo, o painel de conteúdo) é dividido em l x c
células retangulares, onde c é o número de células por linha e l é o número de linhas. Todas as
células têm o mesmo tamanho. Os componentes ficam embutidos dentro das células em fila única
da esquerda para a direita. Se houver mais células que componentes embutidos o gerenciador de
leiaute tentará preencher todas as linhas o mais separado possível e poderá gerar menos que c
colunas! Se houver menos células que componentes então mais colunas são adicionadas.
Basicamente o gerenciador de leiaute por grade ignora o número de colunas. A fim de ter um
número fixo c > 0 de colunas, o número de linhas deve ser ajustado para l = 0 e o número de
colunas para c. Assim, sempre haverá c colunas e o número de linhas dependerá do número de
componentes embutidos. A figura abaixo exemplifica o uso do gerenciador de leiaute por grade.
C3
C2 C1
C4 C5
C3 C2 C1
C4 C5 Vazio
13
Exercícios de Laboratório do módulo 2
1. Crie a classe abaixo, referente à representação de um frame principal. Teste os diferentes
métodos dessa classe no método main, alterando o tamanho do frame, posição na tela e o título.
Crie mais um método exibeFrame de modo que seja possível também ao programador usuário
dessa classe alterar as dimensões da janela, que está limitada no construtor a 200 por 200 pixels.
package br.unip.cc4si4.ALPOO;
import javax.swing.JFrame;
public class JanelaPrincipal extends JFrame{
public JanelaPrincipal(){
this.setSize(200,200);
this.setLocation(200,200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//Torna o frame visivel
public void exibeFrame(){
this.setVisible(true);
}
//Torna o frame visivel e define o texto do titulo
public void exibeFrame(String titulo){
this.setTitle(titulo);
this.setVisible(true);
}
//Torna o frame visivel e define o texto do titulo
//e a posicao da janela
public void exibeFrame(String titulo, int x, int y){
this.setTitle(titulo);
this.setLocation(x,y);
this.setVisible(true);
}
//Torna o frame invisivel
public void ocultaFrame(){
this.setVisible(false);
}
//Cria e exibe o frame
public static void main(String[] args){
new JanelaPrincipal().exibeFrame("Janela Principal", 150, 150);
}
}
2. Crie a classe abaixo, referente à representação de um panel.
package br.unip.cc4si4.ALPOO;
import java.awt.*;
import javax.swing.JPanel;
public class PanelColorido extends JPanel{
//Gera um JPanel com cor de fundo cor
public PanelColorido(Color cor){
this.setBackground(cor);
}
//Gera um JPanel com cor de fundo cor,
//largura e altura
public PanelColorido(Color cor,int largura,int altura){
this.setPreferredSize(new Dimension(largura,altura));
this.setBackground(cor);
}
}
3. Altere o construtor da classe JanelaPrincipal conforme indicado abaixo e inclua também o
seguinte import em seu cabeçalho: import java.awt.*;
public JanelaPrincipal(){
this.setSize(200,200);
this.setLocation(200,200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PanelColorido PCWest = new PanelColorido(Color.white,50,20);
PanelColorido PCEast = new PanelColorido(Color.red);
PanelColorido PCNorth = new PanelColorido(Color.yellow);
PanelColorido PCSouth = new PanelColorido(Color.green);
PanelColorido PCCenter = new PanelColorido(Color.blue);
this.getContentPane().add(PCWest,BorderLayout.WEST);
this.getContentPane().add(PCEast,BorderLayout.EAST);
this.getContentPane().add(PCNorth,BorderLayout.NORTH);
14
this.getContentPane().add(PCSouth,BorderLayout.SOUTH);
this.getContentPane().add(PCCenter,BorderLayout.CENTER);
}
Se você quisesse que o programador usuário dessa classe fosse capaz de alterar a cor de fundo,
que complementação de código seria necessária na classe JanelaPrincipal?
4. Altere novamente o construtor da classe JanelaPrincipal conforme indicado abaixo:
public JanelaPrincipal(LayoutManager layout){
this.getContentPane().setLayout(layout);
this.setSize(200,200);
this.setLocation(200,200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PanelColorido PC1 = new PanelColorido(Color.red ,30,30);
PanelColorido PC2 = new PanelColorido(Color.yellow ,40,20);
PanelColorido PC3 = new PanelColorido(Color.green);
PanelColorido PC4 = new PanelColorido(Color.blue);
PanelColorido PC5 = new PanelColorido(Color.white,80,20);
this.getContentPane().add(PC1);
this.getContentPane().add(PC2);
this.getContentPane().add(PC3);
this.getContentPane().add(PC4);
this.getContentPane().add(PC5);
}
Altere também o método main conforme indicado a seguir:
public static void main(String[] args){
FlowLayout flowLayout1 = new FlowLayout();
JanelaPrincipal flow1Frame = new JanelaPrincipal(flowLayout1);
flow1Frame.exibeFrame("Leiaute por fluxo 1",60,60);
FlowLayout flowLayout2 = new FlowLayout(FlowLayout.LEFT,40,30);
JanelaPrincipal flow2Frame = new JanelaPrincipal(flowLayout2);
flow2Frame.exibeFrame("Leiaute por fluxo 2",300,60);
GridLayout gridLayout = new GridLayout(2,4);
JanelaPrincipal gridFrame = new JanelaPrincipal(gridLayout);
gridFrame.exibeFrame("Leiautepor grade",540,60);
}
O que acontece com a distribuição dos componentes embutidos no frame se alterarmos suas
dimensões de 200 por 200 para 230 por 200 pixels? Porque o construtor recebe como argumento
um gerenciador de leiaute? Esse construtor poderia ter um gerenciador de leiaute sem precisar
receber um como argumento? Explique para que serve cada um dos argumentos (se houver) dos
3 objetos gerenciadores de leiaute criados no método main.
Módulo 3 – Swing parte 2: Utilização de objetos visualmente
Labels
Um label (rótulo) é um componente retangular que exibe texto que não pode ser editado pelo
usuário (mas pode ser alterado pelo programa). A classe JLabel cria rótulos no Swing. Aqui
apresentamos dois construtores e alguns métodos:
public JLabel(String texto)
public JLabel(ImageIcon imagem)
public String getText()
public void setText(String texto)
public void setText(String texto, int alinhamento)
15
public void setForeground(Color cor)
public void setBackground(Color cor)
public void setOpaque(boolean b)
JLabel(String texto) constrói um rótulo que exibe o texto: texto;
JLabel(ImageIcon imagem) constrói um rótulo que exibe a imagem: imagem;
getText() devolve o texto atualmente exibido no rótulo como uma String;
setText(String texto) substitui o texto atualmente exibido no rótulo pelo texto: texto. O
novo texto é instantaneamente apresentado no rótulo;
setText(String texto, int alinhamento) substitui o texto atualmente exibido no rótulo
pelo texto: texto. Ele também ajusta o alinhamento do texto à esquerda, à direita ou ao centro.
Os valores possíveis para alinhamento são encontrados na classe SwingConstants; por
exemplo, use SwingConstants.CENTER para centralizar o texto no rótulo;
setForeground(Color cor) ajusta a cor do texto para cor;
setBackground(Color cor) ajusta a cor do fundo do rótulo para cor. Note que rótulos são
transparentes por padrão e suas cores de fundo não são visíveis. De fato, observa-se que a cor
do componente pai é a que se destaca. Para mudar a cor de fundo de um rótulo primeiro deve-se
torná-lo opaco usando-se o método setOpaque;
setOpaque(boolean b) torna o rótulo transparente se b for false e opaco se b for true.
Buttons
Buttons (botões) são áreas retangulares, geralmente com uma linha delineando-as, que – tal
como os rótulos – podem exibir texto. Eles diferem dos rótulos porque podem disparar eventos.
Um evento ocorre sempre que um botão é pressionado. O sistema em tempo de execução do
Java monitora botões e reconhece quando um evento desse tipo ocorre. Note que um botão não é
necessariamente pressionado clicando-o com o mouse, pode haver também um dedo
pressionando-o em uma tela sensível a toque (as chamadas touch screens). A fim de detectar
quando um botão é pressionado, alguém fica de olho nele; esse alguém é o listener (observador),
um componente não gráfico da biblioteca AWT. O observador tem que estar associado ao botão
para que possa monitorá-lo. Se ocorrer um evento com o botão em tempo de execução, o sistema
informará o observador, que poderá então analisar o evento e dar início a alguma ação específica.
A classe JButton representa botões no Swing. Apresentaremos apenas o construtor e o método
que associa um observador ao botão:
public JButton(String texto);
public void addActionListener(ActionListener observador);
JButton(String texto) constrói um botão que contém o texto: texto;
addActionListener(ActionListener observador) adiciona um observador que detectará
eventos ocorridos no botão.
16
Menus
Menus são normalmente muito utilizados como componentes de frames. Eles estão organizados
hierarquicamente. O componente mais elevado dessa hierarquia é a barra de menu, uma área
retangular localizada abaixo da barra de título de um frame e acima do painel de conteúdo. Os
componentes intermediários são os menus. Um menu aparece como um texto na barra de menu.
Quando alguém clica em um desses textos, o menu selecionado se descortina, apresentando
diversos itens de menu, que estão na base da hieraquia. Os itens de menu são componentes que
disparam eventos. Eles podem ser considerados como um tipo especial de botão. De fato, tal
como os botões, os itens de menu fazem uso de observadores de eventos para monitorá-los.
Às vezes é necessário desabilitar determinados itens de menu por algum período de tempo. Um
item de menu desabilitado não dispara nenhuma ação quando é clicado. Em muitas plataformas o
texto de um item de menu desabilitado aparece esmaecido em relação aos itens habilitados. A
barra de menu é representada pela classe JMenuBar:
JMenuBar()
add(JMenu menu)
JMenuBar() constrói uma barra de menu;
add(JMenu menu) adiciona um menu em uma barra de menu.
Os menus são adicionados à barra de menu da esquerda para a direita na ordem dos comandos
add. Para adicionar uma barra de menu em um frame, usamos o seguinte método da classe
JFrame:
setJMenuBar(JMenuBar barraDeMenu)
Note que existem dois métodos distintos: setJMenuBar e setMenuBar para adicionar um
JMenuBar (usando Swing) e um MenuBar (usando AWT).
Da classe JMenu precisamos do construtor que recebe o título do menu em uma string e métodos
para adicionar itens de menu ou separadores, que são linhas horizontais que separam os itens de
menu em blocos:
JMenu(String tituloDoMenu)
add(JMenuItem itemDeMenu)
addSeparator()
Em um menu, os itens de menu ou separadores são inseridos do topo para a base na ordem dos
comandos add.
Finalmente, da classe JMenuItem necessitamos do construtor que recebe o título do item em
uma string e um método para associar um observador de eventos ao item de menu. Os itens de
menu comportam-se de modo muito semelhante aos botões. Em particular, o observador de
eventos (action listener) é automaticamente informado quando o item é clicado. O observador
então inicia as ações desejadas. Finalmente precisamos de um método para habilitar ou
desabilitar um item de menu:
17
JMenuItem(String textoDoItem)
addActionListener(ActionListener observador)
setEnabled(boolean b)
A chamada setEnabled(false) desabilita um item de menu. O item aparece com um texto
suavizado e qualquer observador associado a ele não é mais notificado cada vez que o item for
clicado. Assim, um item desabilitado não dispara qualquer reação na aplicação. Chamando
setEnabled(true) habilitará o item de menu novamente. O texto torna-se bem destacado e os
observadores associados ao item de menu passam a ser notificados dos eventos.
Exercícios de Laboratório do módulo 3
Neste laboratório teremos o primeiro exemplo de uma aplicação GUI real. Real aqui significa que
teremos um programa que interage com o usuário. A interação é realizada usando botões e itens
de menu em uma tela gráfica. Apesar de o programa ser muito simples, gostaríamos de introduzir
o conceito de uma abordagem modelo-visão-controle (model-view-control ou MVC) neste ponto. A
parte referente ao modelo do programa, não gráfica, lida com o armazenamento, manutenção e
manipulação de dados. A parte referente à visão exibe os dados e fornece os componentes
necessários à interação com o usuário, neste caso, botões e menu. A parte referente ao controle,
também não gráfica, assegura que as ações do usuário resultarão nas respostas desejadas dadas
pelo programa. A parte de controle é a ponte entre o modelo e a visão.
A separação em estruturas de modelo, visão e controle geralmente é uma abordagem
fundamental para o desenvolvimento de uma aplicação rápida e com sucesso. Ela também auxilia
os programadores iniciantes a melhor reconhecer os conceitos essenciais e suas interconexões.
Em Java, tal separação é facilmente obtida usando-se orientação a objetos, isto é, diferentes
classes ou ao menos diferentes métodos para diferentes partes. Em aplicações complexas,
pacotes separados (com seus conjuntosde classes) podem ser usados para partes diferentes da
aplicação.
Vamos então iniciar a especificação da interface gráfica de usuário que queremos representar.
Queremos montar um contador. Ele está especificado como uma estrutura de dados abstrata. O
contador possui uma variável chamada valor do tipo inteiro. Inicialmente ela vale zero. O contador
permite três operações:
• Incremento – incrementa o valor do contador de 1;
• Decremento – decrementa o valor do contador de 1;
• Restauro – reinicia o valor do contador para 0.
Vamos agora definir a aparência da tela e como ela funcionará. A GUI que temos em mente deve
exibir o valor atual do contador e permitir que o usuário possa incrementá-lo, decrementá-lo ou
restaurá-lo. Para esta finalidade teremos três botões. Pressionando o primeiro (incrementar) com
o mouse, incrementaremos o contador. Pressionando o segundo (decrementar) decrementaremos
o contador e pressionando o terceiro (restaurar) zeraremos o contador. Estas opções deverão
18
estar disponíveis também no menu. Assim, teremos um menu Opções com os seguintes itens de
menu: Incrementar, Decrementar e Restaurar. E um segundo menu Programa com o item de
menu Sair, para finalizar a aplicação. A figura abaixo mostra como queremos que a GUI se
pareça.
Vamos agora programar um contador em uma classe não gráfica que chamaremos de Contador.
Esta classe terá apenas uma variável inteira chamada valor que será iniciada em zero no
construtor, conforme exigido pela especificação. A variável valor é privada, de modo que outras
classes só possam manipulá-la através dos métodos fornecidos pela classe Contador.
Representaremos as três operações requeridas na especificação em três métodos com nomes
óbvios: incrementa(), decrementa() e restaura()e um quarto método, getValor(), para
ler o conteúdo da variável valor. Abaixo temos a listagem da classe:
package br.unip.cc4si4.ALPOO;
public class Contador {
private int valor;
//O constructor incia o contador em zero.
public Contador() {
valor = 0;
}
public void incrementa(){
valor++;
}
public void decrementa(){
valor--;
}
public void restaura(){
valor = 0;
}
public int getValor(){
return valor;
}
}
Cuidaremos agora da parte gráfica. Existem muitas maneiras de se arranjar os componentes
(botões, rótulos e menu). Uma delas seria “colar” os botões, o rótulo e o menu diretamente no
painel de conteúdo do frame. Utilizaremos aqui uma abordagem diferente: aplicaremos no painel
de conteúdo do frame um panel intermediário que ficará responsável por embutir os botões, o
rótulo e o menu. A classe responsável por essa disposição de elementos será chamada
PainelDoContador. Assim, PainelDoContador é que será colada ao frame. A vantagem
Incrementar
☺ Aplicação 1 x □ _
Decrementar
Restaurar
Rótulo
contendo o
valor do
contador
Opções
Incrementar
Decrementar
Restaurar
Programa
19
desta abordagem é que se pode reutilizar a classe PainelDoContador como um módulo pronto
em outras aplicações. Reutilização de código, portanto. Veja na figura abaixo a disposição desses
elementos na aplicação:
Abaixo, temos a listagem da classe PainelDoContador:
package br.unip.cc4si4.ALPOO;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JMenuBar;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import javax.swing.SwingConstants;
public class PainelDoContador extends JPanel {
private Contador contador;
private JLabel valorDoLabel;
public PainelDoContador() {
//Cria um objeto contador e define o
//gerenciador de leiaute como sendo BorderLayout.
contador = new Contador();
BorderLayout bordLay = new BorderLayout();
this.setLayout(bordLay);
//Cria uma barra de menu e a adiciona ao panel
JMenuBar barraDeMenu = new JMenuBar();
this.add(barraDeMenu,BorderLayout.NORTH);
//Cria e adiciona os menus à barra de menu
JMenu opcoes = new JMenu("Opções");
JMenu programa = new JMenu("Programa");
barraDeMenu.add(opcoes);
barraDeMenu.add(programa);
//Cria os itens de menu e os adiciona aos menus
JMenuItem incrementar = new JMenuItem("Incrementar");
JMenuItem decrementar = new JMenuItem("Decrementar");
JMenuItem restaurar = new JMenuItem("Restaurar");
JMenuItem sair = new JMenuItem("Sair");
opcoes.add(incrementar);
opcoes.add(decrementar);
opcoes.addSeparator();
opcoes.add(restaurar);
programa.add(sair);
//Cria os botões de incrementar, decrementar e restaurar
//e cria o rotulo que exibe o valor do contador.
JButton botaoIncrementa = new JButton("Incrementar");
JButton botaoDecrementa = new JButton("Decrementar");
JButton botaoRestaura = new JButton("Restaurar");
valorDoLabel = new JLabel(""+contador.getValor(),SwingConstants.CENTER);
//Adiciona os botões e o rótulo no panel utilizando as regras
//de posicionamento de elementos do gerenciador de objetos BorderLayout.
this.add(botaoIncrementa,BorderLayout.WEST);
this.add(botaoDecrementa,BorderLayout.EAST);
this.add(botaoRestaura,BorderLayout.SOUTH);
this.add(valorDoLabel,BorderLayout.CENTER);
}
public void incrementa(){
☺ Aplicação 1
□ _ x
Opções Programa
Incrementar
Decrementar
Restaurar
Rótulo contendo o
valor do contador
JFrame
JPanel
JMenuBar
JButton
JLabel
20
contador.incrementa();
valorDoLabel.setText(""+contador.getValor());
}
public void decrementa(){
contador.decrementar();
valorDoLabel.setText(""+contador.getValor());
}
public void restaura(){
contador.restaurar();
valorDoLabel.setText(""+contador.getValor());
}
}
E em seguida, a listagem da classe JanelaDoContador, que é o frame responsável por embutir
o panel PainelDoContador:
package br.unip.cc4si4.ALPOO;
import javax.swing.JFrame;
import java.awt.BorderLayout;
public class JanelaDoContador extends JFrame {
public JanelaDoContador(){
//Define o tamanho e a posição do frame na tela
this.setSize(300,200);
this.setLocation(200,200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Cria e insere um panel do tipo PainelDoContador
PainelDoContador pdc = new PainelDoContador();
this.getContentPane().add(pdc,BorderLayout.CENTER);
}
public void exibeFrame(String title){
this.setTitle(title);
this.setVisible(true);
}
public void ocultaFrame(){
this.setVisible(false);
}
public static void main(String[] args) {
//Cria um objeto frame e o exibe na tela
JanelaDoContador jdc = new JanelaDoContador();
jdc.exibeFrame("Aplicação 1");
}
}
Se você rodar o programa, observará que ao clicar nos botões ou nos itens de menu nada
acontece. A conexão entre as ações do usuário (como pressionar um botão) e a aplicação é
estabelecida pelos observadores (listeners). Estes são componentes não-gráficos fornecidos pela
biblioteca AWT: java.awt.events.*. Existem diferentes observadores para diferentes tipos de
eventos (pressionar um botão, mover o mouse, etc.). Observadores são, em geral, interfaces e
não classes.
Vamos começar descrevendo como o conceito de um observador normalmente funciona. Alguns
componentes do Swing são capazes de disparar eventos. Por exemplo, um botão pode ser
pressionado ou um item de menu pode ser selecionado. Tais eventos são automaticamente
notificados pelo Java ao sistema em tempo de execução. Agora,o programador pode criar um
observador e associá-lo ao componente gráfico, digamos um botão. Assim, o observador fica
aguardando até que o botão seja pressionado e tome as ações necessárias se isto acontecer. O
sistema em tempo de execução notifica o observador se o botão foi pressionado. A notificação é
feita chamando-se um método específico do observador. O nome deste método é predefinido na
interface do observador. O programador tem que caracterizar este método inserindo o código que
será executado em resposta ao botão que foi pressionado.
21
Em nossa aplicação, o contador tem que ser incrementado ou decrementado em resposta ao
respectivo botão pressionado. O observador é portanto associado aos três botões, ou seja, ele
monitora todos. Se um botão for pressionado o observador é avisado. A fim de tomar a ação
apropriada ele tem que saber qual botão foi pressionado. Esta informação é fornecida pelo
sistema em tempo de execução na forma de um objeto do tipo ActionEvent. Esta classe
também se encontra na biblioteca AWT (em java.awt.events). Um objeto do tipo
ActionEvent contém informação acerca do evento notificado pelo sistema em tempo de
execução.
Para este exercício, criaremos um observadores na classe ObservadorPainel. Esta classe
representa a interface Java ActionListener. A criação da classe requererá ainda a definição
de um único método actionPerformed (ação executada):
public void actionPerformed(ActionEvent evento)
Este é o método chamado pelo sistema em tempo de execução sempre que um botão for
pressionado ou um item de menu for selecionado. Você não terá que chamar esse método, aliás
nem deve. O sistema em tempo de execução também gera uma ação evento e a passa como
um argumento do método actionPerformed. Este código é então executado em resposta ao
pressionar de um botão. A informação contida na ação evento pode ser utilizada para obter mais
informações sobre o quê disparou o evento. A listagem abaixo é da classe ObservadorPainel:
package br.unip.cc4si4.ALPOO;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ObservadorPainel implements ActionListener{
private PainelDoContador pdc;
public ObservadorPainel(PainelDoContador painel) {
pdc = painel;
}
//Este método é chamado pelo sistema em tempo de execução.
//Você deve adicionar o código a ser executado
//em resposta ao evento.
public void actionPerformed(ActionEvent evento){
//Início do seu código:
String actionCommand = evento.getActionCommand();
if(actionCommand.equals("Incrementar")){
pdc.incrementa();
}
else if(actionCommand.equals("Decrementar")){
pdc.decrementa();
}
else if(actionCommand.equals("Restaurar")){
pdc.restaura();
}
else if(actionCommand.equals("Sair")){
System.exit(0);
}
else{
System.out.println("ERRO: ActionCommand inesperado.");
}
//Fim do seu código
}
}
O coração da classe ObservadorPainel é a codificação do método actionPerformed.
Primeiro, determinamos quais dos botões foi pressionado ou qual dos itens de menu foi
selecionado. Isto é feito inspecionando-se o objeto de ação evento que o método
actionPerformed recebeu do sistema em tempo de execução. A linha:
22
String actionCommand = evento.getActionCommand();
Extrai o comando da ação do objeto evento. O comando da ação é geralmente o texto do botão
que foi pressionado ou o texto do item de menu. Em nosso caso ele só pode ser “Incrementar”,
“Decrementar”, “Restaurar” ou “Sair”. Para verificar qual desses textos foi obtido usamos uma
estrutura if-then-else. Dependendo do resultado do teste, chamamos o método incrementa(),
decrementa() ou restaura() do painel, ou ainda finalizamos a aplicação. Neste ponto vemos
porque ao observador é dada uma referência para um objeto PainelDoContador no construtor
da classe. O observador, dessa maneira, sabe qual painel ele tem que atuar em resposta ao
evento. Isto é importante se tivermos diversos painéis em uma aplicação. Para fazer com que o
painel e o observador se comuniquem, acrescente no construtor da classe PainelDoContador
as seguintes linhas de código:
//Cria os observadores de botao.
ObservadorPainel op = new ObservadorPainel(this);
botaoIncrementa.addActionListener(op);
botaoDecrementa.addActionListener(op);
botaoRestaura.addActionListener(op);
//Cria os observadores de menu/itens de menu.
opcoes.addActionListener(op);
incrementar.addActionListener(op);
decrementar.addActionListener(op);
restaurar.addActionListener(op);
sair.addActionListener(op);
1. Desenhe o diagrama de classes do pacote br.unip.cc4si4.ALPOO, apresentando os
métodos de cada classe e as relações entre as classes, inclusive as classes da biblioteca Swing
utilizadas para gerar os diferentes componentes gráficos desta aplicação.
Módulo 4 – Swing parte 3: Tratamento de eventos
Caixas de texto
Caixas de texto apresentam uma única linha de texto. O texto pode ser editado pelo usuário. A
classe JTextField representa caixas de texto no Java. Para editar um texto, clique dentro da
caixa de texto e um cursor piscante aparecerá. A caixa de texto automaticamente desloca o
conteúdo na horizontal se o texto for maior que a caixa. Esta funcionalidade é inerente. Caixas de
texto são opacas e têm cor de fundo branca e texto preto por padrão. Abaixo, o construtor e
alguns métodos:
public JTextField(String texto)
public String getText()
public void setText(String texto)
public void setForeground(Color cor)
public void setBackground(Color cor)
JTextField(String texto) constrói uma caixa de texto que exibe texto.
setText(String texto) substitui o texto atualmente exibido na caixa de texto por texto.
getText() devolve o texto atualmente exibido na caixa de texto no formato String.
23
setForeground(Color cor) ajusta a cor do texto para cor.
setBackground(Color cor) ajusta a cor de fundo para cor.
Botões de rádio
Botões de rádio são representados usando-se a classe JRadioButton. Um botão de rádio é
retangular. Ele contém uma área circular à sua esquerda e um rótulo à sua direita. Botões de rádio
podem ser pressionados bem como podem ser agrupados. Somente um botão de rádio pode ser
pressionado de cada vez e o botão permanecerá pressionado até que outro botão do grupo o
seja. Um ponto preto surge dentro da área circular do botão que for selecionado. A seguir, o
construtor e alguns de seus métodos:
JRadioButton(String nomeDoBotao)
setSelected(boolean pressionado)
setActionCommand(String comando)
String getActionCommand()
JRadioButton(String nomeDoBotao) cria um botão rotulado de nomeDoBotao.
setSelected(boolean pressionado) determina qual botão foi selecionado (pressionado
= true) ou não (pressionado = false). No primeiro caso o ponto preto fica visível dentro da
área circular do botão. Este método é utilizado inicialmente para definir qual dos botões estará
pressionado antes da primeira interação com o usuário.
setActionCommand(String comando) associa a string comando como uma ação de
comando para o botão. Botões de rádio não são associados automaticamente a uma ação de
comando. Isto porque seus rótulos geralmente recebem uma imagem e não um texto. Definimos a
ação de comando nós mesmos através do método setActionCommand.
getActionCommand() devolve a ação de comando associada ao botão de rádio.
Além disso, devemos nos certificar que somente um botão será pressionado de cada vez. Isto é
conseguido agrupando-se os botões. Usamos para isso a classe ButtonGroup da biblioteca AWT.
Abaixo listamos o seu construtor e alguns métodos:
JButtonGroup()
add(JRadioButton botao)
String getSelection().getActionCommand()
JButtonGroup() constrói um grupo de botões mas ainda sem conter nenhum botão.add(JRadioButton botao) adiciona o botão de rádio botao ao grupo.
String getSelection().getActionCommand() devolve a ação de comando do botão que
estiver atualmente selecionado dentro do grupo.
Uma vez os botões dentro de um grupo, somente um de cada vez pode ser pressionado.
Pressionar um botão não pressionado libera o que estiver pressionado.
24
Botões de seleção
O botão de seleção pode ser utilizado para indicar conjuntos de opções em que nenhuma, uma,
várias ou todas as opções são selecionadas. Botões de seleção são representados pela classe
JCheckBox. Um botão de seleção é retangular e contém uma área quadrada à sua esquerda e
um rótulo à sua direita. Quando um botão de seleção é pressionado, um sinal de verificação (�)
surge na área quadrada do botão. A seguir, um de seus construtores:
JCheckBox(String texto)
JCheckBox(String texto) constrói um botão de seleção rotulado de texto.
Exercícios de Laboratório do módulo 4
1. Construir uma aplicação que contenha um frame, um panel e, dentro deste, uma caixa de texto,
um botão e dois rótulos. Esta aplicação deve ser capaz de ler uma temperatura em graus Celsius
fornecida pelo usuário e convertê-la em Farenheit, ao clicar o botão da aplicação. Abaixo, a
listagem da classe JanelaTemperaturas:
package br.unip.cc4si4.ALPOO;
import java.awt.BorderLayout;
import javax.swing.JFrame;
public class JanelaTemperaturas extends JFrame {
public JanelaTemperaturas(){
//Define o tamanho e a posição do frame na tela
this.setSize(200, 100);
this.setLocation(200, 200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Cria e insere um panel do tipo PainelTemperaturas
PainelTemperaturas pt = new PainelTemperaturas();
this.getContentPane().add(pt, BorderLayout.CENTER);
}
public void exibeFrame(String title){
this.setTitle(title);
this.setVisible(true);
}
public static void main(String[] args){
JanelaTemperaturas jt = new JanelaTemperaturas();
jt.exibeFrame("Conversor");
}
}
A seguir, a listagem do panel PainelTemperaturas:
package br.unip.cc4si4.ALPOO;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JTextField;
import java.awt.GridLayout;
public class PainelTemperaturas extends JPanel {
private JLabel rotuloCelsius, rotuloFarenheit;
private JButton botaoConverteTemperatura;
private JTextField caixaTextoTemperatura;
public PainelTemperaturas(){
//Define o gerenciador de leiaute
GridLayout gridlayout = new GridLayout(2,2,1,1);
this.setLayout(gridlayout);
//Cria, na sequência indicada, uma caixa de texto
//um rótulo, um botão e outro rótulo
caixaTextoTemperatura = new JTextField();
rotuloCelsius = new JLabel("Celsius", JLabel.RIGHT);
botaoConverteTemperatura = new JButton("Converter");
rotuloFarenheit = new JLabel("Farenheit", JLabel.RIGHT);
//Acrescenta uma dica na caixa de texto e no
25
//botão para auxílio do usuário
caixaTextoTemperatura.setToolTipText("Temperatura em graus Celsius");
botaoConverteTemperatura.setToolTipText("Converte Celsius para Farenheit");
//Exibe os componentes gráficos no painel
this.add(caixaTextoTemperatura);
this.add(rotuloCelsius);
this.add(botaoConverteTemperatura);
this.add(rotuloFarenheit);
//Insere o observador dos componentes do painel
ObservadorPainelTemperaturas opt = new ObservadorPainelTemperaturas(this);
//Conecta o observador aos componentes
caixaTextoTemperatura.addActionListener(opt);
botaoConverteTemperatura.addActionListener(opt);
}
//Método para leitura do conteúdo da caixa de texto
public float leTemperatura(){
try{
float temp = 1.8f*Float.parseFloat(caixaTextoTemperatura.getText());
rotuloFarenheit.setText(temp+" F");
return temp;
} catch (NumberFormatException nfe) {
rotuloFarenheit.setText("Valor invalido!");
return 0.0f;
}
}
}
E por fim o observador do panel, ObservadorPainelTemperaturas:
package br.unip.cc4si4.ALPOO;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ObservadorPainelTemperaturas implements ActionListener {
//Cria um atributo privado do tipo PainelTemperaturas
private PainelTemperaturas pt;
//Define o construtor da classe que recebe como parâmetro
//o painel PainelTemperaturas
public ObservadorPainelTemperaturas(PainelTemperaturas painel){
pt = painel;
}
//Este método é chamado pelo sistema em tempo de execução
//Você deve adicionar o código a ser executado em resposta ao evento
public void actionPerformed(ActionEvent evento){
//Seu código
pt.leTemperatura();
}
}
2. Construir uma aplicação que contenha dois grupos de botões: um com botões de verificação e
outro com botões de rádio. Incluir também dois rótulos que indiquem as opções feitas pelo
usuário. Utilizar um panel colado ao frame que contenha os dois grupos de botões e seus rótulos.
Para esta aplicação teremos cinco classes: uma para o frame, duas para os panels e demais
componentes gráficos e outras duas classes contendo os observadores de eventos, um para cada
panel. A listagem abaixo apresenta a classe JanelaDeBotoes, que representa o frame:
package br.unip.cc4si4.ALPOO;
import javax.swing.JFrame;
import java.awt.GridLayout;
public class JanelaDeBotoes extends JFrame {
public JanelaDeBotoes(){
//Define o tamanho e a posicao do frame na tela
this.setSize(200,150);
this.setLocation(200,200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Cria e define o gerenciador de leiaute do frame
GridLayout gridlayout = new GridLayout(1,2);
this.setLayout(gridlayout);
//Cria a insere o panel PainelBotaoDeRadio no frame
PainelBotaoDeRadio pbdr = new PainelBotaoDeRadio();
this.getContentPane().add(pbdr);
//Cria e insere o panel PainelBotaoDeVerificacao no frame
PainelBotaoDeVerificacao pbdv = new PainelBotaoDeVerificacao();
this.getContentPane().add(pbdv);
26
}
public void exibeFrame(String titulo){
this.setTitle(titulo);
this.setVisible(true);
}
public void ocultaFrame(){
this.setVisible(false);
}
public static void main(String[] args){
JanelaDeBotoes jdb = new JanelaDeBotoes();
jdb.exibeFrame("Aplicação 2");
}
}
A seguir, a listagem de PainelBotaoDeRadio, que gera um panel que será colado ao frame:
package br.unip.cc4si4.ALPOO;
import javax.swing.JPanel;
import javax.swing.ButtonGroup;
import javax.swing.JRadioButton;
import javax.swing.JLabel;
import java.awt.GridLayout;
public class PainelBotaoDeRadio extends JPanel {
private JRadioButton rb[] = new JRadioButton[3];
private JLabel botaoradio = new JLabel("Sem seleção");
public PainelBotaoDeRadio(){
//Define o gerenciador de leiaute do panel
GridLayout gridleiaute = new GridLayout(4,1);
this.setLayout(gridleiaute);
//Cria um grupo de botões
ButtonGroup bg = new ButtonGroup();
//Cria o observador dos botões de rádio
ObservadorDoPainelBotaoDeRadio opbr = new ObservadorDoPainelBotaoDeRadio(this);
//Cria e insere os botões de verificação no panel, o grupo de botões
//bem como os seus observadores de evento
for(int i=0; i<3; i++){
this.add(rb[i] = new JRadioButton("Alternativa "+(i+1)));
bg.add(rb[i]);
rb[i].addItemListener(opbr);
}
//Insere o label no panel bem como o seu observador de evento
this.add(botaoradio);
}
//Método para renomear o texto do label: botaoradio
public void renomeiaBotaoRadio(String nome){
botaoradio.setText(nome);
}
}
Agora, a listagem de PainelBotaoDeVerificação:
package br.unip.cc4si4.ALPOO;import javax.swing.JPanel;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import java.awt.GridLayout;
public class PainelBotaoDeVerificacao extends JPanel {
private JCheckBox cb[] = new JCheckBox[3];
private JLabel botaoverificacao = new JLabel("Sem seleção");
public PainelBotaoDeVerificacao(){
//Define o gerenciador de leiaute do panel
GridLayout gridleiaute = new GridLayout(4,1);
this.setLayout(gridleiaute);
//Cria o observador de botões de verificação
ObservadorDoPainelBotaoDeVerificacao opbv = new ObservadorDoPainelBotaoDeVerificacao(this);
//Cria e insere os botões de verificação no panel
//bem como os seus observadores de evento
for(int i = 0; i<3; i++){
this.add(cb[i] = new JCheckBox("Alternativa "+(i+1)));
cb[i].addItemListener(opbv);
}
//Insere o label no panel bem como o seu observador de evento
this.add(botaoverificacao);
}
//Método para verificar se um botão foi selecionado
public boolean botaoFoiSelecionado(int i){
27
if(cb[i].isSelected())
return true;
else
return false;
}
//Método para renomear o label botaoverificacao
public void renomeiaBotaoVerificacao(String nome){
botaoverificacao.setText(nome);
}
}
Temos em seguida a listagem do observador ObservadorDoPainelBotaoDeRadio:
package br.unip.cc4si4.ALPOO;
import javax.swing.JRadioButton;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
public class ObservadorDoPainelBotaoDeRadio implements ItemListener {
//Cria um atributo privado do tipo PainelBotaoDeRadio
private PainelBotaoDeRadio pbdr;
//Define o construtor da classe que recebe como parametro
//o painel PainelBotaoDeRadio
public ObservadorDoPainelBotaoDeRadio(PainelBotaoDeRadio painel){
pbdr = painel;
}
//Este metodo e chamado pelo sistema em tempo de execucao
//Voce deve adicionar o codigo a ser executado em resposta ao evento
public void itemStateChanged(ItemEvent evento){
//Inicio do seu codigo:
JRadioButton rb = (JRadioButton)evento.getSource();
String nomeDoBotao = rb.getText();
pbdr.renomeiaBotaoRadio("Selecao: " + nomeDoBotao.charAt(nomeDoBotao.length()-1));
//Fim do seu codigo.
}
}
Finalmente, a listagem do ObservadorDoPainelBotaoDeVerificacao:
package br.unip.cc4si4.ALPOO;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
public class ObservadorDoPainelBotaoDeVerificacao implements ItemListener {
//Cria um atributo privado do tipo PainelBotaoDeVerificacao
private PainelBotaoDeVerificacao pbdv;
//Define o construtor da classe que recebe como parametro
//o painel PainelBotaoDeVerificacao
public ObservadorDoPainelBotaoDeVerificacao(PainelBotaoDeVerificacao painel){
pbdv = painel;
}
//Este metodo e chamado pelo sistema em tempo de execucao
//Voce deve adicionar o codigo a ser executado em resposta ao evento
public void itemStateChanged(ItemEvent evento){
//Inicio do seu codigo:
StringBuffer itens = new StringBuffer("Selecao: ");
for(int i=0; i<3; i++){
itens.append(pbdv.botaoFoiSelecionado(i)?(i+1)+" ":"");
}
pbdv.renomeiaBotaoVerificacao(itens.toString());
//Fim do seu codigo.
}
}
3. Desafio: construir uma calculadora em Java. A calculadora deve ter: um JTextField onde o
usuário visualiza os números e as contas; JButtons para cada número e pelo menos as quatro
operações básicas, além de botões para limpar e corrigir, bem como um JPanel que receberá os
componentes gráficos e será colado ao frame, criado com um JFrame. Os botões com números
devem reagir às ações do teclado e somente responder a teclas numéricas, ponto decimal e sinais
para soma, subtração, divisão e multiplicação. Para isso, deve-se utilizar o observador de eventos
de teclado: KeyListener e criar uma classe observadora que trate os eventos gerados pelo
teclado com o KeyEvent. A aplicação pode ser aprimorada com um menu, via JMenu.