• Nenhum resultado encontrado

Lista de Códigos

6.4 Swing

Quando a versão 1.0 da linguagem Java foi lançada, apenas continha a biblioteca AWTpara a programação de interfaces gráficas. Conforme dito, a grande desvantagem da utilização da bibliotecaAWTé que componentes gráficos têm diferentes aparências (look-and-feel) se executados em diferentes sistemas operacionais.

A biblioteca Swing é definida através das classes do pacote javax.swing e consiste em uma extensão padronizada da bibliotecaAWTque congrega componentes gráficos que utilizam exclusivamente Java (lightweight components), com funcionali- dades e aparência independentes do sistema em que a aplicação é executada.

A biblioteca Swing é compatível com o AWT, mas trabalha de uma maneira totalmente diferente. A biblioteca Swing procura renderizar/desenhar por conta própria todos os componentes, ao invés de delegar essa tarefa ao sistema operacional.

Por ser uma biblioteca de mais alto nível, ou seja, mais abstração, menor aproximação dasAPIs do sistema operacional, ela tem bem menos performance que outras APIs gráficas (por exemplo, AWT) e consome mais memória RAM em geral. Porém, ela é bem mais completa, e os programas que usam a bibliotecaSwingtêm uma aparência muito parecida, independentemente do sistema operacional utilizado.

Uma discussão extensiva da biblioteca Swing encontra-se fora do escopo deste material. Esta seção apenas apresenta uma visão geral das funcionalidades providas pela biblioteca Swing com o objetivo de ressaltar as diferenças e 162

semelhanças com a biblioteca AWT discutida anteriormente. Para um estudo mais aprofundado da bibliotecaSwing, o leitor interessado pode consultar o seguinte link:

http://docs.oracle.com/javase/tutorial/uiswing.

6.4.1 Componentes gráficos

De maneira análoga à biblioteca AWT, na biblioteca Swing um objeto de in- terface como um botão ou uma barra de rolagem é chamado de componente. A classe JComponent é a raiz de todos os componentes Swing. A Figura 6.11 apre- senta a hierarquia de componentes gráficos presentes na biblioteca Swing (pacote javax.swing). Conforme se pode observar por essa figura, a classe JComponent é derivada da classeComponent, raiz da hierarquia de componentes AWT.

Figura 6.11 Hierarquia de componentes gráficos presentes na bibliotecaSwing.

Embora a classe JComponent, raiz da hierarquia de componentes Swing, seja derivada da classe java.awt.Container, não se pode acrescentar diretamente um componente gráfico a qualquer componente Swing. Para as classes Swing que correspondem acontainers no sentido definido pela bibliotecaAWT, ou seja, às quais podem ser acrescentados outros componentes, deve-se obter uma referência ao objeto Containeratravés do método getContentPane().

163

Eventos. Os eventos em componentes Swing são os mesmos da biblioteca AWT, presentes no pacotejava.awt.event. Ou seja, o modelo de tratamento de eventos da bibliotecaAWTse aplica também a componentesSwing.

Janelas. A biblioteca Swing também oferece a sua versão de um frame através da classe JFrame, que é uma extensão da classe Frame. As Figuras 6.12 e 6.13 apresentam dois exemplos simples deframesSwingque contêm componentes gráficos.

NoframedoAWT, quando o usuário clica no botão fechar, nada acontece até que o evento de fechar a janela seja tratado. NoSwing, por padrão, a janela é escondida quando o usuário clica no botão de fechar. Observe que a janela será escondida, mas a aplicação Java não é finalizada.

O projetista pode determinar outras opções para quando o usuário clicar no botão de fechar – determinadas pelo método setDefaultCloseOperation() do JFrame.

Os argumentos para esse método podem ser:

DO_NOTHING_ON_CLOSE – não faz nada quando o usuário clica no botão de fechar. Nesse caso, o programa poderia usar uma classe que implementa a interface WindowListener que execute uma outra ação em seu método windowClosing().

HIDE_ON_CLOSE(o padrão) – esconde oframe. Remove-o da tela.

DISPOSE_ON_CLOSE – faz a mesma coisa que o método dispose(). Remove oframeda tela e libera os recursos usados.

Gerenciador de leiautes. É possível também determinar um gerenciador de leiaute para um frame Swing. Esse gerenciador de leiaute deve ser aplicado ao objeto Container, obtido através do método getContentPane(), assim como os com- ponentes (botões, rótulo, etc.) também devem ser adicionados aoContentPane do JFrame. Os gerenciadores de leiaute definidos na biblioteca AWTpodem ser também aplicados a componentes Swing. As Figuras 6.14 e 6.15 apresentam dois exemplos simples deframes Swing que contêm um gerenciador de leiaute associado.

Botões. EmSwing, o componente que define um botão é JButton. Além de poder ser definido com rótulos de texto, um botão Swing pode conter também ícones. A Figura 6.12 apresenta um exemplo de dois botõesSwing com ícones.

164

Figura 6.12 Componentes gráficosSwing– classeJButton.

Campos de Seleção. A classeJComboBoxpermite a seleção de uma opção entre as opções exibidas. É semelhante à classeList, da biblioteca AWT, discutida anterior- mente. A Figura 6.13 apresenta um exemplo de umcombo box Swing.

Figura 6.13 Componentes gráficosSwing– classeJComboBox.

A classeJCheckBoxfunciona de maneira análoga à classeCheckboxdoAWT. Ou seja, permite a escolha de um ou mais itens a partir de um conjunto de elementos exibidos. A Figura 6.14 apresenta um exemplo de umcheck box Swing.

Figura 6.14 Componentes gráficosSwing– classeJCheckBox.

165

Conforme se pode observar, a Figura 6.14 é bastante similar à Figura 6.4. A interface é a mesma, o que diferencia mesmo são os componentes gráficos utilizados (JFrame,JCheckBox, etc.).

A classe JRadioButton implementa radio buttons. A utilização da classe JRadioButton, associada à classe ButtonGroup, permite que apenas uma das opções exibidas seja escolhida, enquanto o JCheckBox permite múltipla escolha. A Figura 6.15 apresenta um exemplo de umradio button Swing.

Figura 6.15 Componentes gráficosSwing – classeJRadioButton.

Campos de Texto. OJTextFieldé uma área de edição de texto de uma única linha.

Esse componente é equivalente ao componenteTextFieldda bibliotecaAWT. Quando o usuário digitar todo o texto noJTextField, ele pode clicar na teclareturn/enter (que acionará um evento do tipoActionEvent).

OJTextAreaé uma área de edição de texto de múltiplas linhas. Esse componente é equivalente ao componente TextArea da biblioteca AWT. Tendo em vista que no JTextArea a tecla return/enter insere uma nova linha, é comum utilizar um JButtonpara capturar eventos associados a um JTextArea.

Para criação de rótulos, a biblioteca Swing disponibiliza a classe JLabel. O JLabelpermite a apresentação de conteúdo puramente textual, assim como oLabel da bibliotecaAWT, e também imagens.

A Figura 6.16 apresenta um exemplo de um frame simples composto de dois rótulos (objetosJLabel), uma área de texto (objetoJTextArea) e um campo de texto (objetoJTextField). O campo de texto foi configurado de tal forma que não pode ser editado pelo usuário (métodosetEditable(false)). A área de texto foi associada a uma instância de uma classe manipuladora de eventos – classe KeyHandler que é subclasse da classe adaptadora java.awt.event.KeyAdapter. Como pode ser 166

Figura 6.16 Componentes gráficosSwing– campos de texto.

observado pelo Código 6.2, essa classe possui uma referência ao campo texto (atributo field) e trata os eventos do teclado (interface KeyListener) de tal forma que, a cada tecla digitada, o número de caracteres presente na área de texto (texto) é contabilizado, e esse valor é apresentado no campo de texto (numCaracteres).

/∗∗

C l a s s e K e y H a n d l e r T r a t a o s e v e n t o s do t e c l a d o ( i n t e r f a c e K e y L i s t e n e r ) .

A c a d a t e c l a d i g i t a d a , o número de c a r a c t e r e s p r e s e n t e na ár e a de t e x t o é c o n t a b i l i z a d o

@ a u t h o r D e l a n o M e d e i r o s B e d e r

/

p u b l i c c l a s s K e y H a n d l e r e x t e n d s K e y A d a p t e r {

p r i v a t e J T e x t F i e l d f i e l d ;

p u b l i c K e y H a n d l e r ( J T e x t F i e l d f i e l d ) { t h i s. f i e l d = f i e l d ;

}

p u b l i c v o i d k e y R e l e a s e d ( K e y E v e n t e ) {

J T e x t A r e a a r e a = ( ( J T e x t A r e a ) e . g e t C o m p o n e n t ( ) ) ;

f i e l d . s e t T e x t ( I n t e g e r . t o S t r i n g ( a r e a . g e t T e x t ( ) . l e n g t h ( ) ) ) ; }

}

Código 6.2 Classehandlerde eventos do teclado.

Caixas de Diálogo. Na bibliotecaSwing, as caixas de diálogo são criadas a partir da classe JOptionPane ou da classe JDialog. A classe JOptionPane é recomendada quando se deseja criar caixas de diálogos mais simples, enquanto a classe JDialog para quando se deseja criar uma caixa de diálogo mais sofisticada, com todas as funcionalidades de um frame. A classe JFileChooser fornece uma janela para navegação pelo sistema de arquivos. Instâncias dessa classe permitem escolher um arquivo para abrir ou especificar o diretório em que um arquivo será salvo. A classe JFileDialog equivale à classeFileDialog da bibliotecaAWT.

167

Menus. O menu emSwingfunciona de maneira análoga ao menu da biblioteca AWT.

Os passos são semelhantes ao realizados na Seção 6.3 para construir um menuAWT.

(a) Criação de uma barra de menu, representada pela classeJMenuBar, e a posterior adição dessa barra de menu aoframe Swing.

(b) Criação de instâncias da classe JMenu e a posterior adição à barra de menu criada anteriormente. No exemplo apresentado na Figura 6.17, foram criados dois menus: Arquivoe Ajuda.

(c) Criação dos itens de menu, representados pela classeJMenuItem, para os menus (instâncias deJMenu) criados anteriormente. Como se pode observar, é possível adicionar teclas de atalho (por exemplo,CTRL+A) aos itens de menu e criar itens de menu para seleção on/off (instâncias da classe JCheckboxMenuItem). E, por fim, foi utilizado um separador (métodoaddSeparator()) para dividir os itens.

Figura 6.17 Componentes gráficosSwing – menus.

6.4.2 Editor de texto

Finalizando a discussão sobre as bibliotecas Swing e AWT, esta seção apresenta um editor de texto simples implementado utilizando algumas das classes presentes nessas bibliotecas. A implementação Java desse editor de texto é composta de três classes: Editor,FileUtile Handler.

O Código 6.3 apresenta a classeEditor, que é umcontaineronde os componentes gráficosSwing (menu, barra de rolagem, área de texto, etc.) são inseridos.

168

O método configure(), invocado pelo construtor da classe, é responsável por realizar as configurações do editor de texto, assim como inserir os componentes gráficos noframe.

Nas linhas 21-24 são criados um painel com barras de rolagem vertical e hori- zontal (instância da classe JPaneScroll) e uma área de texto (instância da classe JTextArea) que apresenta o texto editado. Observe que a área de texto é associada a uma instância da classeHandler, que é responsável por tratar os eventos de teclado nessa área de texto.

1 /∗∗

2 C l a s s e E d i t o r I n t e r f a c e g ráf i c a . C o n t a i n e r o s d e m a i s c o m p o n e n t e s g ráf i c o s são i n s e r i d o s

3

4 @ a u t h o r D e l a n o M e d e i r o s B e d e r

5 /

6 p u b l i c c l a s s E d i t o r e x t e n d s JFrame {

7 p u b l i c s t a t i c f i n a l S t r i n g TITLE = " E d i t o r de T e x t o S i m p l e s " ; 8 p r i v a t e J T e x t A r e a t e x t A r e a ;

9 p r i v a t e H a n d l e r h a n d l e r ; 10

11 p u b l i c E d i t o r ( ) {

12 h a n d l e r =new H a n d l e r (t h i s) ;

13 c o n f i g u r e ( ) ;

14 }

15

16 p u b l i c J T e x t A r e a g e t T e x t A r e a ( ) {

17 r e t u r n t e x t A r e a ;

18 }

19

20 p r i v a t e v o i d c o n f i g u r e ( ) {

21 J S c r o l l P a n e j S c r o l l P a n e =new J S c r o l l P a n e ( ) ; 22 j S c r o l l P a n e . s e t V i e w p o r t V i e w ( t e x t A r e a ) ; 23 t e x t A r e a =new J T e x t A r e a ( ) ;

24 t e x t A r e a . a d d K e y L i s t e n e r ( h a n d l e r ) ; 25 JMenuItem o p e n =new JMenuItem ( " A b r i r " ) ; 26 o p e n . a d d A c t i o n L i s t e n e r ( h a n d l e r ) ;

27 JMenuItem s a v e =new JMenuItem ( " S a l v a r " ) ; 28 s a v e . a d d A c t i o n L i s t e n e r ( h a n d l e r ) ;

29 JMenuItem e x i t = new JMenuItem ( " S a i r " ) ; 30 e x i t . a d d A c t i o n L i s t e n e r ( h a n d l e r ) ; 31 JMenu m e n u F i l e =new JMenu ( " A r q u i v o " ) ; 32 m e n u F i l e . add ( o p e n ) ;

33 m e n u F i l e . add ( s a v e ) ; 34 m e n u F i l e . a d d S e p a r a t o r ( ) ; 35 m e n u F i l e . add ( e x i t ) ;

36 JMenuBar jMenuBar =new JMenuBar ( ) ;

37 jMenuBar . add ( m e n u F i l e ) ;

38 t h i s. s e t J M e n u B a r ( jMenuBar ) ;

39 J P a n e l c o n t e n t P a n e = ( ( J P a n e l ) t h i s. g e t C o n t e n t P a n e ( ) ) ; 40 c o n t e n t P a n e . s e t L a y o u t (new B o r d e r L a y o u t ( ) ) ;

41 c o n t e n t P a n e . add ( j S c r o l l P a n e , B o r d e r L a y o u t . CENTER) ; 42 t h i s. s e t S i z e ( 4 8 0 , 2 8 4 ) ;

43 t h i s. s e t T i t l e ( TITLE ) ;

44 t h i s. s e t D e f a u l t C l o s e O p e r a t i o n ( W i n d o w C o n s t a n t s . DO_NOTHING_ON_CLOSE) ; 45 t h i s. a d d W i n d o w L i s t e n e r ( h a n d l e r ) ;

46 }

47

48 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {

49 E d i t o r e =new E d i t o r ( ) ;

50 e . s e t V i s i b l e (t r u e) ;

51 }

52 }

Código 6.3 ClasseEditor.

169

Nas linhas 25-38, o menu de opções é criado e adicionado ao editor de texto.

Observe que os itens de menu são associados a uma instância da classeHandler, que é responsável por tratar os eventos de cliques nos itens de menu. Por fim, nas linhas 39-45, são realizadas as últimas configurações (leiaute, tamanho, etc.). A Figura 6.18 apresenta o leiaute final do editor de texto.

Figura 6.18 Aplicação gráficaSwing– editor de texto.

O Código 6.4 apresenta a classe FileUtilresponsável pelas tarefas de carregar e salvar arquivos. Observe que os métodos save() e load() utilizam as classes FileWriter,BufferedWriter,FileReadereBufferedReader, discutidas na Uni- dade 4 e que proporcionam operações de entrada e saídabufferizadas.

O método save()recebe como argumentos um nome de arquivo e uma string (no caso, o conteúdo da área de texto presente na interface gráfica) e salva esse conteúdo no arquivo.

O método load() recebe como argumento um nome de arquivo e devolve uma string com todo o conteúdo presente no arquivo. Note a utilização da classe StringBuilder (Seção 3.4.1.1), pois essa é mais eficiente na concatenação de strings.

Por questões de simplicidade, o tratamento das exceções relacionadas às ope- rações de entrada e saída é bastante simplista. Em aplicações mais robustas, o tratamento de exceções deveria ser mais sofisticado.

170

/∗∗

C l a s s e F i l e U t i l R e s p o n sáv e l p e l a s t a r e f a s de c a r r e g a r e s a l v a r a r q u i v o s .

@ a u t h o r D e l a n o M e d e i r o s B e d e r

/

p u b l i c c l a s s F i l e U t i l {

p u b l i c v o i d s a v e ( S t r i n g f i l e N a m e , S t r i n g t e x t o ) { t r y {

F i l e W r i t e r fw =new F i l e W r i t e r ( f i l e N a m e ) ; B u f f e r e d W r i t e r bw =new B u f f e r e d W r i t e r ( fw ) ; bw . w r i t e ( t e x t o ) ;

bw . c l o s e ( ) ;

} c a t c h ( I O E x c e p t i o n e ) { e . p r i n t S t a c k T r a c e ( ) ; }

}

p u b l i c S t r i n g l o a d ( S t r i n g f i l e N a m e ) {

S t r i n g B u i l d e r t e x t o =new S t r i n g B u i l d e r ( ) ; t r y {

F i l e R e a d e r f r =new F i l e R e a d e r ( f i l e N a m e ) ; B u f f e r e d R e a d e r b r =new B u f f e r e d R e a d e r ( f r ) ; S t r i n g s = b r . r e a d L i n e ( ) ;

w h i l e ( s != n u l l) {

t e x t o . a p p e n d ( s ) . a p p e n d ( " \ n " ) ; s = b r . r e a d L i n e ( ) ;

}

b r . c l o s e ( ) ;

} c a t c h ( I O E x c e p t i o n e ) { e . p r i n t S t a c k T r a c e ( ) ; }

r e t u r n t e x t o . t o S t r i n g ( ) ; }

}

Código 6.4 ClasseFileUtil.

O Código 6.5 apresenta a classe Handler. Por questões de simplicidade, nessa aplicação-exemplo foi implementada apenas a classe Handler, que trata todos os eventos possíveis na aplicação. Porém, em sistemas mais robustos, é recomendável a implementação de diferentes classes manipuladoras de eventos (handlers) – cada uma especializada em um tipo de evento.

O método actionPerformed() da interface ActionListener é responsável por tratar os eventos de cliques nos itens de menu. Esse método tem o seguinte comportamento:

• Se o item de menuAbrirfor clicado, execute o métodoload()que é responsável por carregar o conteúdo de um arquivo. Observe que uma instância da classe JFileDialog é utilizada para o usuário escolher o nome do arquivo a ser carregado e posteriormente salvo.

• Se o item de menu Salvar for clicado, execute o método save() que é res- ponsável por salvar o conteúdo da área de texto em um arquivo. As tarefas de carregar e salvar arquivos são delegadas para uma instância da classeFileUtil.

171

/∗∗

C l a s s e H a n d l e r T r a t a o s e v e n t o s da i n t e r f a c e g ráf i c a

@ a u t h o r D e l a n o M e d e i r o s B e d e r

/

p u b l i c c l a s s H a n d l e r e x t e n d s WindowAdapter i m p l e m e n t s A c t i o n L i s t e n e r , K e y L i s t e n e r { p r i v a t e E d i t o r e d i t o r ;

p r i v a t e J F i l e C h o o s e r j F i l e C h o o s e r ; p r i v a t e b o o l e a n c h a n g e d ;

p r i v a t e F i l e U t i l u t i l ;

p u b l i c H a n d l e r ( E d i t o r e d i t o r ) { t h i s. e d i t o r = e d i t o r ;

t h i s. j F i l e C h o o s e r =new J F i l e C h o o s e r ( ) ;

t h i s. j F i l e C h o o s e r . s e t M u l t i S e l e c t i o n E n a b l e d (f a l s e) ; t h i s. c h a n g e d = f a l s e;

u t i l = new F i l e U t i l ( ) ; }

p u b l i c v o i d a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) { S t r i n g command = e . getActionCommand ( ) ; s w i t c h ( command ) {

c a s e " A b r i r " : { l o a d ( ) ; b r e a k; } c a s e " S a l v a r " : { s a v e ( ) ; b r e a k; } c a s e " S a i r " : { e x i t ( ) ; b r e a k; } }

}

p u b l i c v o i d k e y P r e s s e d ( K e y E v e n t e ) { // Não f a z nada }

p u b l i c v o i d k e y R e l e a s e d ( K e y E v e n t e ) { i f ( ! c h a n g e d ) {

e d i t o r . s e t T i t l e ( E d i t o r . TITLE + "∗" ) ; c h a n g e d = t r u e;

} }

p u b l i c v o i d k e y T y p e d ( K e y E v e n t e ) { // Não f a z nada }

p u b l i c v o i d w i n d o w C l o s i n g ( WindowEvent e ) { e x i t ( ) ; }

p r i v a t e v o i d l o a d ( ) {

i n t s t a t e = j F i l e C h o o s e r . s h o w O p e n D i a l o g ( e d i t o r ) ; i f ( s t a t e == J F i l e C h o o s e r . APPROVE_OPTION) {

S t r i n g f i l e N a m e = j F i l e C h o o s e r . g e t S e l e c t e d F i l e ( ) . g e t A b s o l u t e P a t h ( ) ; e d i t o r . g e t T e x t A r e a ( ) . s e t T e x t ( u t i l . l o a d ( f i l e N a m e ) ) ;

e d i t o r . s e t T i t l e ( E d i t o r . TITLE ) ; c h a n g e d = f a l s e;

} }

p r i v a t e v o i d s a v e ( ) {

i n t s t a t e = j F i l e C h o o s e r . s h o w S a v e D i a l o g ( e d i t o r ) ; i f ( s t a t e == J F i l e C h o o s e r . APPROVE_OPTION) {

S t r i n g f i l e N a m e = j F i l e C h o o s e r . g e t S e l e c t e d F i l e ( ) . g e t A b s o l u t e P a t h ( ) ; u t i l . s a v e ( f i l e N a m e , e d i t o r . g e t T e x t A r e a ( ) . g e t T e x t ( ) ) ;

e d i t o r . s e t T i t l e ( E d i t o r . TITLE ) ; c h a n g e d = f a l s e;

} }

p r i v a t e v o i d e x i t ( ) {

S t r i n g msg = "O c o n t e údo f o i m o d i f i c a d o . Quer s a l v a r a n t e s de s a i r ? " ; i f ( c h a n g e d ) {

i n t s t a t e = J O p t i o n P a n e . s h o w C o n f i r m D i a l o g ( e d i t o r , msg ) ; i f ( s t a t e == J O p t i o n P a n e . YES_OPTION) {

s a v e ( ) ;

} e l s e i f ( s t a t e == J O p t i o n P a n e . CANCEL_OPTION) { r e t u r n;

} }

S y s t e m . e x i t ( 0 ) ; }

}

Código 6.5 ClasseHandler.

172

• Se o item de menuSairfor clicado, execute o métodoexit()responsável por sair da aplicação. Observe que, antes de sair, a aplicação verifica se o usuário deseja salvar, caso esteja alterado, o conteúdo presente na área de texto.

O método KeyReleased() da interface KeyListener é responsável por tratar o evento que ocorre quando uma tecla é liberada, após ter sido pressionada, na área de texto. Esse evento é apenas tratado para atualizar a variávelchanged, que indica se o conteúdo foi alterado ou não. Observe que os demais eventos da interface KeyListener são ignorados.

Por fim, o método windowClosing() da interface WindowListener é respon- sável por tratar o evento de clique no botão de fechar a janela. O comportamento desse método é invocar o métodoexit(), responsável por sair da aplicação.