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