Sei sulla pagina 1di 30

Interface Grfica com o usurio Objetivos do captulo usar herana para personalizar painis e frames Entender o uso de gerenciadores

es de leiaute para organizar os componentes de interface com o usurio em um continer Familiarizar-se com os componentes comuns de interface com o usurio, tais como botes, componentes de texto, caixas de combinaes e menus. Construir programas que tratem eventos de componentes de interface com o usurio.

12.1 Usando herana para personalizar painis No cap.10, vimos como implementar aplicaes que mostram os resultados em uma rea de texto. Entretanto, essas aplicaes no foram capazes de produzir nenhuma sada grfica. Lembre-se como so gerados grficos em um applet. Estendemos a classe Applet e redefinimos o mtodo paint:
public class MyApplet extends Applet { public void paint (Graphics g) { // suas instrues de desenho vo aqui ... } ... }

Porm, essa abordagem no funciona para frames. No se deve desenhar diretamente sobre a superfcie de um frame. Os frames foram projetados para organizar componentes de interface com o usurio, tais como botes, menus e barras de rolagem. Desenhar diretamente sobre o frame interfere na exibio dos componentes de interface com o usurio. Se quisermos mostrar grficos em um frame, desenhamos o grfico sobre um JPanel e o acrescentamos ao frame. Um JPanel vazio e pode-se desenhar sobre ele o que se quiser. Podemos desenhar formas grficas sobre um painel sobrescrevendo o mtodo paintComponent de uma subclasse JPanel Desenhar sobre um painel diferente de desenhar sobre um applet. Sobrescrevemos o mtodo paintComponent. H uma segunda diferena importante. Ao implementar-se o prprio mtodo paintComponent, temos de chamar o mtodo paintComponent da superclasse. Isso d ao mtodo da superclasse uma chance de apagar o contedo velho do painel. A seguir, um esboo do mtodo paintComponent:

public class MyPanel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; // nossas instrues de desenho vo aqui ... } }

Uma vez que tenhamos chamado super.paintComponent e obtido um objeto Graphics2D, estaremos prontos para desenhar formas grficas da maneira usual. Por default, os painis tm um tamanho de 0 por 0 pixels. Portanto, um painel deve configurar seu tamanho preferido em seu construtor, da seguinte forma:
public class MyPanel { public MyPanel() { setPreferredSize( new Dimension(PANEL_WIDTH, PANEL_HEIGTH)); .. } ... private static final int PANEL_WIDTH = 300; private static final int PANEL_HEIGTH = 300; }

Lembre-se do programa MouseApplet do cap.10. Esse applet desenha um retngulo na posio onde for clicado o mouse. Vamos transformar o applet em uma aplicao. Precisamos de um painel para fazer o desenho. No construtor, ns configuramos o tamanho preferido e acrescentamos um escutador de mouse.
public class RectanglePanel extends JPanel { public RectanglePanel() { setPreferredSize( new Dimension(PANEL_WIDTH, PANEL_HEIGTH)); // acrescente o escutador de pressionamento de mouse ... } public void paintComponent(Graphics g) { super.paintComponent(Graphics g); Graphics2D g2 = (Graphics2D)g; ... } ... }

Ao implementar um painel tal como o RectanglePanel, temos de pensar em minimizar o interrelacionamento entre o componente e o resto do programa. Se armazenarmos informaes no lugar errado, vamos ficar movimentando os dados de um lado para outro todo o tempo. Uma boa regra : um painel deve armazenar os dados que necessita para repintar-se. Em nosso caso, a informao simples apenas um retngulo. Para desenhos mais complexos, o painel necessita armazenar a coleo de todos os elementos que so necessrios para recriar o desenho.
public class RectanglePanel extends JPanel { public RectanglePanel() { // o retngulo que o mtodo paint desenha box = new Rectangle(...); ... } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; g2.draw(box); } private Rectangle box; ... }

Agora precisamos de uma segunda classe para disparar uma aplicao que exiba esse painel em um frame:
import import import import import /** Este programa exibe um frame contendo um RectanglePanel. */ public class RectangleTest { public static void main(String[] args) { RectanglePanel rectPanel = new RectanglePanel(); JFrame appFrame = new JFrame(); appFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); appFrame.setContentPane(rectPanel); appFrame.pack(); appFrame.show(); } } javax.swing.JButton; javax.swing.JFrame; javax.swing.JLabel; javax.swing.JPanel; javax.swing.JTextField;

Arquivo RectanglePanel.java
import import import import import import import /** Um painel retangular exibe um retngulo que o usurio pode mover clicando com o mouse. */ public class RectanglePanel extends JPanel { /** * Constri um painel retangular com o retngulo em uma * localizao default. */ public RectanglePanel() { setPreferredSize( new Dimension(PANEL_WIDTH, PANEL_WEIGHT)); // o retngulo que o mtodo paint desenha box = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT); // adiciona o escutador de pressionamento do mouse class MousePressListener implements MouseListener { public void mousePressed (MouseEvent event) { int x = event.getX(); int y = event.getY(); box.setLocation(x, y); repaint(); } // mtodos que no fazem nada public void mouseReleased(MouseEvent event); {} public void mouseClicked(MouseEvent event); {} public void mouseEntered(MouseEvent event); {} public void mouseExited(MouseEvent event); {} } MouseLIstener listener = new MousePressListener(); addMouseListener(listener); } public void paintComponent (Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; g2.draw(box); } java.awt.event.MouseEvent; java.awt.event.MouseLIstener; java.awt.Dimension; java.awt.Graphics; java.awt.Graphics2D; java.awt.Rectangle; javax.swing.JPanel;

private private private private private

Rectangle box; static final int static final int static final int static final int

BOX_X = 100; BOX_Y = 100; BOX_WIDTH = 20; BOX_HEIGHT = 30;

private static final int PANEL_WIDTH = 300; private static final int PANEL_HEIGTH = 300; }

Erro Frequente 12.1 Sobrescrevendo o Mtodo paint de um Painel Quando implementamos um applet, temos de sobrescrever o mtodo paint. Por outro lado, para desenhar em um painel, sobrescrevemos paintComponent. Mas tambm tm um mtodo paint de uso interno pela biblioteca Swing. Se acidentalmente redefinimos o mtodo paint, ento a pintura ser imprevisvel. Esquecendo de Chamar o Mtodo paintComponent da Superclasse O mtodo paintComponent de toda subclasse de um componente Swing tem de chamar super.paintComponent a fim de dar ao mtodo paintComponent da superclasse uma chance de desenhar o pano de fundo, as bordas de decoraes, e configurar os atributos do objeto Graphics. Se esquecermos de chamar super.paintComponent, ento o pano de fundo pode no ser apagado, ou nossas intrues de desenho podem aparecer na posio errada.

Gerenciamento de Leiaute Em Java, construmos interfaces com o usurio acrescentando componentes em contineres tais como painis. Cada continer tem seu prprio gerenciador de leiaute, o qual determina como os componentes so dispostos.
Cada continer tem um gerenciador de leiaute que determina a disposio de seus componentes.

Por default, um JPanel usa um FlowLayout (leiaute de fluxo). O FlowLayout arranja seus componentes de esquerda para a direita e inicia uma nova linha quando no h mais espao na linha atual. Outro gerenciador de leiaute comumente usado o BorderLayout (leiaute de borda). O BorderLayout agrupa o continer em cinco reas: Center, North, West, south e east. Geralmente no preenchemos as cinco reas ao mesmo tempo. Podemos configurar o gerenciador de leiaute de um painel para BorderLayout:
panel.setLayout(new BorderLayout());

Ao acrescentar um componente a um continer com BorderLayout, temos de especificar a posio da seguinte maneira: panel.add(label, BorderLayout.CENTER);

Em vez de usar um painel e configurar seu gerenciador de leiaute para um BorderLayout, podemos tambm usar o painel de contedo default de um frame ele j usa um BorderLayout. Ns o recuperamos com o mtodo getContent Pane : frame.getContentPane().add(label, BorderLayout.CENTER);
O painel de contedo de um frame ou applet tem o BorderLayout por default. O painel tem um FlowLayout por default.

H uma diferena importante entre o BorderLayout e o FlowLayout. O BorderLayout expande cada componente para preencher todo espao disponvel em sua rea. Em contraste, o FlowLayout mantm cada componente no seu tamanho preferido. por isso que os botes dentro de um painel ficam com seu tamanho natural. Portanto, mesmo se tivermos somente um boto, se quisermos proteg-lo de ter seu tamanho alterado, temos de coloc-lo dentro de um novo painel.

O GridLayout organiza os componentes sobre uma grade com um nmero fixo de linhas e colunas, mudando o tamanho de cada um dos componentes a fim de que todos tenham o mesmo tamanho. Assim como o BorderLayout, ele tambm expande cada componente para preencher toda a rea alocada. Se no quisermos que isso acontea, precisamos colocar cada componente dentro de um painel. Para criar um GridLayout, fornecemos o nmero de linhas e colunas no construtor. Ento acrescentamos os componentes, linha por linha, da esquerda para a direita:
JPanel numberPanel = new JPanel (); numberPanel.setLayout(new GridLayout(4, 3)); numberPanel.add(button7); numberPanel.add(button8); numberPanel.add(button9); numberPanel.add(button4); ...

Algumas vezes queremos um arranjo tabular dos componentes em que as colunas tm tamanhos diferentes ou um dos componentes se expande por vrias colunas. Um gerenciador de leiaute mais complexo chamado de GridBagLayout pode tratar dessas situaes. Usando o BorderLayout, o FlowLayout e o GridLayout, juntamente com os painis, podemos criar leiautes de aparncia aceitvel em praticamente todas as situaes

12.3 Usando Herana para Personalizar Frames


Defina uma subclasse JFrame para um frame complexo.

medida que acrescentamos mais componentes de interface com o usurio a um frame, o frame pode tornar-se complexo. Ento usada a herana para um frame que contenha mltiplos componentes. Projete uma subclasse de JFrame e acrescente os componentes de interface com o usurio no construtor. Se um conjunto de componentes de interface com o usurio se tornar complexo, ento escreva um mtodo separado para construir esse conjunto. O ex. a seguir mostra um mtodo separado para construir o painel de controle na parte de baixo do frame.
public class RectangleFrame extends JFrame { public RectangleFrame() { // o painel que desenha o retngulo rectPanel = new RectanglePanel(); getContentPane().add( rectPanel, BorderLayout.CENTER); createControlPanel(); pack(); } private void createControlPanel() { //os campos de texto para inserir as coordenadas x e y final JTextField xField = new JTextField(5); final JTextField yField = new JTextField(5); class MoveButtonListener implements ActionListener { public void actionPerformed (ActionEvent event) { int x = Integer.parseInt(xField.getText()); int y = Integer.parseInt(yField.getText()); rectPanel.setLocation(x, y); } } // cria o boto e anexa o escutador /* o painel para conter os componentes de interface * com o usurio */ JPanel controlPanel = new JPanel(); // acrescenta os componentes ao painel de controle getContentPane().add( controlPanel, BorderLayout.SOUTH); } private RectanglePanel rectPanel; }

Transformamos em variveis de instncia da classe quaisquer componentes que tenham de ser compartilhados entre esses mtodos. Por ex., rectPanel necessrio tanto no construtor RectangleFrame como no mtodo createControlPanel. Agora uma classe de programa separada para exibir o frame:
public class RectangleTest { public static void main (String[] args) { JFrame appFrame = new RectangleFrame(); appFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); appFrame.show(); } }

H uma complexidade adicional. O escutador de aes do boto Move no tem acesso direto ao retngulo dentro de RectanglePanel. Portanto, temos de acrescentar um mtodo ao RectanglePanel que permita que outros configurem a localizao do retngulo.
public class RectangleTest { public static void main (String[] args) { JFrame appFrame = new RectangleFrame(); appFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); appFrame.show(); } } public class RectanglePanel extends JPanel { public RectanglePanel() { ... box = new Rectangle(...); } public void setLocation(int x, inty) { box.setLocation(x,y); repaint(); } public void paintComponent (Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; g2.draw(box); } private Rectangle box; }

Isso bem tpico de um painel que exibe grficos. Geralmente, os grficos se alteram atravs de algum evento externo. A classe do painel precisa fornecer mtodos para alterar o estado do grfico. Esses mtodos devem aplicar as configuraes adequadas e ento chamar repaint para disparar uma nova exibio do desenho. Eis as classes dessa aplicao. Arquivo RectangleTest.java
import javax.swing.JFrame; /* Este programa testa o RectangleFrame. */ public class RectangleTest { public static void main (String[] args) { JFrame appFrame = new RectangleFrame(); appFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); appFrame.show(); } }

Arquivo RectangleFrame.java
import import import import import import import import /** * java.awt.BorderLayout; java.awt.event.ActionEvent; java.awt.event.ActionListener; javax.swing.JButton; javax.swing.JFrame; javax.swing.JLabel; javax.swing.JPanel; javax.swing.JTextField;

Este frame contm um painel que exibe um retngulo e um painel de campos de texto para especificar a posio do retngulo. */ public class RectangleFrame extends JFrame { /** * Constri o frame. */ public RectangleFrame() { // o painel que desenha o retngulo rectPanel = new RectanglePanel(); // adiciona painel ao painel de contedo getContentPane().add( rectPanel, BorderLayout.CENTER);

createControlPanel(); pack(); } /** * Cria o painel de controle com os * na parte de baixo do frame. */ private void createControlPanel() { // os campos de texto para se final JTextField xField = new final JTextField yField = new

campos de texto

inserir as coordenadas x e y JTextField(5); JTextField(5);

// o boto para mover o retngulo JButton moveButton = new JButton("Move"); class MoveButtonListener implements ActionListener { public void actionPerformed(ActionEvent event) { int x = Integer.parseInt (xField.getText()); int y = Integer.parseInt (yField.getText()); rectPanel.setLocation(x, y); } } ActionListener listener = new MoveButtonListener(); moveButton.addActionListener(listener); // os rtulos para rotular os campos de texto JLabel xLabel = new JLabel("x = "); JLabel yLabel = new JLabel("y = "); // o painel para conter os componentes de interface com o usurio JPanel controlPanel = new JPanel(); controlPanel.add(xLabel); controlPanel.add(xField); controlPanel.add(yLabel); controlPanel.add(yField); controlPanel.add(moveButton); getContentPane().add( controlPanel, BorderLayout.SOUTH); } private RectanglePanel rectPanel; }

Arquivo RectanglePanel.java
import import import import import /** Este painel exibe um retngulo */ public class RectanglePanel extends JPanel { /** * Constri um painel retangular com o retngulo em uma * localizao default. */ public RectanglePanel() { setPreferredSize( new Dimension (PANEL_WIDTH, PANEL_HEIGTH)); // o retngulo que o mtodo paint desenha box = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT); } /** Configura a localizao do retngulo e redesenha o painel @param x a coordenada x do canto superior esquerdo do retngulo @param y a coordenada y do canot superior esquerdo do retngulo */ public void setLocation(int x, int y) { box.setLocation(x, y); repaint(); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; g2.draw(box); } private private private private private Rectangle box; static final int static final int static final int static final int java.awt.Dimension; java.awt.Graphics; java.awt.Graphics2D; java.awt.Rectangle; java.swing.JPanel;

BOX_X = 100; BOX_Y = 100; BOX_WIDTH = 20; BOX_HEIGHT = 30;

private static final int PANEL_WIDTH = 300; private static final int PANEL_HEIGHT = 300; }

Tpico Avanado 12.1 Adicionando o Mtodo main Classe Frame D outra olhada no programa RectangleTest. Temos duas classes: RectangleTest, uma classe com apenas um mtodo main que constri e exibe o frame, e a classe RectangleFrame, a qual contm o construtor do frame, mtodos de ajuda e variveis de instncia. Alguns programadores preferem combinar essas duas classes, simplesmente acrescentando o mtodo main classe do frame:
public class RectangleFrame extends JFrame { public static void main(String[] args) { JFrame appFrame = new RectangleFrame(); appFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); appFrame.show(); } public RectangleFrame() { ... } ... }

Tpico Avanado 12.2 Convertendo um Frame em um Applet O pacote javax.swing fornece uma classe JApplet que mutio semelhante a um JFrame. Diferentemente de um Applet simples, o JApplet tambm tem um painel de contedo cujo default o BorderLayout. Portanto, posicionar os componentes em JApplet exatamente igual a faz-lo em um JFrame. Portanto, precisamos apenas de alguns passos para converter um frame em um applet: 1. Descarte a classe com o mtodo main que mostra o frame. 2. Herde de JApplet, e no de JFrame. 3. Remova quaisquer chamadas para setSize. Voc precisa configurar o tamanho na pgina HTML do applet. 4. Remova quaisquer chamadas para setTitle. Se voc quiser mostrar um ttulo, fornea-o em HTML na marca applet.

12.4 Opes Botes de Opo Se as opes forem mutuamente exclusivas, use um conjunto de botes de opo (radio buttons). Em um conjunto de botes de opo, apenas um boto selecionado de cada vez.

Para criar um conjunto de botes de opo, primeiramente criamos cada boto individualmente e ento acrescentamos todos os botes do conjunto a um objeto ButtonGroup:
JRadioButton smallButton = new JRadioButton("Small"); JRadioButton mediumButton = new JRadioButton("Medium"); JRadioButton largeButton = new JRadioButton("Large"); ButtonGroup group = new ButtonGroup(); group.add(smallButton); group.add(mediumButton); group.add(largeButton);

O programa pode ligar ou desligar um boto sem que o usurio clique sobre ele, chamando o mtodo setSelected. Se tivermos uma referncia a um boto, podemos chamar o mtodo isSelected para descobrir se o boto est selecionado ou no neste momento. Por ex.,
if (largeButton.isSelected()) size = LARGE_SIZE; Devemos chamar setSelected(true) sobre um dos botes de opo em cada grupo de botes de opo antes de exibir o continer. Podemos colocar uma borda em volta de um painel para agrupar visualmente seu contedo.

Se houver mltiplos grupos de botes em um continer, uma boa idia agrup-los visualmente juntos. Provavelmente usemos painis para construir nossa interface com o usurio, mas os painis em si so invisveis. Podemos acrescentar uma borda a um painel para torn-lo visvel. A classe EtchedBorder gera uma borda com um efeito de baixo relevo 3D. Podemos acrescentar bordas a qualquer componente, mas o mais comum aplic-las a painis:
JPanel panel = new JPanel(); panel.setBorder(new EtchedBorder());

Se quisermos acrescentar um ttulo borda, temos de construir uma TitledBorder. As bordas Swing podem ser colocadas em camadas, semelhantemente a objetos de fluxo. Geramos uma borda com ttulo fornecendo uma borda bsica e ento o ttulo que queremos.
panel.setBorder(new TitledBorder(EtchedBorder(),"Size"));

Caixa de Seleo No caso de uma escolha binria, use uma caixa de seleo

Botes de opo e caixas de seleo tm aparncia visual diferente. Construmos uma caixa de seleo fornecendo seu nome no construtor:

JCheckBox italicCheckBox = new JCheckBox("italic");

No coloque caixas de seleo dentro de um grupo de botes.

Caixas de combinao Se tivermos um grande conjunto de opes mutuamente exclusivas, usamos uma caixa de combinao. Esse componente chamado de caixa de combinao porque uma combinao de uma lista com um campo de texto. O campo de texto exibe o nome da seleo atual. Quando clicamos sobre a seta direita do campo de texto de um caixa de combinao, uma lista de opes aberta, e podemos escolher um dos itens da lista. Se a caixa de combinao (combo box) for editvel, podemos tambm inserir nossa prpria opo. Para tornar uma caixa de combinao editvel, chame o mtodo setEditable. Para acrescentar strings a uma caixa de combinao, usamos o mtodo addItem.
JComboBox facenameCombo = new JComboBox(); facenameCombo.addItem("Serif"); facenameCombo.addItem("SansSerif"); ...

Obtemos o item que o usurio selecionou chamando o mtodo getSelectedItem. Entretanto, uma vez que as caixas de combinao podem armazenar outros objetos alm de strings, o mtodo getSelectedItem tem tipo de retorno Object. Dessa forma, temos de converter o valor de retorno de volta para String.
String selectedString = (String)facenameCombo.getSelectedItem();

Podemos selecionar um item para o usurio com o mtodo setSelectedItem. Botes de opo, caixas de seleo e caixas de combinao geram um ActionEvent sempre que o usurio selecionar um item. Arquivo ChoiceTest.java
import javax.swing.JFrame; /** Este programa testa o ChoiceFrame. */ public class ChoiceTest { public static void main(String[] args); { JFrame frame = new ChoiceFrame(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); frame.show(); } }

Arquivo ChoiceFrame.java

import import import import import import import import import import import import import import import import import import /**

java.awt.BorderLayout; java.awt.Container; java.awt.Font; java.awt.GridLayout; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.awt.event.WindowAdapter; java.awt.event.WindowEvent; javax.swing.ButtonGroup; javax.swing.JButton; javax.swing.JCheckBox; javax.swing.JComboBox; javax.swing.JFrame; javax.swing.JLabel; javax.swing.JPanel; javax.swing.JRadioButton; javax.swing.border.EtchedBorder; javax.swing.border.TitledBorder;

Constri o frame. */ public ChoiceFrame() { // constri amostra de texto sampleField = new JLabel ("Big Java"); getContentPane().add( sampleField, BorderLayout.CENTER); // este escutador compartilhado entre todos os componentes class ChoiceListener implementes ActionListener { public void actionPerformed(ActionEvent event) { setSampleFont(); } } listener = new ChoiceListener(); createControlPanel(); setSampleFont(); pack(); } /** Cria o painel de controle para mudar a fonte. */ public void createControlPanel() { JPanel facenamePanel = createComboBox(); JPanel sizeGroupPanel = createCheckBoxes(); JPanel styleGroupPanel = createRadioButtons(); // alinha os painis dos componentes

JPanel controlPanel = new JPanel(); controlPanel.setLayout(new GridLayout(3, 1)); controlPanel.add(facenamePanel); controlPanel.add(sizeGroupPanel); controlPanel.add(styleGroupPanel); // acrescenta os painis ao painel de contedo getContentPane().add( controlPanel, BorderLayout.SOUTH); } /** Cria a caixa de combinao com as opes de estilos de fontes. @return o painel contendo a caixa de combinao */ public JPanel createComboBox() { facenameCombo = new JComboBox(); facenameCombo.addItem ("Serif"); facenameCombo.addItem ("SansSerif"); facenameCombo.addItem ("Monospaced"); facenameCombo.setEditable(true); facenameCombo.addActionListener(listener); JPanel panel = new JPanel(); panel.add(facenameCombo); return panel; } /** Cria as caixas de seleo para a seleo dos estilos negrito (bold) e itlico(italic). @return o painel contendo as caixas de seleo */ public JPanel createCheckBoxes() { italicCheckBox = new JCheckBox("Italic"); italicCheckBox.addActionListener(listener); boldCheckBox = new JCheckBox("Bold"); boldCheckBox.addActionListener(listener); JPanel panel = new JPanel(); panel.add(italicCheckBox); panel.add(boldCheckBox); panel.setBorder (new TitledBorder(new EtchedBorder(), "Style")); return panel; } /** Cria os botes de opo para a seleo do tamanho da fonte. @return o painel contendo os botes de opo */ public JPanel createRadioButtons()

{ smallButton = new JRadioButton("Small"); smallButton.addActionListener(listener); mediumButton = new JRadioButton("Medium"); mediumButton.addActionListener(listener); largeButton = new JRadioButton("Large"); largeButton.addActionListener(listener); largeButton.setSelected(true); // acrescenta botes de opo ao grupo de botes ButtonGroup group = new ButtonGroup(); group.add(smallButton); group.add(mediumButton); group.add(largeButton); JPanel panel = new JPanel(); panel.add(smallButton); panel.add(mediumButton); panel.add(largeButton); panel.setBorder (new TitleBorder(new EtchedBorder(), "Size")); return panel; }

/** Obtm a escolha do usurio para o nome da fonte, estilo e tamanho e configura a fonte da amostra de texto. */ public void setSampleFont() { // obter o nome da fonte String facename = (String)facenameCombo.getSelectedItem(); // obtm o estilo da fonte int style = 0; if(italicCheckBox.isSelected()) style = style + Font.ITALIC; if(boldCheckBox.isSelected()) style = style + Font.BOLD; // obtm o tamanho da fonte int size = 0; final int SMALL_SIZE = 24; final int MEDIUM_SIZE = 36; final int LARGE_SIZE = 48; if (smallButton.isSelected()) size = SMALL_SIZE; else if (mediumButton.isSelected())

size = MEDIUM_SIZE; else if (largeButton.isSelected()) size = LARGE_SIZE; // configura a fonte do campo de texto sampleField.setFont( new Font(facename, style, size)); sampleField.repaint(); } private private private private private private private private } JLabel sampleField; JCheckBox italicCheckBox; JCheckBox boldCheckBox; JRadioButton smallButton; JRadioButton mediumButton; JRadioButton largeButton; JComboBox facenameCombo; ActionListener listener;

Como Fazer? Passo 1

12.1 Faa um esboo de componentes que voc deseja

Desenhe todos os botes, rtulos, campos de texto e bordas numa folha de papel. O melhor papel milimetrado Passo 2 Identifique agrupamentos de componentes adjacentes com o mesmo leiaute

Geralmente, a organizao dos componentes suficientemente complexa para termos de usar diversos painis, cada um com seu prprio gerenciador de leiaute. Comece olhando para componentes adjacentes que esto organizados de cima para baixo ou da esquerda para a direita. Se diversos componentes esto circundados por uma borda, eles provavelmente devem ser agrupados juntos. Passo 3 Identifique os leiautes de cada grupo

Quando os componentes estiverem organizados horizontalmente, use o FlowLayout. Quando os componentes estiverem organizados verticalmente, use o GridLayout. A grade tem tantas linhas quanto voc tiver componentes, e uma coluna. No ex. da interface com o usurio para pedir pizza, voc escolheria Passo 4 Um GridLayout (3,1) para botes de opo Um GridLayout (2,1) para caixas de seleo Um FlowLayout para rtulo e o campo de texto Junte os grupos

Olhe para cada grupo como uma bolha, e rena as bolhas em grupos maiores, da mesma forma que voc agrupou os componentes no passo anterior. Se voc notar uma bolha grande cercada por bolhas menores, voc pode agrup-las em um BorderLayout.

Talvez seja preciso repetir o agrupamento novamente se houver uma interface com o usurio muito complexa. A concluso estar feita quando todos os grupos estiverem organizados em um nico continer. Por ex., os trs grupos de componentes da interface com o usurio para pedir pizzas pode ser organizada da seguinte maneira: Um grupo contendo os dois primeiros grupos de componentes, colocado no centro de um continer de um BorderLayout O terceiro grupo de componentes, na regio sul desse continer inserir fig. aqui.... Neste passo podemos enfrentar algumas complicaes. As bolhas dos grupos tendem a variar de tamanho mais do que os componentes individuais. Se voc coloc-los dentro de um GridLayout, este os forar a ficar todos do mesmo tamanho. Ocasionalmente, voc tambm gostaria que um componente de um grupo se alinhasse com um componente de outro grupo, mas no h como comunicar essa inteno aos gerenciadores de leiuate. Esses problemas podem ser vencidos usando gerenciadores de leiaute mais sofisticados ou implementando um gerenciador de leiaute personalizado. Passo 5 Escreva o cdigo para gerar o leiuate

Comece com a construo dos componentes. Ento, construa um painel para cada grupo de componentes e configure seu gerenciador de leiaute se no for um FlowLayout (o default para painis). Acrescente uma borda ao painel se for necessrio. Finalmente, acrescente os componentes ao painel. Continue dessa forma at atingir o continer mais externo. Em vez de construir outro painel, use o painel de contedo do JFrame ou JApplet circundante. Naturalmente, preciso acrescentar tratadores de eventos aos componentes. A seguir, temos um esboo do cdigo necessrio para a interface com o usurio que pede uma pizza.

JPanel radioButtonPanel = new JPanel(); radioButtonPanel.setLayout(new GridLayout(3, 1)); radioButton.setBorder(new TitledBorder( new EtchedBorder(), "Size")); radioButtonPanel.add(smallButton); radioButtonPanel.add(mediumButton); radioButtonPanel.add(largeButton); JPanel checkBoxPanel = new JPanel(); checkBoxPanel.setLayout(new GridLayout(2, 1)); checkBoxPanel.add(pepperoniButton()); checkBoxPanel.add(anchoviesButton()); JPanel centerPanel = new JPanel(); // usa FlowLayout centerPanel.add(radioButtonPanel);

centerPanel.add(checkBoxPanel); //use o painel de contedo como continer de mais alto nvel //o painel de contedo usa BorderLayout por default getContentPanel().add(centerPanel, BorderLayout.CENTER); getContentPanel().add(pricePanel, BorderLayout.SOUTH);

12.5

Menus

Um frame contm uma barra de menus, que contm menus. Um menu contm submenus e itens de menu. O continer para os itens do menu de mais alto nvel chamado de barra de menu no mundo Java. Primeiramente, construmos uma barra de menu e a anexamos ao frame:
public class MyFrame extends JFrame { JMenuBar menuBar = new JMenuBar(); setJMenu(menuBar); ... }

ento, acrescentamos menus barra de menus:


JMenu fileMenu = new JMenu("File"); menuBar.add(fileMenu);

O menu uma coleo de itens de menu e mais menus (submenus). Acrescentamos itens de menu e submenus com o mtodo add:
JMenuItem fileNewMenuItem = new JMenuItem ("New"); fileMenu.add(fileNewMenuItem);

Um item de menu no possui outros submenus. Quando o usurio seleciona um item de menu, este envia um evento de ao. Portanto, devemos acrescentar um escutador para cada item de menu:
fileNewMenuItem.addActionListener(listener);

Acrescentamos escutadores de ao apenas para itens de menu, no para menus nem para a barra de menu. Quando o usurio clica sobre um nome de menu e se abre um submenu, nenhum evento de ao enviado. O programa a seguir constri um menu pequeno, mas tpico, e captura os eventos de ao dos itens de menu. Para manter o programa legvel, uma boa idia usar um mtodo separado para cada menu ou conjunto de menus relacionados. D uma olhada no mtodo createMoveItem, o qual cria um item de menu para mover para cima, para baixo, para a esquerda ou para a direita. A mesma classe escutadora de ao cuida dos quatro casos, sendo que os valores dx e dy variam para cada item de menu.

Arquivo MenuTest.java
import javax.swing.JFrame; /** Este programa testa o MenuFrame */ public class MenuTest { public static void main(String[] args) { JFrame frame = new MenuFrame(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); frame.show(); } }

Arquivo MenuFrame.java

import import import import import import import import /**

java.awt.BorderLayout; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.util.Random; java.swing.JFrame; java.swing.JMenu; java.swing.JMenuBar; java.swing.JMenuItem;

Este frame tem um menu com comandos para configurar a posio de um retngulo */ public class MenuFrame extends JFrame { /** Constri o frame */ public MenuFrame() { generator = new Random(); // adiciona o painel de desenho ao painel de contedo panel = new RectanglePanel(); getContentPane().add(panel, BorderLayout.CENTER); pack(); //constri o menu javax.swing.JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); menuBar.add(createFileMenu()); menuBar.add(createEditMenu()); }

/** * Cria o menu File. * @return o menu */ public JMenu createFileMenu() { javax.swing.JMenu menu = new JMenu("File"); menu.add(createFileNewItem()); menu.add(createFileExitItem()); return menu; } /** * Cria o menu Edit. * @return menu; */ public JMenu createEditMenu() { javax.swing.JMenu menu = new JMenu("Edit"); menu.add(createMoveMenu()); menu.add(createEditRandomizeItem()); return menu; } /** * Cria o submenu Move. * @return o menu */ public JMenu createMoveMenu() { javax.swing.JMenu menu = new JMenu("Move"); menu.add(createMoveItem("Up", 0, -1)); menu.add(createMoveItem("Down", 0, -1)); menu.add(createMoveItem("Left", 0, -1)); menu.add(createMoveItem("Right", 0, -1)); return menu; } /** * Cria o item menu File->New e configura seu escutador de ao. * @return o item de menu. */ public JMenuItem createFileNewItem() { javax.swing.JMenuItem item = new JMenuItem("New"); class MenuItemListener implements ActionListener { public void actionPerformed(ActionEvent event) { panel.reset(); } } ActionListener listener = new MenuItemListener(); item.addActionListener(listener); return item; } /** * Cria o item de menu File->Exit e configura seu escutador de ao.

* @return o item de menu. */ public JMenuItem createFileExitItem() { javax.swing.JMenuItem item = new JMenuItem("Exit"); class MenuItemListener implements ActionListener { public void actionPerformed(ActionEvent event) { System.exit(0); } } ActionLIstener listener = new MenuItemListener(); item.addActionListener(listener); return item; } /** * Cria um item de menu para mover o retngulo e configura seu * escutador de ao. * @param label o rotulo do menu * @param dx a quantidade que se deve mover o retangulo na direcao x * @param dy a quantidade que se deve mover o retangulo na direcao y * @return o item de menu */ public JMenuItem createMoveItem(String label, final int dx, final int dy) { javax.swing.JMenuItem item = new JMenuItem (label); class MenuItemListener implements ActionListener { public void actionPerformed(ActionEvent event) { panel.moveRectangle(dx, dy); } } ActionListener listener = new MenuItemListener(); item.addActionListener(listener); return item; } /** * Cria o item de menu Edit->Randomize e configura seu escutador de ao. * @return o item de menu */ public JMenuItem createEditRandomizeItem() { javax.swing.JMenuItem item = new JMenuItem("Randomize"); class MenuItemListener implements ActionListener { public void actionPerformed(ActionEvent event) { int width = panel.getWidth(); int heigth = panel.getHeight(); int dx = -1 + generator.nextInt(3); int dy = -1 + generator.nextInt(3); panel.moveRectangle(dx, dy); }

} ActionListener listener = new MenuItemListener(); item.addActionListener(listener); return item; } private RectanglePanel panel; private Random generator; }

Arquivo RectanglePanel.java
import import import import import /** Um painel que mostra um retangulo */ class RectanglePanel extends JPanel { /** * Constri um painel com o retngulo no canto superior esquerdo. */ public RectanglePanel() { setPreferredSize( new Dimension(PANEL_WIDTH, PANEL_HEIGHT)); // o retangulo que o metodo paint desenha box = new Rectangle(0, 0, BOX_WIDTH, BOX_HEIGHT); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; g2.draw(box); } /** * Reinicializa o retangulo para o canto superior esquerdo. */ public void reset() { box.setLocation(0, 0); repaint(); } /** * Move o retangulo e o redesenha. O retangulo * movido por multiplos de sua largura ou altura. * @param dx o numero de unidades de largura. * @param dy o numero de unidades de altura */ public void moveRectangle(int dx, int dy) { box.translate(dx * BOX_WIDTH, dy * BOX_HEIGHT); java.awt.Dimension; java.awt.Graphics; java.awt.Graphics2D; java.awt.Rectangle; java.swing.JPanel;

repaint(); } private private private private private } Rectangle box; static final int static final int static final int static final int

BOX_WIDTH = 20; BOX_HEIGTH = 30; PANEL_WIDTH = 300; PANEL_HEIGTH = 300;

12.6

Explorando a documentao do Swing

Uma das opes verificar os nomes das classes, por ex., uma que inicia com J e concluir que JSlider pode ser um bom candidato. A seguir fazemos algumas perguntas: Como construir um JSlider? Como posso ser notificado quando o usurio o moveu? Como posso saber para qual valor o usurio o configurou? Temos desenvolver a habilidade de separar os conceitos fundamentais de mincias efmeras. Por ex., importante entender o conceito de tratamento de eventos. Uma vez entendido o conceito, cabe a pergunta: Que evento o controle deslizante envia quando o usurio o move? Mas no importante memorizar como se configura marcas de medida, ou saber como implementar um controle deslizandte com uma aparncia e comportamento personalizados. Considere
public JSlider()

cria um controle deslizante horizontal na faixa de 0 a 100 e com um valor inicial de 50. Talvez isso seja suficiente por enquanto, mas e se quisermos outra faixa ou outro valor inicial? Parece ser limitado demais. Do outro lado do espectro temos
public JSlider(BoundedRangeModel brm) Cria um controle deslizandte horizontal usando o BoundedRangeModel especificado

Podemos clicar sobre o link BoundedRangeModel para obter uma longa explicao dessa classe. Olhando mais adiante encontramos
public JSlider(int min, int max, int value)

Parece muito genrico para ser til e muito simples para ser utilizado. Talvez queiramos ocultar o fato de que tambm podemos ter controles deslizantes verticais. A seguir, queremos saber quais eventos so gerados por um controle deslizante. No h nenhum mtodo addActionListener. Isso faz sentido. Ajustar um controle deslizante parece ser

diferente de clicar um boto, e o Swing usa um tipo de evento diferente para esses eventos. H um mtodo
public void addChangeListener(ChangeListener 1)

clique sobre o link ChangeListener para descobrir mais sobre essa interface. Ela s tem um mtodo
void stateChanged(ChangeEvent e)

Aparentemente, esse mtodo chamado sempre que o usurio move o controle deslizante. O que um ChangeEvent? Uma vez mais, clique sobre o link para descobrir que essa classe de eventos no tem nenhum mtodo prprio, mas ela herda o mtodo getSource de sua superclasse EventObject. Agora temos um plano: acrescentar um escutador de mudana de evento a cada controle deslizante. Quando o controle deslizante alterado, o mtodo stateChanged chamado. Descubra o novo valor do controle deslizante. Recalcule o valor da cor e redesenhe o painel de cores. Dessa forma, o painel de cores continuamente redesenhado medida que o usurio move um dos controles deslizantes. Para calcular o valor da cor, ainda necessrio obter o valor atual do controle deslizante. Verificamos todos os mtodos que iniciam por get.
public int geValue()

que retorna o valor do controle deslizante Agora j sabemos tudo para escrever o programa. O programa usa um novo construtor, dois novos mtodos, e um escutador de eventos de um tipo novo. Arquivo SliderTest.java
import javax.swing.JFrame; public class SliderTest{ public static void main(String[] args){ SliderFrame frame = new SliderFrame(); frame.setDefaultCloseOperation( JFrame,EXIT_ON_CLOSE); } }

Arquivo SliderFrame.java

import import import import import import

java.awt.BorderLayout; java.awt.color; java.awt.Container; java.awt.Dimension; java.awt.GridLayout; java.awt.event.WindowAdapter;

import import import import import import import import

javax.awt.event.WindowEvent; javax.swing.JFrame; javax.swing.JLabel; javax.swing.JPanel; javax.swing.JSlider; javax.swing.SwingConstants; javax.swing.event.ChangeListener; javax.swing.event.ChangeEvent;

class SliderFrame extends JFrame { public SliderFrame() { colorPanel = new JPanel(); colorPanel.setPreferredSize( new Dimension(PANEL_WIDTH, PANEL_HEIGTH)); getContentPane().add(colorPanel, BorderLayout.CENTER); createControlPanel(); setSampleColor(); pack(); } public void createControlPanel() { class ColorListener implements ChangeListener { public void stateChanged(ChangeEvent event) { setSampleColor(); } } ChangeListener listener = new ColorListener(); redSlider = new JSlider(0, 100, 100); redSlider.addChangeListener(listener); greenSlider = new JSlider(0, 100, 70); greenSlider.addChangeListener(listener); blueSlider = new JSlider(0, 100, 70); blueSlider.addChangeListener(listener); JPanel controlPanel = new JPanel(); controlPanel.setLayout(new GridLayout(3, 2)); controlPanel.add(new JLabel("Red", SwingConstants.RIGHT)); controlPanel.add(greenSlider); controlPanel.add(new JLabel("Green", SwingConstants.RIGHT)); controlPanel.add(greenSlider); controlPanel.add(new JLabel("Blue", SwingConstants.RIGHT)); controlPanel.add(blueSlider);

getContentPane().add(controlPanel, BorderLayout.SOUTH); }

/** * Le os valores dos controles deslizantes e configura o painel para * a cor selecionada */ public void setSampleColor() // le os valores dos controles deslizantes { float red = 0.01F * redSlider.getValue(); float green = 0.01F * greenSlider.getValue(); float blue = 0.01F * blueSlider.getValue(); // configura o pano de fundo do painel para a cor selecionada colorPanel.setBackground( new Color (red, green, blue)); colorPanel.repaint(); } private private private private JPanel colorPanel; JSlider redSlider; JSlider greenSlider; JSlider blueSlider;

private static final int PANEL_WIDTH = 300; private static final int PANEL_HEIGHT = 300;

Exerccios de Reviso R12.1. Qual a diferena entre os mtodos paint e paintComponent?

O mtodo paint utilizado para grficos em um applet. A classe Applet extendida e o mtodo paint redefinido. No mtodo paintComponent o grfico desenhado sobre um painel. Ele sobrescrito de uma subclasse JPanel. Uma segunda diferena importante que ao implementar-se o prprio mtodo paintComponent, temos de chamar o mtodo paintComponent da superclasse. Isso d ao mtodo da superclasse uma chance de apagar o contedo velho do painel. Uma vez que tenhamos chamado super.paintComponent e obtido um objeto Graphics2D, estaremos prontos para desenhar formas grficas da maneira usual. R12.2. O que acontece se voc no chamar super.paintComponent em uma classe que estende JPanel? Comprove usando o programa RectangleTest. Voc consegue descobrir como o programa vai se comportar se voc transformar essa chamada em um comentrio?

R12.3. O que acontece quando desenhamos diretamente sobre um frame? Experimente reescreva a aplicao RectanglePanel e mova o mtodo paintComponent diretamente para dentro da classe RectangleFrame. R12.4. O que um gerenciador de leiaute? Qual a vantagem de um gerenciador de leiaute tem sobre dizer ao continer coloque este componente na posio (x, y)? R12.5. O que acontece quando voc coloca um nico boto na rea CENTER de um continer que usa BorderLayout? Comprove isso, escrevendo um pequeno programa de amostra, caso voc no tenha certeza da resposta. R12.6. O que acontece se voc colocar mltiplos botes na rea SOUTH? Experimente, escrevendo um pequeno programa de amostra, se voc no tiver certeza da resposta. R12.7. O que acontece quando voc acrescenta um boto a um continer que usa BorderLayout e omite a posio? Experimente e explique. R12.8. O que acontece quando voc tenta acrescentar um componente diretamente a um JFrame e no ao painel de contedo? Experimente e explique. R12.9. O programa SliderTest usa um gerenciador de leiaute GridLayout. Explique um problema da grade o qual evidenciado na figura 16. O que voc poderia fazer para superar esse problema? R12.10. Qual a diferena entre um Applet e um JApplet?

Potrebbero piacerti anche