Você está na página 1de 10

Curso de Java Mdulo II

Swing
Fbio Mengue fabio@unicamp.br Centro de Computao - Unicamp

Conceitos
Swing um pacote de classes que servem para a construo de GUI's (Graphical User Interface). O pacote foi criado em 1997, e inclui tudo que se necessita para a construo de telas, desde botes at tabelas. Alm disso, os programas que utilizam o Swing tem a capacidade de alterar sua interface (chamado de Look and Feel, em ingls), trabalhar com conceitos de acessibilidade (para pessoas com dificuldade de viso ou audio), 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, tambm 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 cdigo abaixo (em negrito) indica como uma aplicao especifica o look and feel: ... public static void main(String[] args) { try { UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception e) { }
1

...//Cria e mostra a GUI... O cdigo 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 padro (caso nenhum seja especificado) o Java (tambm chamado de Metal).

Criando o Container e adicionando componentes


Todo programa Swing deve ter pelo menos um container (tambm chamado top-level container). Normalmente ele um JFrame (uma janela completa, com decoraes). Cada JFrame representa uma janela. O JFrame prov o suporte para outros componentes, no tocante a hierarquia e trabalho com eventos. O JFrame possui duas divises. Uma delas o ContentPane, que representa a parte da janela onde podemos montar nossa aplicao. O ContentPane na verdade um JPanel, um outro container que normalmente utilizado para receber componentes que fazem parte do mesmo contexto de layout. Isso necessrio para separar o design de partes da janela. Segue um pedao de cdigo de exemplo: public class MinhaAplicacao { ... public static void main(String[] args) { ... JFrame frame = new JFrame("Minha Aplicao"); //...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

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

Exemplos de componentes
Botes, Check Boxes, Radio Buttons, Grupos de Botes, Itens de Menu, cones, Campos Texto, ToolTips, Bordas, ScrollPanes (barras de scroll), Mini Editor (JTextPane), Combo (listas drop-down), ListBoxes, Tabbed Pane (lista de arquivos), Caixas de Mensagem, Menus, Janelas Pop-Up, Objetos de desenho, Caixas de Dilogo, Caixas de escolha de Arquivos, Sliders, rvores, Tabelas, reas de Transferncia (clipboard), entre outros.

Tipos de layout
Abaixo temos uma lista dos componentes mais utilizados na montagem de telas Swing. BorderLayout: o padro. Divide a tela em cinco regies (NORTH, SOUTH, EAST, WEST, CENTER). Todo componente adicionado entra automaticamente no centro, empurrando os outros para as bordas. Voc pode incluir um componente em outra regio 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 da esquerda pra direita, ata terminar o espao da linha. Da, ele faz a mesma coisa na linha abaixo. Todos os componentes sempre tero um espao do tamanho que eles esto ocupando no momento. GridLayout: permite construir uma tabela de componentes. Ao adicion-los, eles so colocados da esquerda para a direita e de cima para baixo em uma grade. Voc pode especificar o nmero de colunas e linhas que sero necessrias, e todas tero o mesmo tamanho. Se existir menos componentes do que o total de espaos, eles ficaro vazios. Caso contrrio, o componente excedente no ser mostrado. Por exemplo: ... Container cp = getContentPane(); cp.setLayout(new GridLayout(7,3)); ...
3

GridBagLayout: permite maior controle que o GridLayout. Neste layout voc pode definir exatamente como as regies da sua grade iro se comportar e reformatar caso a janela tenha seu tamanho alterado. Entretanto, o gerenciador mais complexo de utilizar. Ele foi criado para ser utilizado por programas de criao de GUIs. Absolute positioning: permite posicionamento absoluto dos componentes. uma das piores maneiras de gerenciar o layout, pois no permite flexibilidade quando a janela tem seu tamanho alterado. Para utiliza-lo: ... Container cp = getContentPane(); cp.setLayout(null); ... E depois utilize o mtodo setBounds() para cada um dos componentes, indicando onde ele inicia e termina. Basta adicionar ao container depois disso. BoxLayout: uma verso simplificada do GridBagLayout. Permite indicar a localizao dos componentes horizontalmente e verticalmente, alm de permitir o controle da distncia entre eles. 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 container que deve ser gerenciado como um primeiro argumento e a direo do layout como segundo argumento. Concluso: Swing um pacote muito poderoso. Poucas linhas podem fazer muito. A grande idia 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 desenho com mouse, sem perder tempo precioso desenhando tudo na base do codifica-compila-executa.
4

Outros containers
Vimos que por vezes, para que o design saia certo, devemos utilizar vrios layout managers simultaneamente. A utilizao de qualquer subclasse de Container permite que agrupemos componentes para que eles sejam mostrados e tratados como apenas um conjunto. Normalmente, a preferncia sempre recai sobre o JPanel.

Disparando eventos
A maioria das aplicaes deve ter alguns componentes que apresentem a tela da maneira que o usurio quer ver. Esses componentes muitas vezes so apenas informativos e um tanto inertes (como os labels, por exemplo), mas outros so criados com o propsito de realizar servio (como os botes, por exemplo). Devido natureza orientada a objetos do Java, o cdigo a ser executado quando um boto pressionado normalmente pertence a outro objeto, que possui a lgica de negcio. Esse objeto deve ser um mtodo, a ser invocado pelo boto quando este for clicado, por exemplo. A maneira Java de fazer isso criando ouvidores (chamados de Listeners), ligados ao boto. Do ponto de vista do boto, o Listener uma lista de objetos a serem invocados quando acontecer uma ao (um clique de mouse, por exemplo). Do ponto de vista do objeto, ele deve implementar um mtodo com um nome especial, e esse mtodo ser invocado automaticamente na chamada. Tome como exemplo o cdigo 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 ActionEvent AdjustmentEvent FocusEvent, KeyEvent, MouseEvent WindowEvent ItemEvent TextEvent
5

Classes que geram esse evento JButton, JList, JTextField, JMenuItem, JCheckBoxMenuItem, Jmenu, JPopupMenu Jscrollbar Component Window, including JDialog, JFileDialog, Jframe JCheckBox, JCheckBoxMenuItem, JComboBox, Jlist JTextComponent, JTextArea, JTextField

Lidando com Eventos


O trabalho de lidar com eventos quase sempre acompanha as aplicaes que utilizam Swing. Mesmo que o aplicativo no tenha botes, pode acontecer o fechamento da janela, o que por si s um evento. Normalmente existem botes e campos de texto, que eles lidam com eventos criando uma lista de objetos a serem informados. Os objetos, por sua vez, devem criar um mtodo especial para 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 exige que essa classe defina um certo mtodo especial que ser executado quando o evento ocorrer. A classe pode implementar vrios Event Listeners, conseqentemente possuindo vrios mtodos especiais. Temos uma lista deles: Interface ActionListener AdjustmentListener ComponentListener ComponentAdapter FocusListener FocusAdapter KeyListener KeyAdapter MouseListener MouseAdapter MouseMotionListener MouseMotionAdapter WindowListener WindowAdapter Mtodos da interface actionPerformed(ActionEvent) adjustmentValueChanged( AdjustmentEvent) componentHidden(ComponentEvent) componentShown(ComponentEvent) componentMoved(ComponentEvent) componentResized(ComponentEvent) focusGained(FocusEvent) focusLost(FocusEvent) keyPressed(KeyEvent) keyReleased(KeyEvent) keyTyped(KeyEvent) mouseClicked(MouseEvent) mouseReleased(MouseEvent) mouseDragged(MouseEvent) mouseMoved(MouseEvent) windowOpened(WindowEvent) windowClosing(WindowEvent) windowClosed(WindowEvent) windowActivated(WindowEvent) windowDeactivated(WindowEvent) windowIconified(WindowEvent) windowDeiconified(WindowEvent)

Lidando com Threads


Se seu programa cria e utiliza a GUI normalmente, seu programa dito single threaded. Isso quer dizer que apenas componentes includos na mesma thread iro manipular a GUI, tornando desnecessria a preocupao com a situao eventual em que outra thread tente acessar a GUI ao mesmo tempo. A construo normal de um programa Swing segue o padro abaixo: public class MeuPrograma { public static void main(String[] args) { JFrame f = new JFrame(...); ...//Adicione os componentes... f.pack(); f.setVisible(true); //No crie mais nada aqui. } ... //Toda a manipulao -- setText, getText, etc. -//deve ser feita usando eventos como actionPerformed(). ... } No cdigo acima, a construo da GUI est na thread principal. Voc pode construir sua GUI em qualquer thread, desde que voc no faa nenhuma chamada depois do pack(), que acontece apenas no mtodo main(). A nica instruo que deve vir aps o setVisible(). Essa tcnica torna a aplicao thread safe. Entretanto, a linguagem Java permite que se crie programas que utilizam mltiplas threads. No caso da programao Swing, se algum destes cdigos afetar a GUI que j est visvel sem utilizar os eventos programados (que onde o Java para tudo para esperar o retorno do mtodo), voc tem um problema a mais a tratar.

Usando threads
A primeira regra para utilizar threads : evite usar threads. Elas so difceis de lidar, tornam o programa mais complicado para manuteno e aumentam a chance de erros ocorrerem. Tudo isso acontece porque o programador pode se esquecer de imaginar uma certa situao que pode simplesmente fazer com que o programa pare de responder caso um evento ocorra. Para isso, deve-se tomar precaues para que nenhuma thread crie chamadas para qualquer mtodo de componente Swing. Se a chamada for necessria, ela deve ser feita atravs de um evento. Apesar de seus perigos, o uso de threads pode ser muito til, e as vezes, imprescindvel. Como fazer com que meu aplicativo continue respondendo ao usurio ao mesmo tempo em que me mostra um relgio ? Normalmente as threads so utilizadas em casos onde o programador deseja duas (ou mais) linhas de execuo. Meu programa pode contar o tempo, aguardar uma
7

interrupo de uma fonte externa de dados e ao mesmo tempo responder aos comandos do usurio. Veja o exemplo abaixo: ... CapturaEvento ce = new CapturaEvento(); Button b = new Button(OK); b.addActionListener(ce); ... Definio 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 mtodo trataBotao(). Depois de ficar 5 segundos parado, incrementa o contador, e comea tudo novamente. Note que o programa que gerou o evento (e chamou o CapturaEvento) est esperando um retorno, que nunca ir acontecer, pois o loop feito no mtodo trataBotao() infinito. Para o usurio, a tela simplesmente congela. Assim, o mtodo trataBotao() deve continuar a contar, mas a interface deve continuar a responder. Deve-se criar outra thread para resolver o problema. A maneira mais fcil 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

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 mtodo run(), que a poro de cdigo que ir se repetir em todas as threads. Temos tambm mtodos para iniciar e parar uma thread (start() e terminate()) Qual seria o resultado da execuo do cdigo acima ? Agora podemos resolver o problema de nosso programa usando uma thread. O truque colocar o nosso loop infinito dentro de um mtodo run(). No caso de nosso exemplo com Swing, poderamos 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 utilizao de Threads implica ainda no entendimento de acessos concorrentes ao mesmo recurso, que pode gerar um deadlock ou mesmo uma exceo. O Java possui uma

maneira de controlar essas colises. a palavra reservada synchronized. Ela evita que mais de uma 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, mtodos para notificar outras threads, que permite que controlemos nossas threads e implementemos servios to complexos quanto daemons. Quando mal utilizadas, o mnimo que acontece que seu programa fica lento. A complexidade e as patologias (como acabar com os recursos da mquina, entrar em condies de corrida e deadlock) muitas vezes justificam a no utilizao deste tipo de recurso. Mas esses assuntos fogem do escopo deste curso. Recomendamos a leitura da bibliografia indicada para maiores informaes.

Bibliografia
The Java Tutorial http://www.sun.com/docs Eckel, Bruce. Thinking in Java, 2nd edition, Revision 12 Horstmann, Cay S., Cornell, Gary. Core Java. Makron Books
Proibida a alterao, reproduo e cpia de parte deste material para qualquer finalidade sem a permisso do Centro de Computao da Unicamp. A utilizao deste material permitida desde que conste a autoria do mesmo.

2002 Centro de Computao da Unicamp.

10