CURSO JAVA 02

10
Curso de Java – Módulo II Swing Fábio Mengue – [email protected] Centro de Computação - Unicamp Conceitos Swing é um pacote de classes que servem para a construção de GUI's (Graphical User Interface). O pacote foi criado em 1997, e inclui tudo que se necessita para a construção de telas, desde botões até tabelas. Além disso, os programas que utilizam o Swing tem a capacidade de alterar sua interface (chamado de “Look and Feel”, em inglês), trabalhar com conceitos de acessibilidade (para pessoas com dificuldade de visão ou audição), imagens 2D e suporte a Drag and Drop entre aplicativos Java e nativos. Importando pacotes Swing Como todo programa Java, temos que indicar os pacotes de classes que iremos utilizar. Normalmente temos que importar o pacote abaixo: import javax.swing.*; Mas a maioria dos programas Swing trata com eventos; portanto, também importamos os pacotes: import java.awt.*; import java.awt.event.*; Escolhendo o “Look and Feel” Existem alguns “look and feel” que o programa pode usar: Java, Windows, CDE/Motif, e outros. O código abaixo (em negrito) indica como uma aplicação especifica o “look and feel”: ... public static void main(String[] args) { try { UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception e) { } 1

Transcript of CURSO JAVA 02

Page 1: CURSO JAVA 02

Curso de Java – Módulo IISwing

Fábio Mengue – [email protected] de Computação - Unicamp

Conceitos

Swing é um pacote de classes que servem para a construção de GUI's (Graphical UserInterface). O pacote foi criado em 1997, e inclui tudo que se necessita para a construção de telas,desde botões até tabelas. Além disso, os programas que utilizam o Swing tem a capacidade dealterar sua interface (chamado de “Look and Feel”, em inglês), trabalhar com conceitos deacessibilidade (para pessoas com dificuldade de visão ou audição), imagens 2D e suporte a Dragand Drop entre aplicativos Java e nativos.

Importando pacotes Swing

Como todo programa Java, temos que indicar os pacotes de classes que iremos utilizar.Normalmente temos que importar o pacote abaixo:

import javax.swing.*;

Mas a maioria dos programas Swing trata com eventos; portanto, também importamos ospacotes:

import java.awt.*;import java.awt.event.*;

Escolhendo o “Look and Feel”

Existem alguns “look and feel” que o programa pode usar: Java, Windows, CDE/Motif, eoutros. O código abaixo (em negrito) indica como uma aplicação especifica o “look and feel”:

...

public static void main(String[] args) {

try {

UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

} catch (Exception e) { }

1

Page 2: CURSO JAVA 02

...//Cria e mostra a GUI...

O código acima indica que o “look and feel” Java deve ser utilizado(CrossPlatform). Para utilizar outro (por exemplo, Windows), veja alinha abaixo:

UIManager.setLookAndFeel( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");

Temos ainda:

"com.sun.java.swing.plaf.motif.MotifLookAndFeel" (para CDE/Motif)“com.sun.java.swing.plaf.windows.WindowsLookAndFeel” (para Windows)“javax.swing.plaf.mac.MacLookAndFeel” (para Mac).

O “look and feel” padrão (caso nenhum seja especificado) é o Java (tambémchamado de Metal).

Criando o Container e adicionando componentes

Todo programa Swing deve ter pelo menos um container (também chamado top-levelcontainer). Normalmente ele é um JFrame (uma janela completa, com decorações). Cada JFramerepresenta uma janela. O JFrame provê o suporte para outros componentes, no tocante ahierarquia e trabalho com eventos.

O JFrame possui duas divisões. Uma delas é o ContentPane, que representa a parte dajanela onde podemos montar nossa aplicação. O ContentPane na verdade é um JPanel, um outrocontainer que normalmente é utilizado para receber componentes que fazem parte do mesmocontexto de layout. Isso é necessário para separar o design de partes da janela.

Segue um pedaço de código de exemplo:

public class MinhaAplicacao { ... public static void main(String[] args) { ... JFrame frame = new JFrame("Minha Aplicação"); //...cria os componentes e os insere no frame... frame.getContentPane().add(contents, BorderLayout.CENTER);

//Mostra o frame frame.addWindowListener(...); frame.pack(); frame.setVisible(true); }}

2

Page 3: CURSO JAVA 02

No programa principal, a primeira linha cria o JFrame. Depois de incluir os elementosdesejados na GUI, cria-se o gerenciador de layout que indica aos elementos dentro do containercomo eles devem ser comportar.

Exemplos de componentes

Botões, Check Boxes, Radio Buttons, Grupos de Botões, Itens de Menu, Ícones, CamposTexto, ToolTips, Bordas, ScrollPanes (barras de scroll), Mini Editor (JTextPane), Combo (listasdrop-down), ListBoxes, Tabbed Pane (lista de arquivos), Caixas de Mensagem, Menus, JanelasPop-Up, Objetos de desenho, Caixas de Diálogo, Caixas de escolha de Arquivos, Sliders,Árvores, Tabelas, Áreas de Transferência (clipboard), entre outros.

Tipos de layout

Abaixo temos uma lista dos componentes mais utilizados na montagem de telas Swing.

BorderLayout: é o padrão. Divide a tela em cinco regiões (NORTH, SOUTH, EAST, WEST,CENTER). Todo componente adicionado entra automaticamente no centro, “empurrando” osoutros para as bordas. Você pode incluir um componente em outra região como no exemplo:

...Container cp = getContentPane();cp.add(BorderLayout.NORTH, new JButton("North"));cp.add(BorderLayout.SOUTH, new JButton("South"));cp.add(BorderLayout.EAST, new JButton("East"));cp.add(BorderLayout.WEST, new JButton("West"));cp.add(BorderLayout.CENTER, new JButton("Center"));...

FlowLayout: é o mais simples. Ele simplesmente “enche” o container com componentes daesquerda pra direita, ata terminar o espaço da linha. Daí, ele faz a mesma coisa na linha abaixo.Todos os componentes sempre terão um espaço do tamanho que eles estão ocupando nomomento.

GridLayout: permite construir uma tabela de componentes. Ao adicioná-los, eles são colocadosda esquerda para a direita e de cima para baixo em uma grade. Você pode especificar o númerode colunas e linhas que serão necessárias, e todas terão o mesmo tamanho. Se existir menoscomponentes do que o total de espaços, eles ficarão vazios. Caso contrário, o componenteexcedente não será mostrado. Por exemplo:...Container cp = getContentPane();cp.setLayout(new GridLayout(7,3));...

3

Page 4: CURSO JAVA 02

GridBagLayout: permite maior controle que o GridLayout. Neste layout você pode definirexatamente como as regiões da sua grade irão se comportar e reformatar caso a janela tenha seutamanho alterado. Entretanto, é o gerenciador mais complexo de utilizar. Ele foi criado para serutilizado por programas de criação de GUI’s.

Absolute positioning: permite posicionamento absoluto dos componentes. É uma das pioresmaneiras de gerenciar o layout, pois não permite flexibilidade quando a janela tem seu tamanhoalterado. Para utiliza-lo:...Container cp = getContentPane();cp.setLayout(null);...E depois utilize o método setBounds() para cada um dos componentes, indicando onde ele iniciae termina. Basta adicionar ao container depois disso.

BoxLayout: é uma versão simplificada do GridBagLayout. Permite indicar a localização doscomponentes horizontalmente e verticalmente, além de permitir o controle da distância entreeles. Veja o exemplo:...JPanel jpv = new JPanel();jpv.setLayout(new BoxLayout(jpv, BoxLayout.Y_AXIS));

for(int i = 0; i < 5; i++)jpv.add(new JButton("" + i));

JPanel jph = new JPanel();jph.setLayout(new BoxLayout(jph, BoxLayout.X_AXIS));

for(int i = 0; i < 5; i++)jph.add(new JButton("" + i));

Container cp = getContentPane();cp.add(BorderLayout.EAST, jpv);cp.add(BorderLayout.SOUTH, jph);...

O construtor do gerenciador BoxLayout é diferente dos outros. Você indica um containerque deve ser gerenciado como um primeiro argumento e a direção do layout como segundoargumento.

Conclusão: Swing é um pacote muito poderoso. Poucas linhas podem fazer muito. A grandeidéia aqui é misturar os gerenciadores, combinando os simples com os complexos. Entretanto,como todo desenho de GUI, é mais produtivo apelar para um produto que permita o desenhocom mouse, sem perder tempo precioso desenhando tudo na base do codifica-compila-executa.

4

Page 5: CURSO JAVA 02

Outros containers

Vimos que por vezes, para que o design saia certo, devemos utilizar vários layoutmanagers simultaneamente. A utilização de qualquer subclasse de Container permite queagrupemos componentes para que eles sejam mostrados e tratados como apenas um conjunto.Normalmente, a preferência sempre recai sobre o JPanel.

Disparando eventos

A maioria das aplicações deve ter alguns componentes que apresentem a tela da maneiraque o usuário quer ver. Esses componentes muitas vezes são apenas informativos e um tantoinertes (como os labels, por exemplo), mas outros são criados com o propósito de realizar serviço(como os botões, por exemplo).

Devido à natureza orientada a objetos do Java, o código a ser executado quando um botãoé pressionado normalmente pertence a outro objeto, que possui a lógica de negócio. Esse objetodeve ser um método, a ser invocado pelo botão quando este for clicado, por exemplo.

A maneira Java de fazer isso é criando “ouvidores” (chamados de Listeners), ligados aobotão. Do ponto de vista do botão, o Listener é uma lista de objetos a serem invocados quandoacontecer uma ação (um clique de mouse, por exemplo). Do ponto de vista do objeto, ele deveimplementar um método com um nome especial, e esse método será invocado automaticamentena chamada.

Tome como exemplo o código abaixo:...MeuExemplo Objeto = new MeuExemplo();...JButton button = new JButton("OK");button.addActionListener(Objeto);...

A partir de agora, quando button for clicado, ele irá realizar uma chamada a MeuObjeto.Temos uma lista de tipos de componentes e os eventos por eles gerados a seguir:

Evento Classes que geram esse eventoActionEvent JButton, JList, JTextField, JMenuItem,

JCheckBoxMenuItem, Jmenu, JPopupMenuAdjustmentEvent JscrollbarFocusEvent, KeyEvent, MouseEvent ComponentWindowEvent Window, including JDialog, JFileDialog,

JframeItemEvent JCheckBox, JCheckBoxMenuItem,

JComboBox, JlistTextEvent JTextComponent, JTextArea, JTextField

5

Page 6: CURSO JAVA 02

Lidando com Eventos

O trabalho de lidar com eventos quase sempre acompanha as aplicações que utilizamSwing. Mesmo que o aplicativo não tenha botões, pode acontecer o fechamento da janela, o quepor si só é um evento.

Normalmente existem botões e campos de texto, que eles lidam com eventos criando umalista de objetos a serem informados. Os objetos, por sua vez, devem criar um método especialpara atender o evento. Veja o exemplo: class MeuExemplo implements ActionListener {... public void actionPerformed(ActionEvent e) { System.out.println (“Quem causou o evento foi “ + e.getSource()); }}

A classe deve implementar uma certa interface. A palavra reservada implements exigeque essa classe defina um certo método especial que será executado quando o evento ocorrer. Aclasse pode implementar vários Event Listeners, conseqüentemente possuindo vários métodosespeciais. Temos uma lista deles:

Interface Métodos da interfaceActionListener actionPerformed(ActionEvent)AdjustmentListener adjustmentValueChanged(

AdjustmentEvent)ComponentListenerComponentAdapter

componentHidden(ComponentEvent)componentShown(ComponentEvent)componentMoved(ComponentEvent)componentResized(ComponentEvent)

FocusListenerFocusAdapter

focusGained(FocusEvent)focusLost(FocusEvent)

KeyListenerKeyAdapter

keyPressed(KeyEvent)keyReleased(KeyEvent)keyTyped(KeyEvent)

MouseListenerMouseAdapter

mouseClicked(MouseEvent)mouseReleased(MouseEvent)

MouseMotionListenerMouseMotionAdapter

mouseDragged(MouseEvent)mouseMoved(MouseEvent)

WindowListenerWindowAdapter

windowOpened(WindowEvent)windowClosing(WindowEvent) windowClosed(WindowEvent) windowActivated(WindowEvent)windowDeactivated(WindowEvent) windowIconified(WindowEvent) windowDeiconified(WindowEvent)

6

Page 7: CURSO JAVA 02

Lidando com Threads

Se seu programa cria e utiliza a GUI normalmente, seu programa é dito “single threaded”.Isso quer dizer que apenas componentes incluídos na mesma thread irão manipular a GUI,tornando desnecessária a preocupação com a situação eventual em que outra thread tente acessara GUI ao mesmo tempo. A construção normal de um programa Swing segue o padrão abaixo:

public class MeuPrograma { public static void main(String[] args) { JFrame f = new JFrame(...); ...//Adicione os componentes... f.pack(); f.setVisible(true); //Não crie mais nada aqui. }

... //Toda a manipulação -- setText, getText, etc. -- //deve ser feita usando eventos como actionPerformed(). ...}

No código acima, a construção da GUI está na thread principal. Você pode construir suaGUI em qualquer thread, desde que você não faça nenhuma chamada depois do pack(), queacontece apenas no método main(). A única instrução que deve vir após é o setVisible(). Essatécnica torna a aplicação “thread safe”.

Entretanto, a linguagem Java permite que se crie programas que utilizam múltiplasthreads. No caso da programação Swing, se algum destes códigos afetar a GUI que já está visívelsem utilizar os eventos programados (que é onde o Java para tudo para esperar o retorno dométodo), você tem um problema a mais a tratar.

Usando threads

A primeira regra para utilizar threads é: evite usar threads. Elas são difíceis de lidar,tornam o programa mais complicado para manutenção e aumentam a chance de erros ocorrerem.Tudo isso acontece porque o programador pode se esquecer de imaginar uma certa situação quepode simplesmente fazer com que o programa pare de responder caso um evento ocorra. Paraisso, deve-se tomar precauções para que nenhuma thread crie chamadas para qualquer método decomponente Swing. Se a chamada for necessária, ela deve ser feita através de um evento.

Apesar de seus perigos, o uso de threads pode ser muito útil, e as vezes, imprescindível.Como fazer com que meu aplicativo continue respondendo ao usuário ao mesmo tempo em queme mostra um relógio ? Normalmente as threads são utilizadas em casos onde o programadordeseja duas (ou mais) linhas de execução. Meu programa pode contar o tempo, aguardar uma

7

Page 8: CURSO JAVA 02

interrupção de uma fonte externa de dados e ao mesmo tempo responder aos comandos dousuário.

Veja o exemplo abaixo:... CapturaEvento ce = new CapturaEvento(); Button b = new Button(“OK”); b.addActionListener(ce);...

Definição de CapturaEvento:

... class CapturaEvento implements ActionListener { public void actionPerformed(ActionEvent e) { trataBotao(); } private void trataBotao() { int count = 0; while (true) { Thread.sleep(5); count++; } }...

O que deve acontecer no programa acima ? Ele funciona ?

Ao lidar com o evento, o programa irá executar o método trataBotao(). Depois de ficar 5segundos parado, incrementa o contador, e começa tudo novamente.

Note que o programa que gerou o evento (e chamou o CapturaEvento) está esperando umretorno, que nunca irá acontecer, pois o loop feito no método trataBotao() é infinito. Para ousuário, a tela simplesmente congela. Assim, o método trataBotao() deve continuar a contar, masa interface deve continuar a responder. Deve-se criar outra thread para resolver o problema.

A maneira mais fácil é gerando uma subclasse de Thread, como no exemplo abaixo:

public class SimpleThread extends Thread { private int countDown = 5; private static int threadCount = 0; private int threadNumber = ++threadCount; public SimpleThread() { System.out.println("Making " + threadNumber); } public void run() {

8

Page 9: CURSO JAVA 02

while(true) { System.out.println("Thread " + threadNumber + "(" + countDown + ")"); if(--countDown == 0) return; } } public static void main(String[] args) { for(int i = 0; i < 5; i++) new SimpleThread().start(); System.out.println("All Threads Started"); } }

Quando estamos extendendo a classe Thread, devemos sobrecarregar o método run(), queé a porção de código que irá se repetir em todas as threads. Temos também métodos para iniciare parar uma thread (start() e terminate()) Qual seria o resultado da execução do código acima ?

Agora podemos resolver o problema de nosso programa usando uma thread. O truque écolocar o nosso loop infinito dentro de um método run(). No caso de nosso exemplo com Swing,poderíamos fazer algo do tipo:

... class CapturaEvento implements ActionListener { public void actionPerformed(ActionEvent e) { TrataBotao b = new TrataBotao(); } class TrataBotao extends Thread { TrataBotao() { start(); } void run() { int count = 0; while (true) { Thread.sleep(5); count++; } }...

SwingUtilities.invokeLater(getTextFieldText); ... System.out.println(myStrings[0] + " " + myStrings[1]);}

A utilização de Threads implica ainda no entendimento de acessos concorrentes aomesmo recurso, que pode gerar um deadlock ou mesmo uma exceção. O Java possui uma

9

Page 10: CURSO JAVA 02

maneira de controlar essas colisões. É a palavra reservada synchronized. Ela evita que mais deuma thread tenha acesso a um recurso ao mesmo tempo:

public synchronized void run() { while (true) { t1.setText(Integer.toString(count1++)); t2.setText(Integer.toString(count2++)); sleep(500); }

Existe ainda controle de estado de threads (bloquear, parar, terminar, etc.), prioridades,métodos para notificar outras threads, que permite que controlemos nossas threads eimplementemos serviços tão complexos quanto daemons. Quando mal utilizadas, o mínimo queacontece é que seu programa fica lento. A complexidade e as “patologias” (como acabar com osrecursos da máquina, entrar em condições de corrida e deadlock) muitas vezes justificam a nãoutilização deste tipo de recurso. Mas esses assuntos fogem do escopo deste curso.Recomendamos a leitura da bibliografia indicada para maiores informações.

Bibliografia

The Java Tutorial – http://www.sun.com/docsEckel, Bruce. Thinking in Java, 2nd edition, Revision 12Horstmann, Cay S., Cornell, Gary. Core Java. Makron Books

Proibida a alteração, reprodução e cópia de parte deste material para qualquer finalidade sem a permissão do Centrode Computação da Unicamp.

A utilização deste material é permitida desde que conste a autoria do mesmo.

2002 Centro de Computação da Unicamp.

10